You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
321 lines
9.8 KiB
321 lines
9.8 KiB
#include "PageBackgroundChangeController.h" |
|
|
|
#include <memory> |
|
|
|
#include "control/Control.h" |
|
#include "control/pagetype/PageTypeHandler.h" |
|
#include "control/pagetype/PageTypeMenu.h" |
|
#include "gui/dialog/backgroundSelect/ImagesDialog.h" |
|
#include "gui/dialog/backgroundSelect/PdfPagesDialog.h" |
|
#include "stockdlg/ImageOpenDlg.h" |
|
#include "undo/GroupUndoAction.h" |
|
#include "undo/PageBackgroundChangedUndoAction.h" |
|
|
|
#include "XojMsgBox.h" |
|
#include "i18n.h" |
|
|
|
|
|
PageBackgroundChangeController::PageBackgroundChangeController(Control* control): |
|
control(control), currentPageType(control->getPageTypes(), control->getSettings(), false, true) { |
|
currentPageType.setListener(this); |
|
|
|
currentPageType.hideCopyPage(); |
|
|
|
currentPageType.addApplyBackgroundButton(this, true, ApplyPageTypeSource::CURRENT); |
|
|
|
registerListener(control); |
|
} |
|
|
|
auto PageBackgroundChangeController::getMenu() -> GtkWidget* { return currentPageType.getMenu(); } |
|
|
|
void PageBackgroundChangeController::changeAllPagesBackground(const PageType& pt) { |
|
control->clearSelectionEndText(); |
|
|
|
Document* doc = control->getDocument(); |
|
|
|
auto groupUndoAction = std::make_unique<GroupUndoAction>(); |
|
|
|
for (size_t p = 0; p < doc->getPageCount(); p++) { |
|
auto undoAction = commitPageTypeChange(p, pt); |
|
if (undoAction) { |
|
groupUndoAction->addAction(undoAction.release()); |
|
} |
|
} |
|
|
|
control->getUndoRedoHandler()->addUndoAction(std::move(groupUndoAction)); |
|
|
|
ignoreEvent = true; |
|
currentPageType.setSelected(pt); |
|
ignoreEvent = false; |
|
} |
|
|
|
void PageBackgroundChangeController::changeCurrentPageBackground(PageTypeInfo* info) { |
|
changeCurrentPageBackground(info->page); |
|
} |
|
|
|
void PageBackgroundChangeController::changeCurrentPageBackground(PageType& pageType) { |
|
if (ignoreEvent) { |
|
return; |
|
} |
|
|
|
control->clearSelectionEndText(); |
|
|
|
PageRef page = control->getCurrentPage(); |
|
if (!page) { |
|
return; |
|
} |
|
|
|
Document* doc = control->getDocument(); |
|
const size_t pageNr = doc->indexOf(page); |
|
g_assert(pageNr != npos); |
|
|
|
auto undoAction = commitPageTypeChange(pageNr, pageType); |
|
if (undoAction) { |
|
control->getUndoRedoHandler()->addUndoAction(std::move(undoAction)); |
|
} |
|
|
|
ignoreEvent = true; |
|
currentPageType.setSelected(pageType); |
|
ignoreEvent = false; |
|
} |
|
|
|
auto PageBackgroundChangeController::commitPageTypeChange(const size_t pageNum, const PageType& pageType) |
|
-> std::unique_ptr<UndoAction> { |
|
PageRef page = control->getDocument()->getPage(pageNum); |
|
if (!page) { |
|
return {}; |
|
} |
|
|
|
Document* doc = control->getDocument(); |
|
const size_t pageNr = doc->indexOf(page); |
|
g_assert(pageNr != npos); |
|
|
|
// Get values for Undo / Redo |
|
const double origW = page->getWidth(); |
|
const double origH = page->getHeight(); |
|
BackgroundImage origBackgroundImage = page->getBackgroundImage(); |
|
const size_t origPdfPage = page->getPdfPageNr(); |
|
PageType origType = page->getBackgroundType(); |
|
|
|
// Apply the new background |
|
applyPageBackground(page, pageType); |
|
|
|
control->firePageChanged(pageNr); |
|
control->updateBackgroundSizeButton(); |
|
return std::make_unique<PageBackgroundChangedUndoAction>(page, origType, origPdfPage, origBackgroundImage, origW, |
|
origH); |
|
} |
|
|
|
/** |
|
* Apply a new Image Background, asks the user which image should be inserted |
|
* |
|
* @return true on success, false if the user cancels |
|
*/ |
|
auto PageBackgroundChangeController::applyImageBackground(PageRef page) -> bool { |
|
Document* doc = control->getDocument(); |
|
|
|
doc->lock(); |
|
ImagesDialog dlg(control->getGladeSearchPath(), doc, control->getSettings()); |
|
doc->unlock(); |
|
|
|
dlg.show(GTK_WINDOW(control->getGtkWindow())); |
|
BackgroundImage img = dlg.getSelectedImage(); |
|
|
|
if (!img.isEmpty()) { |
|
page->setBackgroundImage(img); |
|
page->setBackgroundType(PageType(PageTypeFormat::Image)); |
|
} else if (dlg.shouldShowFilechooser()) { |
|
bool attach = false; |
|
GFile* file = ImageOpenDlg::show(control->getGtkWindow(), control->getSettings(), true, &attach); |
|
if (file == nullptr) { |
|
// The user canceled |
|
return false; |
|
} |
|
|
|
|
|
auto filepath = Util::fromGFile(file); |
|
|
|
BackgroundImage newImg; |
|
GError* err = nullptr; |
|
newImg.loadFile(filepath, &err); |
|
newImg.setAttach(attach); |
|
if (err) { |
|
XojMsgBox::showErrorToUser(control->getGtkWindow(), |
|
FS(_F("This image could not be loaded. Error message: {1}") % err->message)); |
|
g_error_free(err); |
|
return false; |
|
} |
|
|
|
|
|
page->setBackgroundImage(newImg); |
|
page->setBackgroundType(PageType(PageTypeFormat::Image)); |
|
} |
|
|
|
// Apply correct page size |
|
GdkPixbuf* pixbuf = page->getBackgroundImage().getPixbuf(); |
|
if (pixbuf) { |
|
page->setSize(gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); |
|
|
|
size_t pageNr = doc->indexOf(page); |
|
if (pageNr != npos) { |
|
// Only if the page is already inserted into the document |
|
control->firePageSizeChanged(pageNr); |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
/** |
|
* Apply a new PDF Background, asks the user which page should be selected |
|
* |
|
* @return true on success, false if the user cancels |
|
*/ |
|
auto PageBackgroundChangeController::applyPdfBackground(PageRef page) -> bool { |
|
Document* doc = control->getDocument(); |
|
|
|
if (doc->getPdfPageCount() == 0) { |
|
|
|
string msg = _("You don't have any PDF pages to select from. Cancel operation.\n" |
|
"Please select another background type: Menu \"Journal\" → \"Configure Page Template\"."); |
|
XojMsgBox::showErrorToUser(control->getGtkWindow(), msg); |
|
return false; |
|
} |
|
|
|
doc->lock(); |
|
auto* dlg = new PdfPagesDialog(control->getGladeSearchPath(), doc, control->getSettings()); |
|
doc->unlock(); |
|
|
|
dlg->show(GTK_WINDOW(control->getGtkWindow())); |
|
|
|
int selected = dlg->getSelectedPage(); |
|
delete dlg; |
|
|
|
if (selected >= 0 && selected < static_cast<int>(doc->getPdfPageCount())) { |
|
// no need to set a type, if we set the page number the type is also set |
|
page->setBackgroundPdfPageNr(selected); |
|
|
|
XojPdfPageSPtr p = doc->getPdfPage(selected); |
|
page->setSize(p->getWidth(), p->getHeight()); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
/** |
|
* Apply the background to the page, asks for PDF Page or Image, if needed |
|
* |
|
* @return true on success, false if the user cancels |
|
*/ |
|
auto PageBackgroundChangeController::applyPageBackground(PageRef page, const PageType& pt) -> bool { |
|
if (pt.isPdfPage()) { |
|
return applyPdfBackground(page); |
|
} |
|
if (pt.isImagePage()) { |
|
return applyImageBackground(page); |
|
} |
|
|
|
|
|
page->setBackgroundType(pt); |
|
return true; |
|
} |
|
|
|
/** |
|
* Copy the background from source to target |
|
*/ |
|
void PageBackgroundChangeController::copyBackgroundFromOtherPage(PageRef target, PageRef source) { |
|
// Copy page size |
|
target->setSize(source->getWidth(), source->getHeight()); |
|
|
|
// Copy page background type |
|
PageType bg = source->getBackgroundType(); |
|
target->setBackgroundType(bg); |
|
|
|
if (bg.isPdfPage()) { |
|
// If PDF: Copy PDF Page |
|
target->setBackgroundPdfPageNr(source->getPdfPageNr()); |
|
} else if (bg.isImagePage()) { |
|
// If Image: Copy the Image |
|
target->setBackgroundImage(source->getBackgroundImage()); |
|
} else { |
|
// Copy the background color |
|
target->setBackgroundColor(source->getBackgroundColor()); |
|
} |
|
} |
|
|
|
void PageBackgroundChangeController::insertNewPage(size_t position) { |
|
control->clearSelectionEndText(); |
|
|
|
Document* doc = control->getDocument(); |
|
if (position > doc->getPageCount()) { |
|
position = doc->getPageCount(); |
|
} |
|
|
|
PageTemplateSettings model; |
|
model.parse(control->getSettings()->getPageTemplate()); |
|
|
|
auto page = std::make_shared<XojPage>(model.getPageWidth(), model.getPageHeight()); |
|
PageType pt = control->getNewPageType()->getSelected(); |
|
PageRef current = control->getCurrentPage(); |
|
|
|
// current should always be valid, but if you open an invalid file or something like this... |
|
if (pt.format == PageTypeFormat::Copy && current) { |
|
copyBackgroundFromOtherPage(page, current); |
|
} else { |
|
// Create a new page from template |
|
if (!applyPageBackground(page, pt)) { |
|
// User canceled PDF or Image Selection |
|
return; |
|
} |
|
|
|
// Set background Color |
|
page->setBackgroundColor(model.getBackgroundColor()); |
|
|
|
if (model.isCopyLastPageSize() && current) { |
|
page->setSize(current->getWidth(), current->getHeight()); |
|
} |
|
} |
|
|
|
control->insertPage(page, position); |
|
} |
|
|
|
void PageBackgroundChangeController::documentChanged(DocumentChangeType type) {} |
|
|
|
void PageBackgroundChangeController::pageSizeChanged(size_t page) {} |
|
|
|
void PageBackgroundChangeController::pageChanged(size_t page) {} |
|
|
|
void PageBackgroundChangeController::pageInserted(size_t page) {} |
|
|
|
void PageBackgroundChangeController::pageDeleted(size_t page) {} |
|
|
|
void PageBackgroundChangeController::pageSelected(size_t page) { |
|
auto const& current = control->getCurrentPage(); |
|
if (!current) { |
|
return; |
|
} |
|
|
|
ignoreEvent = true; |
|
currentPageType.setSelected(current->getBackgroundType()); |
|
ignoreEvent = false; |
|
} |
|
|
|
void PageBackgroundChangeController::applySelectedPageBackground(bool allPages, ApplyPageTypeSource src) { |
|
PageType pt; |
|
switch (src) { |
|
case ApplyPageTypeSource::SELECTED: |
|
pt = control->getNewPageType()->getSelected(); |
|
break; |
|
case ApplyPageTypeSource::CURRENT: |
|
pt = control->getCurrentPage()->getBackgroundType(); |
|
break; |
|
} |
|
|
|
if (allPages) { |
|
changeAllPagesBackground(pt); |
|
} else { |
|
PageTypeInfo info; |
|
info.page = pt; |
|
changeCurrentPageBackground(&info); |
|
} |
|
}
|
|
|