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.
785 lines
21 KiB
785 lines
21 KiB
#include "XournalView.h" |
|
|
|
#include <cmath> |
|
#include <memory> |
|
#include <tuple> |
|
|
|
#include <gdk/gdk.h> |
|
|
|
#include "control/Control.h" |
|
#include "control/PdfCache.h" |
|
#include "control/settings/MetadataManager.h" |
|
#include "gui/inputdevices/HandRecognition.h" |
|
#include "model/Document.h" |
|
#include "model/Stroke.h" |
|
#include "undo/DeleteUndoAction.h" |
|
#include "widgets/XournalWidget.h" |
|
|
|
#include "Layout.h" |
|
#include "PageView.h" |
|
#include "Rectangle.h" |
|
#include "RepaintHandler.h" |
|
#include "Shadow.h" |
|
#include "Util.h" |
|
#include "XournalppCursor.h" |
|
#include "filesystem.h" |
|
|
|
XournalView::XournalView(GtkWidget* parent, Control* control, ScrollHandling* scrollHandling): |
|
scrollHandling(scrollHandling), control(control) { |
|
this->cache = new PdfCache(control->getSettings()->getPdfPageCacheSize()); |
|
registerListener(control); |
|
|
|
InputContext* inputContext = nullptr; |
|
if (this->control->getSettings()->getExperimentalInputSystemEnabled()) { |
|
inputContext = new InputContext(this, scrollHandling); |
|
this->widget = gtk_xournal_new(this, inputContext); |
|
} else { |
|
this->widget = gtk_xournal_new_deprecated(this, scrollHandling); |
|
} |
|
// we need to refer widget here, because we unref it somewhere twice!? |
|
g_object_ref(this->widget); |
|
|
|
gtk_container_add(GTK_CONTAINER(parent), this->widget); |
|
gtk_widget_show(this->widget); |
|
|
|
g_signal_connect(getWidget(), "realize", G_CALLBACK(onRealized), this); |
|
|
|
this->repaintHandler = new RepaintHandler(this); |
|
this->handRecognition = new HandRecognition(this->widget, inputContext, control->getSettings()); |
|
|
|
control->getZoomControl()->addZoomListener(this); |
|
|
|
gtk_widget_set_can_default(this->widget, true); |
|
gtk_widget_grab_default(this->widget); |
|
|
|
gtk_widget_grab_focus(this->widget); |
|
|
|
this->cleanupTimeout = g_timeout_add_seconds(5, reinterpret_cast<GSourceFunc>(clearMemoryTimer), this); |
|
} |
|
|
|
XournalView::~XournalView() { |
|
g_source_remove(this->cleanupTimeout); |
|
|
|
for (auto&& page: viewPages) { |
|
delete page; |
|
} |
|
viewPages.clear(); |
|
|
|
delete this->cache; |
|
this->cache = nullptr; |
|
delete this->repaintHandler; |
|
this->repaintHandler = nullptr; |
|
|
|
gtk_widget_destroy(this->widget); |
|
this->widget = nullptr; |
|
|
|
delete this->handRecognition; |
|
this->handRecognition = nullptr; |
|
} |
|
|
|
auto pageViewIncreasingClockTime(XojPageView* a, XojPageView* b) -> gint { |
|
return a->getLastVisibleTime() - b->getLastVisibleTime(); // >0 will put a after b |
|
} |
|
|
|
void XournalView::staticLayoutPages(GtkWidget* widget, GtkAllocation* allocation, void* data) { |
|
auto* xv = static_cast<XournalView*>(data); |
|
xv->layoutPages(); |
|
} |
|
|
|
auto XournalView::clearMemoryTimer(XournalView* widget) -> gboolean { |
|
GList* list = nullptr; |
|
|
|
for (auto&& page: widget->viewPages) { |
|
if (page->getLastVisibleTime() > 0) { |
|
list = g_list_insert_sorted(list, page, reinterpret_cast<GCompareFunc>(pageViewIncreasingClockTime)); |
|
} |
|
} |
|
|
|
int pixel = 2884560; |
|
int firstPages = 4; |
|
|
|
int i = 0; |
|
|
|
for (GList* l = g_list_last(list); l != nullptr; l = l->prev) // older (higher time) to newer (lower time) |
|
{ |
|
if (firstPages) { |
|
firstPages--; |
|
} else { |
|
auto* v = static_cast<XojPageView*>(l->data); |
|
|
|
if (pixel <= 0) { |
|
v->deleteViewBuffer(); |
|
} else { |
|
pixel -= v->getBufferPixels(); |
|
} |
|
} |
|
i++; |
|
} |
|
|
|
g_list_free(list); |
|
|
|
// call again |
|
return true; |
|
} |
|
|
|
auto XournalView::getCurrentPage() const -> size_t { return currentPage; } |
|
|
|
const int scrollKeySize = 30; |
|
|
|
auto XournalView::onKeyPressEvent(GdkEventKey* event) -> bool { |
|
size_t p = getCurrentPage(); |
|
if (p != npos && p < this->viewPages.size()) { |
|
XojPageView* v = this->viewPages[p]; |
|
if (v->onKeyPressEvent(event)) { |
|
return true; |
|
} |
|
} |
|
|
|
// Esc leaves fullscreen mode |
|
if (event->keyval == GDK_KEY_Escape) { |
|
if (control->isFullscreen()) { |
|
control->setFullscreen(false); |
|
control->setViewPresentationMode(false); |
|
control->getWindow()->setToolbarVisible(true); |
|
return true; |
|
} |
|
} |
|
|
|
// F5 starts presentation modus |
|
if (event->keyval == GDK_KEY_F5) { |
|
if (!control->isFullscreen()) { |
|
control->setViewPresentationMode(true); |
|
control->setFullscreen(true); |
|
control->getWindow()->setToolbarVisible(false); |
|
return true; |
|
} |
|
} |
|
|
|
guint state = event->state & gtk_accelerator_get_default_mod_mask(); |
|
|
|
Layout* layout = gtk_xournal_get_layout(this->widget); |
|
|
|
if (state & GDK_SHIFT_MASK) { |
|
GtkAllocation alloc = {0}; |
|
gtk_widget_get_allocation(gtk_widget_get_parent(this->widget), &alloc); |
|
int windowHeight = alloc.height - scrollKeySize; |
|
|
|
if (event->keyval == GDK_KEY_Page_Down) { |
|
layout->scrollRelative(0, windowHeight); |
|
return false; |
|
} |
|
if (event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_space) { |
|
layout->scrollRelative(0, -windowHeight); |
|
return true; |
|
} |
|
} else { |
|
if (event->keyval == GDK_KEY_Page_Down || event->keyval == GDK_KEY_KP_Page_Down) { |
|
control->getScrollHandler()->goToNextPage(); |
|
return true; |
|
} |
|
if (event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_KP_Page_Up) { |
|
control->getScrollHandler()->goToPreviousPage(); |
|
return true; |
|
} |
|
} |
|
|
|
if (event->keyval == GDK_KEY_space) { |
|
GtkAllocation alloc = {0}; |
|
gtk_widget_get_allocation(gtk_widget_get_parent(this->widget), &alloc); |
|
int windowHeight = alloc.height - scrollKeySize; |
|
|
|
layout->scrollRelative(0, windowHeight); |
|
return true; |
|
} |
|
|
|
// Numeric keypad always navigates by page |
|
if (event->keyval == GDK_KEY_KP_Up) { |
|
this->pageRelativeXY(0, -1); |
|
return true; |
|
} |
|
|
|
if (event->keyval == GDK_KEY_KP_Down) { |
|
this->pageRelativeXY(0, 1); |
|
return true; |
|
} |
|
|
|
if (event->keyval == GDK_KEY_KP_Left) { |
|
this->pageRelativeXY(-1, 0); |
|
return true; |
|
} |
|
|
|
if (event->keyval == GDK_KEY_KP_Right) { |
|
this->pageRelativeXY(1, 0); |
|
return true; |
|
} |
|
|
|
|
|
if (event->keyval == GDK_KEY_Up) { |
|
if (control->getSettings()->isPresentationMode()) { |
|
control->getScrollHandler()->goToPreviousPage(); |
|
return true; |
|
} |
|
|
|
|
|
if (state & GDK_SHIFT_MASK) { |
|
this->pageRelativeXY(0, -1); |
|
} else { |
|
layout->scrollRelative(0, -scrollKeySize); |
|
} |
|
return true; |
|
} |
|
|
|
if (event->keyval == GDK_KEY_Down) { |
|
if (control->getSettings()->isPresentationMode()) { |
|
control->getScrollHandler()->goToNextPage(); |
|
return true; |
|
} |
|
|
|
|
|
if (state & GDK_SHIFT_MASK) { |
|
this->pageRelativeXY(0, 1); |
|
} else { |
|
layout->scrollRelative(0, scrollKeySize); |
|
} |
|
return true; |
|
} |
|
|
|
if (event->keyval == GDK_KEY_Left) { |
|
if (state & GDK_SHIFT_MASK) { |
|
this->pageRelativeXY(-1, 0); |
|
} else { |
|
if (control->getSettings()->isPresentationMode()) { |
|
control->getScrollHandler()->goToPreviousPage(); |
|
} else { |
|
layout->scrollRelative(-scrollKeySize, 0); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
if (event->keyval == GDK_KEY_Right) { |
|
if (state & GDK_SHIFT_MASK) { |
|
this->pageRelativeXY(1, 0); |
|
} else { |
|
if (control->getSettings()->isPresentationMode()) { |
|
control->getScrollHandler()->goToNextPage(); |
|
} else { |
|
layout->scrollRelative(scrollKeySize, 0); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End) { |
|
control->getScrollHandler()->goToLastPage(); |
|
return true; |
|
} |
|
|
|
if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home) { |
|
control->getScrollHandler()->goToFirstPage(); |
|
return true; |
|
} |
|
|
|
// vim like scrolling |
|
if (event->keyval == GDK_KEY_j) { |
|
layout->scrollRelative(0, 60); |
|
return true; |
|
} |
|
if (event->keyval == GDK_KEY_k) { |
|
layout->scrollRelative(0, -60); |
|
return true; |
|
} |
|
if (event->keyval == GDK_KEY_h) { |
|
layout->scrollRelative(-60, 0); |
|
return true; |
|
} |
|
if (event->keyval == GDK_KEY_l) { |
|
layout->scrollRelative(60, 0); |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
auto XournalView::getRepaintHandler() -> RepaintHandler* { return this->repaintHandler; } |
|
|
|
auto XournalView::onKeyReleaseEvent(GdkEventKey* event) -> bool { |
|
size_t p = getCurrentPage(); |
|
if (p != npos && p < this->viewPages.size()) { |
|
XojPageView* v = this->viewPages[p]; |
|
if (v->onKeyReleaseEvent(event)) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void XournalView::onRealized(GtkWidget* widget, XournalView* view) { |
|
// Disable event compression |
|
if (gtk_widget_get_realized(view->getWidget())) { |
|
gdk_window_set_event_compression(gtk_widget_get_window(view->getWidget()), false); |
|
} else { |
|
g_warning("could not disable event compression"); |
|
} |
|
} |
|
|
|
// send the focus back to the appropriate widget |
|
void XournalView::requestFocus() { gtk_widget_grab_focus(this->widget); } |
|
|
|
auto XournalView::searchTextOnPage(string text, size_t p, int* occures, double* top) -> bool { |
|
if (p == npos || p >= this->viewPages.size()) { |
|
return false; |
|
} |
|
XojPageView* v = this->viewPages[p]; |
|
|
|
return v->searchTextOnPage(text, occures, top); |
|
} |
|
|
|
void XournalView::forceUpdatePagenumbers() { |
|
size_t p = this->currentPage; |
|
this->currentPage = npos; |
|
|
|
control->firePageSelected(p); |
|
} |
|
|
|
auto XournalView::getViewFor(size_t pageNr) -> XojPageView* { |
|
if (pageNr == npos || pageNr >= this->viewPages.size()) { |
|
return nullptr; |
|
} |
|
return this->viewPages[pageNr]; |
|
} |
|
|
|
void XournalView::pageSelected(size_t page) { |
|
if (this->currentPage == page && this->lastSelectedPage == page) { |
|
return; |
|
} |
|
|
|
Document* doc = control->getDocument(); |
|
doc->lock(); |
|
auto const& file = doc->getEvMetadataFilename(); |
|
doc->unlock(); |
|
|
|
control->getMetadataManager()->storeMetadata(file, page, getZoom()); |
|
|
|
if (this->lastSelectedPage != npos && this->lastSelectedPage < this->viewPages.size()) { |
|
this->viewPages[this->lastSelectedPage]->setSelected(false); |
|
} |
|
|
|
this->currentPage = page; |
|
|
|
size_t pdfPage = npos; |
|
|
|
if (page != npos && page < viewPages.size()) { |
|
XojPageView* vp = viewPages[page]; |
|
vp->setSelected(true); |
|
lastSelectedPage = page; |
|
pdfPage = vp->getPage()->getPdfPageNr(); |
|
} |
|
|
|
control->updatePageNumbers(currentPage, pdfPage); |
|
|
|
control->updateBackgroundSizeButton(); |
|
} |
|
|
|
auto XournalView::getControl() -> Control* { return control; } |
|
|
|
void XournalView::scrollTo(size_t pageNo, double yDocument) { |
|
if (pageNo >= this->viewPages.size()) { |
|
return; |
|
} |
|
|
|
XojPageView* v = this->viewPages[pageNo]; |
|
|
|
// Make sure it is visible |
|
Layout* layout = gtk_xournal_get_layout(this->widget); |
|
|
|
int x = v->getX(); |
|
int y = v->getY() + std::lround(yDocument); |
|
int width = v->getDisplayWidth(); |
|
int height = v->getDisplayHeight(); |
|
|
|
layout->ensureRectIsVisible(x, y, width, height); |
|
|
|
// Select the page |
|
control->firePageSelected(pageNo); |
|
} |
|
|
|
|
|
void XournalView::pageRelativeXY(int offCol, int offRow) { |
|
size_t currPage = getCurrentPage(); |
|
|
|
XojPageView* view = getViewFor(currPage); |
|
int row = view->getMappedRow(); |
|
int col = view->getMappedCol(); |
|
|
|
Layout* layout = gtk_xournal_get_layout(this->widget); |
|
auto optionalPageIndex = layout->getIndexAtGridMap(row + offRow, col + offCol); |
|
if (optionalPageIndex) { |
|
this->scrollTo(*optionalPageIndex, 0); |
|
} |
|
} |
|
|
|
|
|
void XournalView::endTextAllPages(XojPageView* except) { |
|
for (auto v: this->viewPages) { |
|
if (except != v) { |
|
v->endText(); |
|
} |
|
} |
|
} |
|
|
|
void XournalView::layerChanged(size_t page) { |
|
if (page != npos && page < this->viewPages.size()) { |
|
this->viewPages[page]->rerenderPage(); |
|
} |
|
} |
|
|
|
void XournalView::getPasteTarget(double& x, double& y) { |
|
size_t pageNo = getCurrentPage(); |
|
if (pageNo == npos) { |
|
return; |
|
} |
|
|
|
Rectangle<double>* rect = getVisibleRect(pageNo); |
|
|
|
if (rect) { |
|
x = rect->x + rect->width / 2; |
|
y = rect->y + rect->height / 2; |
|
delete rect; |
|
} |
|
} |
|
|
|
/** |
|
* Return the rectangle which is visible on screen, in document cooordinates |
|
* |
|
* Or nullptr if the page is not visible |
|
*/ |
|
auto XournalView::getVisibleRect(size_t page) -> Rectangle<double>* { |
|
if (page == npos || page >= this->viewPages.size()) { |
|
return nullptr; |
|
} |
|
XojPageView* p = this->viewPages[page]; |
|
|
|
return getVisibleRect(p); |
|
} |
|
|
|
auto XournalView::getVisibleRect(XojPageView* redrawable) -> Rectangle<double>* { |
|
return gtk_xournal_get_visible_area(this->widget, redrawable); |
|
} |
|
|
|
/** |
|
* @return Helper class for Touch specific fixes |
|
*/ |
|
auto XournalView::getHandRecognition() -> HandRecognition* { return handRecognition; } |
|
|
|
/** |
|
* @return Scrollbars |
|
*/ |
|
auto XournalView::getScrollHandling() -> ScrollHandling* { return scrollHandling; } |
|
|
|
auto XournalView::getWidget() -> GtkWidget* { return widget; } |
|
|
|
void XournalView::zoomIn() { control->getZoomControl()->zoomOneStep(ZOOM_IN); } |
|
|
|
void XournalView::zoomOut() { control->getZoomControl()->zoomOneStep(ZOOM_OUT); } |
|
|
|
void XournalView::ensureRectIsVisible(int x, int y, int width, int height) { |
|
Layout* layout = gtk_xournal_get_layout(this->widget); |
|
layout->ensureRectIsVisible(x, y, width, height); |
|
} |
|
|
|
void XournalView::zoomChanged() { |
|
Layout* layout = gtk_xournal_get_layout(this->widget); |
|
size_t currentPage = this->getCurrentPage(); |
|
XojPageView* view = getViewFor(currentPage); |
|
ZoomControl* zoom = control->getZoomControl(); |
|
|
|
if (!view) { |
|
return; |
|
} |
|
|
|
|
|
if (zoom->isZoomPresentationMode() || zoom->isZoomFitMode()) { |
|
scrollTo(currentPage); |
|
} else { |
|
auto pos = zoom->getScrollPositionAfterZoom(); |
|
if (pos.x != -1 && pos.y != -1) { |
|
// Todo: This could be one source of all evil: |
|
layout->scrollAbs(pos.x, pos.y); |
|
} |
|
} |
|
// move this somewhere else maybe |
|
layout->recalculate(); |
|
|
|
Document* doc = control->getDocument(); |
|
doc->lock(); |
|
auto const& file = doc->getEvMetadataFilename(); |
|
doc->unlock(); |
|
|
|
control->getMetadataManager()->storeMetadata(file, getCurrentPage(), zoom->getZoomReal()); |
|
|
|
// Updates the Eraser's cursor icon in order to make it as big as the erasing area |
|
control->getCursor()->updateCursor(); |
|
|
|
this->control->getScheduler()->blockRerenderZoom(); |
|
} |
|
|
|
void XournalView::pageSizeChanged(size_t page) { layoutPages(); } |
|
|
|
void XournalView::pageChanged(size_t page) { |
|
if (page != npos && page < this->viewPages.size()) { |
|
this->viewPages[page]->rerenderPage(); |
|
} |
|
} |
|
|
|
void XournalView::pageDeleted(size_t page) { |
|
size_t currentPage = control->getCurrentPageNo(); |
|
|
|
delete this->viewPages[page]; |
|
viewPages.erase(begin(viewPages) + page); |
|
|
|
layoutPages(); |
|
control->getScrollHandler()->scrollToPage(currentPage); |
|
} |
|
|
|
auto XournalView::getTextEditor() -> TextEditor* { |
|
for (auto&& page: viewPages) { |
|
if (page->getTextEditor()) { |
|
return page->getTextEditor(); |
|
} |
|
} |
|
|
|
return nullptr; |
|
} |
|
|
|
void XournalView::resetShapeRecognizer() { |
|
for (auto&& page: viewPages) { |
|
page->resetShapeRecognizer(); |
|
} |
|
} |
|
|
|
auto XournalView::getCache() -> PdfCache* { return this->cache; } |
|
|
|
void XournalView::pageInserted(size_t page) { |
|
Document* doc = control->getDocument(); |
|
doc->lock(); |
|
auto* pageView = new XojPageView(this, doc->getPage(page)); |
|
doc->unlock(); |
|
|
|
viewPages.insert(begin(viewPages) + page, pageView); |
|
|
|
Layout* layout = gtk_xournal_get_layout(this->widget); |
|
|
|
// recalculate the layout width and height amd layout the pages with the updated layout size |
|
layout->recalculate(); |
|
layout->layoutPages(layout->getMinimalWidth(), layout->getMinimalHeight()); |
|
|
|
// check which pages are visible and select the most visible page |
|
layout->updateVisibility(); |
|
} |
|
|
|
auto XournalView::getZoom() -> double { return control->getZoomControl()->getZoom(); } |
|
|
|
auto XournalView::getDpiScaleFactor() -> int { return gtk_widget_get_scale_factor(widget); } |
|
|
|
void XournalView::clearSelection() { |
|
EditSelection* sel = GTK_XOURNAL(widget)->selection; |
|
GTK_XOURNAL(widget)->selection = nullptr; |
|
delete sel; |
|
|
|
control->setClipboardHandlerSelection(getSelection()); |
|
|
|
getCursor()->setMouseSelectionType(CURSOR_SELECTION_NONE); |
|
control->getToolHandler()->setSelectionEditTools(false, false, false); |
|
} |
|
|
|
void XournalView::deleteSelection(EditSelection* sel) { |
|
if (sel == nullptr) { |
|
sel = getSelection(); |
|
} |
|
|
|
if (sel) { |
|
XojPageView* view = sel->getView(); |
|
auto undo = std::make_unique<DeleteUndoAction>(sel->getSourcePage(), false); |
|
sel->fillUndoItem(undo.get()); |
|
control->getUndoRedoHandler()->addUndoAction(std::move(undo)); |
|
|
|
clearSelection(); |
|
|
|
view->rerenderPage(); |
|
repaintSelection(true); |
|
} |
|
} |
|
|
|
void XournalView::setSelection(EditSelection* selection) { |
|
clearSelection(); |
|
GTK_XOURNAL(this->widget)->selection = selection; |
|
|
|
control->setClipboardHandlerSelection(getSelection()); |
|
|
|
bool canChangeSize = false; |
|
bool canChangeColor = false; |
|
bool canChangeFill = false; |
|
|
|
for (Element* e: *selection->getElements()) { |
|
if (e->getType() == ELEMENT_TEXT) { |
|
canChangeColor = true; |
|
} else if (e->getType() == ELEMENT_STROKE) { |
|
auto* s = dynamic_cast<Stroke*>(e); |
|
if (s->getToolType() != STROKE_TOOL_ERASER) { |
|
canChangeColor = true; |
|
canChangeFill = true; |
|
} |
|
canChangeSize = true; |
|
} |
|
|
|
if (canChangeColor && canChangeSize && canChangeFill) { |
|
break; |
|
} |
|
} |
|
|
|
control->getToolHandler()->setSelectionEditTools(canChangeColor, canChangeSize, canChangeFill); |
|
|
|
repaintSelection(); |
|
} |
|
|
|
void XournalView::repaintSelection(bool evenWithoutSelection) { |
|
if (evenWithoutSelection) { |
|
gtk_widget_queue_draw(this->widget); |
|
return; |
|
} |
|
|
|
EditSelection* selection = getSelection(); |
|
if (selection == nullptr) { |
|
return; |
|
} |
|
|
|
// repaint always the whole widget |
|
gtk_widget_queue_draw(this->widget); |
|
} |
|
|
|
/** |
|
* Recalculates the layout height and width for the XournalView widget |
|
*/ |
|
void XournalView::layoutPages() { |
|
Layout* layout = gtk_xournal_get_layout(this->widget); |
|
layout->recalculate(); |
|
} |
|
|
|
auto XournalView::getDisplayHeight() const -> int { |
|
GtkAllocation allocation = {0}; |
|
gtk_widget_get_allocation(this->widget, &allocation); |
|
return allocation.height; |
|
} |
|
|
|
auto XournalView::getDisplayWidth() const -> int { |
|
GtkAllocation allocation = {0}; |
|
gtk_widget_get_allocation(this->widget, &allocation); |
|
return allocation.width; |
|
} |
|
|
|
auto XournalView::isPageVisible(size_t page, int* visibleHeight) -> bool { |
|
Rectangle<double>* rect = getVisibleRect(page); |
|
if (rect) { |
|
if (visibleHeight) { |
|
*visibleHeight = std::lround(rect->height); |
|
} |
|
|
|
delete rect; |
|
return true; |
|
} |
|
if (visibleHeight) { |
|
*visibleHeight = 0; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void XournalView::documentChanged(DocumentChangeType type) { |
|
if (type != DOCUMENT_CHANGE_CLEARED && type != DOCUMENT_CHANGE_COMPLETE) { |
|
return; |
|
} |
|
|
|
XournalScheduler* scheduler = this->control->getScheduler(); |
|
scheduler->lock(); |
|
scheduler->removeAllJobs(); |
|
|
|
clearSelection(); |
|
|
|
for (auto&& page: viewPages) { |
|
delete page; |
|
} |
|
viewPages.clear(); |
|
|
|
this->cache->clearCache(); |
|
|
|
Document* doc = control->getDocument(); |
|
doc->lock(); |
|
|
|
size_t pagecount = doc->getPageCount(); |
|
viewPages.reserve(pagecount); |
|
for (size_t i = 0; i < pagecount; i++) { |
|
viewPages.push_back(new XojPageView(this, doc->getPage(i))); |
|
} |
|
|
|
doc->unlock(); |
|
|
|
layoutPages(); |
|
scrollTo(0, 0); |
|
|
|
scheduler->unlock(); |
|
} |
|
|
|
auto XournalView::cut() -> bool { |
|
size_t p = getCurrentPage(); |
|
if (p == npos || p >= viewPages.size()) { |
|
return false; |
|
} |
|
|
|
XojPageView* page = viewPages[p]; |
|
return page->cut(); |
|
} |
|
|
|
auto XournalView::copy() -> bool { |
|
size_t p = getCurrentPage(); |
|
if (p == npos || p >= viewPages.size()) { |
|
return false; |
|
} |
|
|
|
XojPageView* page = viewPages[p]; |
|
return page->copy(); |
|
} |
|
|
|
auto XournalView::paste() -> bool { |
|
size_t p = getCurrentPage(); |
|
if (p == npos || p >= viewPages.size()) { |
|
return false; |
|
} |
|
|
|
XojPageView* page = viewPages[p]; |
|
return page->paste(); |
|
} |
|
|
|
auto XournalView::actionDelete() -> bool { |
|
size_t p = getCurrentPage(); |
|
if (p == npos || p >= viewPages.size()) { |
|
return false; |
|
} |
|
|
|
XojPageView* page = viewPages[p]; |
|
return page->actionDelete(); |
|
} |
|
|
|
auto XournalView::getDocument() -> Document* { return control->getDocument(); } |
|
|
|
auto XournalView::getViewPages() const -> std::vector<XojPageView*> const& { return viewPages; } |
|
|
|
auto XournalView::getCursor() -> XournalppCursor* { return control->getCursor(); } |
|
|
|
auto XournalView::getSelection() -> EditSelection* { |
|
g_return_val_if_fail(this->widget != nullptr, nullptr); |
|
g_return_val_if_fail(GTK_IS_XOURNAL(this->widget), nullptr); |
|
|
|
return GTK_XOURNAL(this->widget)->selection; |
|
}
|
|
|