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.
 
 
 
 
 
 

3463 lines
72 KiB

#include "Control.h"
#include "ExportHandler.h"
#include "PrintHandler.h"
#include "gui/Cursor.h"
#include "gui/dialog/AboutDialog.h"
#include "gui/dialog/GotoDialog.h"
#include "gui/dialog/FormatDialog.h"
#include "gui/dialog/ImagesDialog.h"
#include "gui/dialog/SettingsDialog.h"
#include "gui/dialog/PdfPagesDialog.h"
#include "gui/dialog/SelectBackgroundColorDialog.h"
#include "gui/dialog/toolbarCustomize/ToolbarDragDropHandler.h"
#include "gui/dialog/ToolbarManageDialog.h"
#include "gui/TextEditor.h"
#include "gui/toolbarMenubar/model/ToolbarData.h"
#include "gui/toolbarMenubar/model/ToolbarModel.h"
#include "gui/toolbarMenubar/ToolMenuHandler.h"
#include "gui/XournalView.h"
#include "jobs/AutosaveJob.h"
#include "jobs/BlockingJob.h"
#include "jobs/PdfExportJob.h"
#include "jobs/SaveJob.h"
#include "xojfile/LoadHandler.h"
#include "model/BackgroundImage.h"
#include "model/FormatDefinitions.h"
#include "model/XojPage.h"
#include "settings/ButtonConfig.h"
#include "settings/MetadataManager.h"
#include "stockdlg/ImageOpenDlg.h"
#include "stockdlg/XojOpenDlg.h"
#include "undo/AddUndoAction.h"
#include "undo/DeleteUndoAction.h"
#include "undo/InsertDeletePageUndoAction.h"
#include "undo/InsertLayerUndoAction.h"
#include "undo/InsertUndoAction.h"
#include "undo/PageBackgroundChangedUndoAction.h"
#include "undo/RemoveLayerUndoAction.h"
#include "view/DocumentView.h"
#include <config.h>
#include <config-dev.h>
#include <config-features.h>
#include <CrashHandler.h>
#include <i18n.h>
#include <serializing/ObjectInputStream.h>
#include <Stacktrace.h>
#include <XInputUtils.h>
#include <boost/locale.hpp>
#include <boost/filesystem.hpp>
namespace bf = boost::filesystem;
#include <gtk/gtk.h>
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
#include <vector>
using std::vector;
// TODO Check for error log on startup, also check for emergency save document!
Control::Control(GladeSearchpath* gladeSearchPath)
{
XOJ_INIT_TYPE(Control);
this->win = NULL;
this->recent = new RecentManager();
this->undoRedo = new UndoRedoHandler(this);
this->recent->addListener(this);
this->undoRedo->addUndoRedoListener(this);
this->isBlocking = false;
this->gladeSearchPath = gladeSearchPath;
this->metadata = new MetadataManager();
this->cursor = new Cursor(this);
this->lastAction = ACTION_NONE;
this->lastGroup = GROUP_NOGROUP;
this->lastEnabled = false;
this->fullscreen = false;
path name = path(g_get_home_dir());
name /= CONFIG_DIR;
name /= SETTINGS_XML_FILE;
this->settings = new Settings(name);
this->settings->load();
this->sidebar = NULL;
this->searchBar = NULL;
this->scrollHandler = new ScrollHandler(this);
this->scheduler = new XournalScheduler();
this->hiddenFullscreenWidgets = NULL;
this->sidebarHidden = false;
this->autosaveTimeout = 0;
this->defaultWidth = -1;
this->defaultHeight = -1;
this->statusbar = NULL;
this->lbState = NULL;
this->pgState = NULL;
this->maxState = 0;
this->doc = new Document(this);
// for crashhandling
setEmergencyDocument(this->doc);
this->zoom = new ZoomControl();
this->zoom->setZoom100(this->settings->getDisplayDpi() / 72.0);
this->toolHandler = new ToolHandler(this, this, this->settings);
this->toolHandler->loadSettings();
/**
* This is needed to update the previews
*/
this->changeTimout = g_timeout_add_seconds(10, (GSourceFunc) checkChangedDocument, this);
this->clipboardHandler = NULL;
this->dragDropHandler = NULL;
}
Control::~Control()
{
XOJ_CHECK_TYPE(Control);
g_source_remove(this->changeTimout);
this->enableAutosave(false);
deleteLastAutosaveFile("");
this->scheduler->stop();
for (XojPage* page : this->changedPages)
{
page->unreference();
}
delete this->clipboardHandler;
delete this->recent;
delete this->undoRedo;
delete this->settings;
delete this->toolHandler;
delete this->sidebar;
delete this->doc;
delete this->searchBar;
delete this->scrollHandler;
delete this->metadata;
delete this->cursor;
delete this->zoom;
delete this->scheduler;
delete this->dragDropHandler;
XOJ_RELEASE_TYPE(Control);
}
void Control::renameLastAutosaveFile()
{
XOJ_CHECK_TYPE(Control);
if (!this->lastAutosaveFilename.empty())
{
path filename = this->lastAutosaveFilename;
path renamed = Util::getAutosaveFilename();
renamed.replace_extension(filename.filename());
if (bf::exists(filename))
{
bf::remove(renamed);
bf::rename(filename, renamed);
}
else
{
bf::remove(renamed);
this->save(false);
bf::rename(filename, renamed);
bf::remove(filename);
}
}
}
void Control::setLastAutosaveFile(path newAutosaveFile)
{
this->lastAutosaveFilename = newAutosaveFile;
}
void Control::deleteLastAutosaveFile(path newAutosaveFile)
{
XOJ_CHECK_TYPE(Control);
if (!this->lastAutosaveFilename.empty())
{
// delete old autosave file
bf::remove(path(this->lastAutosaveFilename));
}
this->lastAutosaveFilename = newAutosaveFile;
}
bool Control::checkChangedDocument(Control* control)
{
XOJ_CHECK_TYPE_OBJ(control, Control);
if (!control->doc->tryLock())
{
// call again later
return true;
}
for (XojPage* page : control->changedPages)
{
int p = control->doc->indexOf(page);
if (p != -1)
{
control->firePageChanged(p);
}
page->unreference();
}
control->changedPages.clear();
control->doc->unlock();
// Call again
return true;
}
void Control::saveSettings()
{
XOJ_CHECK_TYPE(Control);
this->toolHandler->saveSettings();
gint width = 0;
gint height = 0;
gtk_window_get_size((GtkWindow*) *this->win, &width, &height);
if (!this->win->isMaximized())
{
this->settings->setMainWndSize(width, height);
}
this->settings->setMainWndMaximized(this->win->isMaximized());
this->sidebar->saveSize();
}
void Control::initWindow(MainWindow* win)
{
XOJ_CHECK_TYPE(Control);
win->setRecentMenu(recent->getMenu());
selectTool(toolHandler->getToolType());
this->win = win;
this->zoom->initZoomHandler(win->getXournal()->getWidget());
this->sidebar = new Sidebar(win, this);
updatePageNumbers(0, -1);
toolHandler->eraserTypeChanged();
this->searchBar = new SearchBar(this);
// Disable undo buttons
undoRedoChanged();
setViewTwoPages(settings->isShowTwoPages());
setViewPresentationMode(settings->isPresentationMode());
setPageInsertType(settings->getPageInsertType());
penSizeChanged();
eraserSizeChanged();
hilighterSizeChanged();
updateDeletePageButton();
this->clipboardHandler = new ClipboardHandler(this, win->getXournal()->getWidget());
this->enableAutosave(settings->isAutosaveEnabled());
win->setFontButtonFont(settings->getFont());
XInputUtils::initUtils(win->getWindow());
XInputUtils::setLeafEnterWorkaroundEnabled(settings->isEnableLeafEnterWorkaround());
}
bool Control::autosaveCallback(Control* control)
{
XOJ_CHECK_TYPE_OBJ(control, Control);
if (!control->undoRedo->isChangedAutosave())
{
//cout << "Info: autosave not necessary, nothing changed..." << endl;
// do nothing, nothing changed
return true;
}
else
{
cout << "Info: autosave document..." << endl;
}
AutosaveJob* job = new AutosaveJob(control);
control->scheduler->addJob(job, JOB_PRIORITY_NONE);
job->unref();
return true;
}
void Control::enableAutosave(bool enable)
{
XOJ_CHECK_TYPE(Control);
if (this->autosaveTimeout)
{
g_source_remove(this->autosaveTimeout);
this->autosaveTimeout = 0;
}
if (enable)
{
int timeout = settings->getAutosaveTimeout() * 60;
this->autosaveTimeout = g_timeout_add_seconds(timeout, (GSourceFunc) autosaveCallback, this);
}
}
void Control::updatePageNumbers(int page, int pdfPage)
{
XOJ_CHECK_TYPE(Control);
if (this->win == NULL)
{
return;
}
this->win->updatePageNumbers(page, this->doc->getPageCount(), pdfPage);
this->sidebar->selectPageNr(page, pdfPage);
this->metadata->setInt(this->doc->getEvMetadataFilename(), "page", page);
int current = this->win->getXournal()->getCurrentPage();
int count = this->doc->getPageCount();
fireEnableAction(ACTION_GOTO_FIRST, current != 0);
fireEnableAction(ACTION_GOTO_BACK, current != 0);
fireEnableAction(ACTION_GOTO_PREVIOUS_ANNOTATED_PAGE, current != 0);
fireEnableAction(ACTION_GOTO_PAGE, count > 1);
fireEnableAction(ACTION_GOTO_NEXT, current < count - 1);
fireEnableAction(ACTION_GOTO_LAST, current < count - 1);
fireEnableAction(ACTION_GOTO_NEXT_ANNOTATED_PAGE, current < count - 1);
}
void Control::actionPerformed(ActionType type, ActionGroup group, GdkEvent* event, GtkMenuItem* menuitem,
GtkToolButton* toolbutton, bool enabled)
{
XOJ_CHECK_TYPE(Control);
switch (type)
{
// Menu File
case ACTION_NEW:
clearSelectionEndText();
newFile();
break;
case ACTION_OPEN:
clearSelectionEndText();
openFile();
break;
case ACTION_ANNOTATE_PDF:
clearSelectionEndText();
annotatePdf("", false, false);
break;
case ACTION_SAVE:
save();
break;
case ACTION_SAVE_AS:
saveAs();
break;
case ACTION_EXPORT_AS_PDF:
exportAsPdf();
break;
case ACTION_EXPORT_AS:
exportAs();
break;
case ACTION_DOCUMENT_PROPERTIES:
// TODO LOW PRIO: not implemented, but menupoint is hidden...
break;
case ACTION_PRINT:
print();
break;
case ACTION_QUIT:
quit();
break;
// Menu Edit
case ACTION_UNDO:
this->clearSelection();
//Move out of text mode to allow textboxundo to work
clearSelectionEndText();
undoRedo->undo();
this->resetShapeRecognizer();
break;
case ACTION_REDO:
this->clearSelection();
undoRedo->redo();
this->resetShapeRecognizer();
break;
case ACTION_CUT:
cut();
break;
case ACTION_COPY:
copy();
break;
case ACTION_PASTE:
paste();
break;
case ACTION_SEARCH:
clearSelectionEndText();
searchBar->showSearchBar(true);
break;
case ACTION_DELETE:
if (!win->getXournal()->actionDelete())
{
deleteSelection();
}
break;
case ACTION_SETTINGS:
showSettings();
break;
// Menu Navigation
case ACTION_GOTO_FIRST:
scrollHandler->scrollToPage(0);
break;
case ACTION_GOTO_BACK:
scrollHandler->goToPreviousPage();
break;
case ACTION_GOTO_PAGE:
gotoPage();
break;
case ACTION_GOTO_NEXT:
scrollHandler->goToNextPage();
break;
case ACTION_GOTO_LAST:
scrollHandler->scrollToPage(this->doc->getPageCount() - 1);
break;
case ACTION_GOTO_NEXT_ANNOTATED_PAGE:
scrollHandler->scrollToAnnotatedPage(true);
break;
case ACTION_GOTO_PREVIOUS_ANNOTATED_PAGE:
scrollHandler->scrollToAnnotatedPage(false);
break;
// Menu Journal
case ACTION_NEW_PAGE_BEFORE:
insertNewPage(getCurrentPageNo());
break;
case ACTION_NEW_PAGE_AFTER:
insertNewPage(getCurrentPageNo() + 1);
break;
case ACTION_NEW_PAGE_AT_END:
insertNewPage(this->doc->getPageCount());
break;
case ACTION_DELETE_PAGE:
deletePage();
break;
case ACTION_NEW_LAYER:
addNewLayer();
break;
case ACTION_DELETE_LAYER:
deleteCurrentLayer();
break;
case ACTION_PAPER_FORMAT:
paperFormat();
break;
case ACTION_PAPER_BACKGROUND_COLOR:
changePageBackgroundColor();
break;
case ACTION_SET_PAPER_BACKGROUND_PLAIN:
case ACTION_SET_PAPER_BACKGROUND_LINED:
case ACTION_SET_PAPER_BACKGROUND_RULED:
case ACTION_SET_PAPER_BACKGROUND_GRAPH:
case ACTION_SET_PAPER_BACKGROUND_IMAGE:
case ACTION_SET_PAPER_BACKGROUND_PDF:
clearSelectionEndText();
setPageBackground(type);
break;
case ACTION_NEW_PAGE_PLAIN:
clearSelectionEndText();
if (enabled)
{
setPageInsertType(PAGE_INSERT_TYPE_PLAIN);
}
break;
case ACTION_NEW_PAGE_LINED:
clearSelectionEndText();
if (enabled)
{
setPageInsertType(PAGE_INSERT_TYPE_LINED);
}
break;
case ACTION_NEW_PAGE_RULED:
clearSelectionEndText();
if (enabled)
{
setPageInsertType(PAGE_INSERT_TYPE_RULED);
}
break;
case ACTION_NEW_PAGE_GRAPH:
clearSelectionEndText();
if (enabled)
{
setPageInsertType(PAGE_INSERT_TYPE_GRAPH);
}
break;
case ACTION_NEW_PAGE_COPY:
clearSelectionEndText();
if (enabled)
{
setPageInsertType(PAGE_INSERT_TYPE_COPY);
}
break;
case ACTION_NEW_PAGE_PDF_BACKGROUND:
clearSelectionEndText();
if (enabled)
{
setPageInsertType(PAGE_INSERT_TYPE_PDF_BACKGROUND);
}
break;
// Menu Tools
case ACTION_TOOL_PEN:
clearSelection();
if (enabled)
{
selectTool(TOOL_PEN);
}
break;
case ACTION_TOOL_ERASER:
clearSelection();
if (enabled)
{
selectTool(TOOL_ERASER);
}
break;
case ACTION_TOOL_ERASER_STANDARD:
if (enabled)
{
toolHandler->setEraserType(ERASER_TYPE_DEFAULT);
}
break;
case ACTION_TOOL_ERASER_DELETE_STROKE:
if (enabled)
{
toolHandler->setEraserType(ERASER_TYPE_DELETE_STROKE);
}
break;
case ACTION_TOOL_ERASER_WHITEOUT:
if (enabled)
{
toolHandler->setEraserType(ERASER_TYPE_WHITEOUT);
}
break;
case ACTION_TOOL_HILIGHTER:
clearSelection();
if (enabled)
{
selectTool(TOOL_HILIGHTER);
}
break;
case ACTION_TOOL_TEXT:
clearSelection();
if (enabled)
{
selectTool(TOOL_TEXT);
}
break;
case ACTION_TOOL_IMAGE:
clearSelection();
if (enabled)
{
selectTool(TOOL_IMAGE);
}
break;
case ACTION_TOOL_SELECT_RECT:
if (enabled)
{
selectTool(TOOL_SELECT_RECT);
}
break;
case ACTION_TOOL_SELECT_REGION:
if (enabled)
{
selectTool(TOOL_SELECT_REGION);
}
break;
case ACTION_TOOL_SELECT_OBJECT:
if (enabled)
{
selectTool(TOOL_SELECT_OBJECT);
}
break;
case ACTION_TOOL_VERTICAL_SPACE:
clearSelection();
if (enabled)
{
selectTool(TOOL_VERTICAL_SPACE);
}
break;
case ACTION_TOOL_HAND:
if (enabled)
{
selectTool(TOOL_HAND);
}
break;
case ACTION_TOOL_DRAW_RECT:
setRectangleEnabled(enabled);
break;
case ACTION_TOOL_DRAW_CIRCLE:
setCircleEnabled(enabled);
break;
case ACTION_TOOL_DRAW_ARROW:
// selectTool(TOOL_DRAW_ARROW);
setArrowEnabled(enabled);
break;
case ACTION_TOOL_DEFAULT:
if (enabled)
{
selectDefaultTool();
}
break;
case ACTION_RULER:
setRulerEnabled(enabled);
break;
case ACTION_SHAPE_RECOGNIZER:
setShapeRecognizerEnabled(enabled);
break;
case ACTION_SIZE_VERY_THIN:
if (enabled)
{
setToolSize(TOOL_SIZE_VERY_FINE);
}
break;
case ACTION_SIZE_FINE:
if (enabled)
{
setToolSize(TOOL_SIZE_FINE);
}
break;
case ACTION_SIZE_MEDIUM:
if (enabled)
{
setToolSize(TOOL_SIZE_MEDIUM);
}
break;
case ACTION_SIZE_THICK:
if (enabled)
{
setToolSize(TOOL_SIZE_THICK);
}
break;
case ACTION_SIZE_VERY_THICK:
if (enabled)
{
setToolSize(TOOL_SIZE_VERY_THICK);
}
break;
case ACTION_TOOL_ERASER_SIZE_FINE:
if (enabled)
{
this->toolHandler->setEraserSize(TOOL_SIZE_FINE);
eraserSizeChanged();
}
break;
case ACTION_TOOL_ERASER_SIZE_MEDIUM:
if (enabled)
{
this->toolHandler->setEraserSize(TOOL_SIZE_MEDIUM);
eraserSizeChanged();
}
break;
case ACTION_TOOL_ERASER_SIZE_THICK:
if (enabled)
{
this->toolHandler->setEraserSize(TOOL_SIZE_THICK);
eraserSizeChanged();
}
break;
case ACTION_TOOL_PEN_SIZE_VERY_THIN:
if (enabled)
{
this->toolHandler->setPenSize(TOOL_SIZE_VERY_FINE);
penSizeChanged();
}
break;
case ACTION_TOOL_PEN_SIZE_FINE:
if (enabled)
{
this->toolHandler->setPenSize(TOOL_SIZE_FINE);
penSizeChanged();
}
break;
case ACTION_TOOL_PEN_SIZE_MEDIUM:
if (enabled)
{
this->toolHandler->setPenSize(TOOL_SIZE_MEDIUM);
penSizeChanged();
}
break;
case ACTION_TOOL_PEN_SIZE_THICK:
if (enabled)
{
this->toolHandler->setPenSize(TOOL_SIZE_THICK);
penSizeChanged();
}
break;
case ACTION_TOOL_PEN_SIZE_VERY_THICK:
if (enabled)
{
this->toolHandler->setPenSize(TOOL_SIZE_VERY_THICK);
penSizeChanged();
}
break;
case ACTION_TOOL_HILIGHTER_SIZE_FINE:
if (enabled)
{
this->toolHandler->setHilighterSize(TOOL_SIZE_FINE);
hilighterSizeChanged();
}
break;
case ACTION_TOOL_HILIGHTER_SIZE_MEDIUM:
if (enabled)
{
this->toolHandler->setHilighterSize(TOOL_SIZE_MEDIUM);
hilighterSizeChanged();
}
break;
case ACTION_TOOL_HILIGHTER_SIZE_THICK:
if (enabled)
{
this->toolHandler->setHilighterSize(TOOL_SIZE_THICK);
hilighterSizeChanged();
}
break;
case ACTION_FONT_BUTTON_CHANGED:
fontChanged();
break;
case ACTION_SELECT_FONT:
if (win)
{
win->getToolMenuHandler()->showFontSelectionDlg();
}
break;
// Used for all colors
case ACTION_SELECT_COLOR:
case ACTION_SELECT_COLOR_CUSTOM:
// nothing to do here, the color toolbar item handles the color
break;
case ACTION_TEX:
runLatex();
break;
// Menu View
case ACTION_ZOOM_100:
case ACTION_ZOOM_FIT:
case ACTION_ZOOM_IN:
case ACTION_ZOOM_OUT:
invokeLater(type);
break;
case ACTION_VIEW_TWO_PAGES:
setViewTwoPages(enabled);
break;
case ACTION_VIEW_PRESENTATION_MODE:
setViewPresentationMode(enabled);
break;
case ACTION_FOOTER_LAYER:
{
clearSelectionEndText();
PageRef p = getCurrentPage();
if (p.isValid())
{
p->setSelectedLayerId(this->win->getCurrentLayer());
this->win->getXournal()->layerChanged(getCurrentPageNo());
this->win->updateLayerCombobox();
if (p.isValid())
{
int layer = p->getSelectedLayerId();
fireEnableAction(ACTION_DELETE_LAYER, layer > 0);
}
}
}
break;
case ACTION_MANAGE_TOOLBAR:
manageToolbars();
break;
case ACTION_CUSTOMIZE_TOOLBAR:
customizeToolbars();
break;
case ACTION_FULLSCREEN:
enableFullscreen(enabled);
break;
// Footer, not really an action, but need an identifier to
case ACTION_FOOTER_PAGESPIN:
case ACTION_FOOTER_ZOOM_SLIDER:
// nothing to do here
break;
// Menu Help
case ACTION_HELP:
this->help();
break;
case ACTION_ABOUT:
showAbout();
break;
default:
g_warning("Unhandled action event: %i / %i", type, group);
Stacktrace::printStracktrace();
}
if (type >= ACTION_TOOL_PEN && type <= ACTION_TOOL_HAND)
{
ActionType at = (ActionType) (toolHandler->getToolType() - TOOL_PEN + ACTION_TOOL_PEN);
if (type == at && !enabled)
{
fireActionSelected(GROUP_TOOL, at);
}
}
}
// TODO: create help for Xournal++
#if OFFLINE_HELP_ENABLED
#define XOJ_HELP "ghelp:xournalpp"
#else
#define XOJ_HELP "https://github.com/xournalpp/xournalpp/wiki/User-Manual"
#endif
void Control::help()
{
GError* error = NULL;
gtk_show_uri(gtk_window_get_screen(GTK_WINDOW(this->win->getWindow())), XOJ_HELP, gtk_get_current_event_time(), &error);
if (error)
{
GtkWidget* dialog = gtk_message_dialog_new((GtkWindow*) getWindow(), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK, "%s",
FC(_F("There was an error displaying help: {1}") % error->message));
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(this->getWindow()->getWindow()));
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
g_error_free(error);
}
}
bool Control::copy()
{
if (this->win && this->win->getXournal()->copy())
{
return true;
}
return this->clipboardHandler->copy();
}
bool Control::cut()
{
if (this->win && this->win->getXournal()->cut())
{
return true;
}
return this->clipboardHandler->cut();
}
bool Control::paste()
{
if (this->win && this->win->getXournal()->paste())
{
return true;
}
return this->clipboardHandler->paste();
}
void Control::clearSelectionEndText()
{
XOJ_CHECK_TYPE(Control);
clearSelection();
if (win)
{
win->getXournal()->endTextAllPages();
}
}
void Control::invokeLater(ActionType type)
{
XOJ_CHECK_TYPE(Control);
g_idle_add((GSourceFunc) &invokeCallback, new CallbackData(this, type));
}
/**
* Fire page selected, but first check if the page Number is valid
*
* @return the page ID or -1 if the page is not found
*/
int Control::firePageSelected(PageRef page)
{
XOJ_CHECK_TYPE(Control);
this->doc->lock();
int pageId = this->doc->indexOf(page);
this->doc->unlock();
if (pageId == -1)
{
return -1;
}
DocumentHandler::firePageSelected(pageId);
return pageId;
}
void Control::firePageSelected(int page)
{
XOJ_CHECK_TYPE(Control);
DocumentHandler::firePageSelected(page);
}
void Control::manageToolbars()
{
XOJ_CHECK_TYPE(Control);
ToolbarManageDialog dlg(this->gladeSearchPath, this->win->getToolbarModel());
dlg.show(GTK_WINDOW(this->win->getWindow()));
this->win->updateToolbarMenu();
const char* file = Util::getConfigFile(TOOLBAR_CONFIG).c_str();
this->win->getToolbarModel()->save(file);
}
void Control::customizeToolbars()
{
XOJ_CHECK_TYPE(Control);
g_return_if_fail(this->win != NULL);
if (this->win->getSelectedToolbar()->isPredefined())
{
GtkWidget* dialog = gtk_message_dialog_new((GtkWindow*) *this->win, GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "%s",
FC(_F("The Toolbarconfiguration \"{1}\" is predefined, "
"would you create a copy to edit?")
% this->win->getSelectedToolbar()->getName()));
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(this->getWindow()->getWindow()));
int res = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
if (res == -8) // Yes
{
ToolbarData* data = new ToolbarData(*this->win->getSelectedToolbar());
ToolbarModel* model = this->win->getToolbarModel();
for (int i = 0; i < 100; i++)
{
string id = data->getId() + " Copy";
if (i != 0)
{
id += CONCAT(" ", i);
}
if (!model->existsId(id))
{
if (i != 0)
{
data->setName(CONCAT(data->getName(), " ", _("Copy"), " ", i));
}
else
{
data->setName(CONCAT(data->getName(), " ", _("Copy")));
}
data->setId(id);
break;
}
}
model->add(data);
this->win->toolbarSelected(data);
this->win->updateToolbarMenu();
}
else
{
return;
}
}
if (!this->dragDropHandler)
{
this->dragDropHandler = new ToolbarDragDropHandler(this);
}
this->dragDropHandler->configure();
}
void Control::endDragDropToolbar()
{
XOJ_CHECK_TYPE(Control);
if (!this->dragDropHandler)
{
return;
}
this->dragDropHandler->clearToolbarsFromDragAndDrop();
}
void Control::startDragDropToolbar()
{
XOJ_CHECK_TYPE(Control);
if (!this->dragDropHandler)
{
return;
}
this->dragDropHandler->prepareToolbarsForDragAndDrop();
}
bool Control::isInDragAndDropToolbar()
{
XOJ_CHECK_TYPE(Control);
if (!this->dragDropHandler)
{
return false;
}
return this->dragDropHandler->isInDragAndDrop();
}
void Control::setRulerEnabled(bool enabled)
{
XOJ_CHECK_TYPE(Control);
if (this->toolHandler->isRuler() == enabled)
{
return;
}
this->toolHandler->setRuler(enabled);
fireActionSelected(GROUP_RULER, enabled ? ACTION_RULER : ACTION_NONE);
if (enabled)
{
this->toolHandler->setRuler(true, true);
}
}
void Control::setRectangleEnabled(bool enabled)
{
XOJ_CHECK_TYPE(Control);
if (this->toolHandler->isRectangle() == enabled)
{
return;
}
this->toolHandler->setRectangle(enabled);
fireActionSelected(GROUP_RULER, enabled ? ACTION_TOOL_DRAW_RECT : ACTION_NONE);
if (enabled)
{
this->toolHandler->setRectangle(true, true);
}
}
void Control::setArrowEnabled(bool enabled)
{
XOJ_CHECK_TYPE(Control);
if (this->toolHandler->isArrow() == enabled)
{
return;
}
this->toolHandler->setArrow(enabled);
fireActionSelected(GROUP_RULER, enabled ? ACTION_TOOL_DRAW_ARROW : ACTION_NONE);
if (enabled)
{
this->toolHandler->setArrow(true, true);
}
}
void Control::setCircleEnabled(bool enabled)
{
XOJ_CHECK_TYPE(Control);
if (this->toolHandler->isCircle() == enabled)
{
return;
}
this->toolHandler->setCircle(enabled);
fireActionSelected(GROUP_RULER, enabled ? ACTION_TOOL_DRAW_CIRCLE : ACTION_NONE);
if (enabled)
{
this->toolHandler->setCircle(true, true);
}
}
void Control::setShapeRecognizerEnabled(bool enabled)
{
XOJ_CHECK_TYPE(Control);
if (this->toolHandler->isShapeRecognizer() == enabled)
{
return;
}
this->toolHandler->setShapeRecognizer(enabled);
fireActionSelected(GROUP_SHAPE_RECOGNIZER, enabled ? ACTION_SHAPE_RECOGNIZER : ACTION_NONE);
if (enabled)
{
this->toolHandler->setShapeRecognizer(true, true);
this->resetShapeRecognizer();
}
}
void Control::enableFullscreen(bool enabled, bool presentation)
{
XOJ_CHECK_TYPE(Control);
if (enabled)
{
gtk_window_fullscreen((GtkWindow*) *win);
string str = presentation ? settings->getPresentationHideElements() : settings->getFullscreenHideElements();
using std::vector;
vector<string> part;
ba::split(part, str, boost::is_any_of(","));
for (string s : part)
{
if ("sidebarContents" == s && settings->isSidebarVisible())
{
this->sidebarHidden = true;
win->setSidebarVisible(false);
}
else
{
GtkWidget* w = win->get(s.c_str());
if (w == NULL)
{
g_warning("Fullscreen: Try to hide \"%s\", but coulden't find it. Wrong entry in ~/"
CONFIG_DIR "/" SETTINGS_XML_FILE "?", s.c_str());
}
else
{
if (gtk_widget_get_visible(w))
{
gtk_widget_hide(w);
this->hiddenFullscreenWidgets = g_list_append(this->hiddenFullscreenWidgets, w);
}
}
}
}
}
else
{
gtk_window_unfullscreen((GtkWindow*) *win);
for (GList* l = this->hiddenFullscreenWidgets; l != NULL; l = l->next)
{
gtk_widget_show(GTK_WIDGET(l->data));
}
if (this->sidebarHidden)
{
this->sidebarHidden = false;
win->setSidebarVisible(true);
}
g_list_free(this->hiddenFullscreenWidgets);
this->hiddenFullscreenWidgets = NULL;
}
fireActionSelected(GROUP_FULLSCREEN, enabled ? ACTION_FULLSCREEN : ACTION_NONE);
this->fullscreen = enabled;
}
void Control::disableSidebarTmp(bool disabled)
{
XOJ_CHECK_TYPE(Control);
this->sidebar->setTmpDisabled(disabled);
}
void Control::addDefaultPage()
{
XOJ_CHECK_TYPE(Control);
PageInsertType type = settings->getPageInsertType();
double width = 0;
double heigth = 0;
getDefaultPagesize(width, heigth);
PageRef page = new XojPage(width, heigth);
page->setBackgroundColor(settings->getPageBackgroundColor());
if (PAGE_INSERT_TYPE_PLAIN == type)
{
page->setBackgroundType(BACKGROUND_TYPE_NONE);
}
else if (PAGE_INSERT_TYPE_RULED == type)
{
page->setBackgroundType(BACKGROUND_TYPE_RULED);
}
else if (PAGE_INSERT_TYPE_GRAPH == type)
{
page->setBackgroundType(BACKGROUND_TYPE_GRAPH);
}
else //PAGE_INSERT_TYPE_LINED or PDF or COPY
{
page->setBackgroundType(BACKGROUND_TYPE_LINED);
}
this->doc->lock();
this->doc->addPage(page);
this->doc->unlock();
updateDeletePageButton();
}
void Control::getDefaultPagesize(double& width, double& height)
{
XOJ_CHECK_TYPE(Control);
if (this->defaultHeight < 0)
{
SElement& format = settings->getCustomElement("format");
format.setComment("paperformat",
"Available values are: system, A4, Letter, Custom: "
"For custom you have to create the tags width and height.");
string settingsPaperFormat;
string paper;
if (format.getString("paperformat", settingsPaperFormat))
{
if (settingsPaperFormat == "system")
{
// nothing to do
}
else if (settingsPaperFormat == "Custom")
{
double w = 0;
double h = 0;
if (format.getDouble("width", w) && format.getDouble("height", h))
{
width = w;
height = h;
this->defaultHeight = h;
this->defaultWidth = w;
return;
}
}
else
{
paper = settingsPaperFormat;
}
}
else
{
format.setString("paperformat", "system");
}
GtkPaperSize* size = NULL;
if (!paper.empty())
{
GList* list = gtk_paper_size_get_paper_sizes(false);
for (GList* l = list; l != NULL; l = l->next)
{
GtkPaperSize* s = (GtkPaperSize*) l->data;
//it would be nice to make StringUtils method, but now I'm not in the mood - down there is basically compareIgnoreCase
if (std::use_facet<bl::collator<char>>(std::locale()).compare(bl::collator_base::secondary,
paper, gtk_paper_size_get_display_name(s)))
{
size = s;
}
else
{
gtk_paper_size_free(s);
}
}
g_list_free(list);
}
if (size == NULL)
{
size = gtk_paper_size_new(NULL);
}
this->defaultWidth = gtk_paper_size_get_width(size, GTK_UNIT_POINTS);
this->defaultHeight = gtk_paper_size_get_height(size, GTK_UNIT_POINTS);
gtk_paper_size_free(size);
}
width = this->defaultWidth;
height = this->defaultHeight;
}
void Control::updateDeletePageButton()
{
XOJ_CHECK_TYPE(Control);
if (this->win)
{
GtkWidget* w = this->win->get("menuDeletePage");
gtk_widget_set_sensitive(w, this->doc->getPageCount() > 1);
}
}
void Control::deletePage()
{
XOJ_CHECK_TYPE(Control);
clearSelectionEndText();
// don't allow delete pages if we have less than 2 pages,
// so we can be (more or less) sure there is at least one page.
if (this->doc->getPageCount() < 2)
{
return;
}
int pNr = getCurrentPageNo();
if (pNr < 0 || pNr > this->doc->getPageCount())
{
// something went wrong...
return;
}
this->doc->lock();
PageRef page = doc->getPage(pNr);
this->doc->unlock();
// first send event, then delete page...
firePageDeleted(pNr);
this->doc->lock();
doc->deletePage(pNr);
this->doc->unlock();
updateDeletePageButton();
this->undoRedo->addUndoAction(new InsertDeletePageUndoAction(page, pNr, false));
if (pNr >= this->doc->getPageCount())
{
pNr = this->doc->getPageCount() - 1;
}
scrollHandler->scrollToPage(pNr, 0);
}
void Control::insertNewPage(int position)
{
XOJ_CHECK_TYPE(Control);
clearSelectionEndText();
PageInsertType type = settings->getPageInsertType();
if (position > doc->getPageCount())
{
position = doc->getPageCount();
}
double width = 0;
double height = 0;
int lastPage = position - 1;
if (lastPage < 0)
{
getDefaultPagesize(width, height);
}
else
{
PageRef page = doc->getPage(lastPage);
if (page.isValid())
{
width = page->getWidth();
height = page->getHeight();
}
else
{
getDefaultPagesize(width, height);
}
}
PageRef page = new XojPage(width, height);
page->setBackgroundColor(settings->getPageBackgroundColor());
if (PAGE_INSERT_TYPE_PLAIN == type)
{
page->setBackgroundType(BACKGROUND_TYPE_NONE);
}
else if (PAGE_INSERT_TYPE_LINED == type)
{
page->setBackgroundType(BACKGROUND_TYPE_LINED);
}
else if (PAGE_INSERT_TYPE_RULED == type)
{
page->setBackgroundType(BACKGROUND_TYPE_RULED);
}
else if (PAGE_INSERT_TYPE_GRAPH == type)
{
page->setBackgroundType(BACKGROUND_TYPE_GRAPH);
}
else if (PAGE_INSERT_TYPE_COPY == type)
{
PageRef current = getCurrentPage();
if (!current.isValid()) // should not happen, but if you open an invalid file or something like this...
{
page->setBackgroundType(BACKGROUND_TYPE_LINED);
}
else
{
BackgroundType bg = current->getBackgroundType();
page->setBackgroundType(bg);
if (bg == BACKGROUND_TYPE_PDF)
{
page->setBackgroundPdfPageNr(current->getPdfPageNr());
}
else if (bg == BACKGROUND_TYPE_IMAGE)
{
page->setBackgroundImage(current->getBackgroundImage());
}
else
{
page->setBackgroundColor(current->getBackgroundColor());
}
page->setSize(current->getWidth(), current->getHeight());
}
}
else if (PAGE_INSERT_TYPE_PDF_BACKGROUND == type)
{
if (this->doc->getPdfPageCount() == 0)
{
GtkWidget* dialog = gtk_message_dialog_new((GtkWindow*) *win,
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
"%s", _C("You don't have any PDF pages to select from. "
"Cancel operation.\nPlease select another background type: "
"Menu \"Journal\" / \"Insert Page Type\"."));
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(this->getWindow()->getWindow()));
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return;
}
else
{
this->doc->lock();
PdfPagesDialog* dlg = new PdfPagesDialog(this->gladeSearchPath, this->doc, this->settings);
for (int i = 0; i < doc->getPageCount(); i++)
{
PageRef p = doc->getPage(i);
if (p->getBackgroundType() == BACKGROUND_TYPE_PDF && p->getPdfPageNr() >= 0)
{
dlg->setPageUsed(i);
}
}
dlg->show(GTK_WINDOW(this->win->getWindow()));
int selected = dlg->getSelectedPage();
delete dlg;
if (selected < 0 || selected >= doc->getPdfPageCount())
{
// page is automatically deleted
return;
}
// no need to set a type, if we set the page number the type is also set
page->setBackgroundPdfPageNr(selected);
XojPopplerPage* p = doc->getPdfPage(selected);
page->setSize(p->getWidth(), p->getHeight());
this->doc->unlock();
}
}
insertPage(page, position);
}
void Control::insertPage(PageRef page, int position)
{
XOJ_CHECK_TYPE(Control);
this->doc->lock();
this->doc->insertPage(page, position);
this->doc->unlock();
firePageInserted(position);
getCursor()->updateCursor();
int visibleHeight = 0;
scrollHandler->isPageVisible(position, &visibleHeight);
if (visibleHeight < 10)
{
scrollHandler->scrollToPage(position);
}
firePageSelected(position);
updateDeletePageButton();
undoRedo->addUndoAction(new InsertDeletePageUndoAction(page, position, true));
}
void Control::addNewLayer()
{
XOJ_CHECK_TYPE(Control);
clearSelectionEndText();
PageRef p = getCurrentPage();
if (!p.isValid())
{
return;
}
Layer* l = new Layer();
p->insertLayer(l, p->getSelectedLayerId());
if (win)
{
win->updateLayerCombobox();
}
undoRedo->addUndoAction(new InsertLayerUndoAction(p, l));
}
void Control::setPageBackground(ActionType type)
{
XOJ_CHECK_TYPE(Control);
PageRef page = getCurrentPage();
if (!page.isValid())
{
return;
}
this->doc->lock();
int pageNr = this->doc->indexOf(page);
this->doc->unlock();
if (pageNr == -1)
{
return; // should not happen...
}
int origPdfPage = page->getPdfPageNr();
BackgroundType origType = page->getBackgroundType();
BackgroundImage origBackgroundImage = page->getBackgroundImage();
double origW = page->getWidth();
double origH = page->getHeight();
if (ACTION_SET_PAPER_BACKGROUND_PLAIN == type)
{
page->setBackgroundType(BACKGROUND_TYPE_NONE);
}
else if (ACTION_SET_PAPER_BACKGROUND_LINED == type)
{
page->setBackgroundType(BACKGROUND_TYPE_LINED);
}
else if (ACTION_SET_PAPER_BACKGROUND_RULED == type)
{
page->setBackgroundType(BACKGROUND_TYPE_RULED);
}
else if (ACTION_SET_PAPER_BACKGROUND_GRAPH == type)
{
page->setBackgroundType(BACKGROUND_TYPE_GRAPH);
}
else if (ACTION_SET_PAPER_BACKGROUND_IMAGE == type)
{
this->doc->lock();
ImagesDialog* dlg = new ImagesDialog(this->gladeSearchPath, this->doc, this->settings);
this->doc->unlock();
dlg->show(GTK_WINDOW(this->win->getWindow()));
BackgroundImage img = dlg->getSelectedImage();
if (!img.isEmpty())
{
page->setBackgroundImage(img);
page->setBackgroundType(BACKGROUND_TYPE_IMAGE);
}
else if (dlg->shouldShowFilechooser())
{
bool attach = false;
GFile* file = ImageOpenDlg::show((GtkWindow*) *win, settings, true, &attach);
if (file == NULL)
{
return;
}
char* name = g_file_get_path(file);
string filename = name;
g_free(name);
g_object_unref(file);
BackgroundImage newImg;
GError* err = NULL;
newImg.loadFile(filename, &err);
newImg.setAttach(attach);
if (err)
{
GtkWidget* dialog = gtk_message_dialog_new((GtkWindow*) *win,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s",
FC(_F("This image could not be loaded. Error message: {1}")
% err->message));
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(this->getWindow()->getWindow()));
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
g_error_free(err);
return;
}
else
{
page->setBackgroundImage(newImg);
page->setBackgroundType(BACKGROUND_TYPE_IMAGE);
}
}
GdkPixbuf* pixbuf = page->getBackgroundImage().getPixbuf();
if (pixbuf)
{
page->setSize(gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf));
firePageSizeChanged(pageNr);
}
delete dlg;
}
else if (ACTION_SET_PAPER_BACKGROUND_PDF == type)
{
if (doc->getPdfPageCount() == 0)
{
GtkWidget* dialog = gtk_message_dialog_new((GtkWindow*) *win,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s",
_C("You don't have any PDF pages to select from. Cancel operation.\n"
"Please select another background type: Menu \"Journal\"\"Insert Page Type\"."));
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(this->getWindow()->getWindow()));
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return;
}
else
{
this->doc->lock();
PdfPagesDialog* dlg = new PdfPagesDialog(this->gladeSearchPath, this->doc, this->settings);
for (int i = 0; i < doc->getPageCount(); i++)
{
PageRef p = doc->getPage(i);
if (p->getBackgroundType() == BACKGROUND_TYPE_PDF && p->getPdfPageNr() >= 0)
{
dlg->setPageUsed(i);
}
}
this->doc->unlock();
dlg->show(GTK_WINDOW(this->win->getWindow()));
int selected = dlg->getSelectedPage();
delete dlg;
if (selected < 0 || selected >= doc->getPdfPageCount())
{
return;
}
// no need to set a type, if we set the page number the type is also set
page->setBackgroundPdfPageNr(selected);
}
}
firePageChanged(pageNr);
updateBackgroundSizeButton();
this->undoRedo->addUndoAction(
new PageBackgroundChangedUndoAction(page, origType, origPdfPage, origBackgroundImage, origW, origH));
}
void Control::gotoPage()
{
GotoDialog* dlg = new GotoDialog(this->gladeSearchPath, this->doc->getPageCount());
dlg->show(GTK_WINDOW(this->win->getWindow()));
int page = dlg->getSelectedPage();
if (page != -1)
{
this->scrollHandler->scrollToPage(page - 1, 0);
}
delete dlg;
}
void Control::updateBackgroundSizeButton()
{
XOJ_CHECK_TYPE(Control);
if (this->win == NULL)
{
return;
}
// Update paper color button
PageRef p = getCurrentPage();
if (!p.isValid() || this->win == NULL)
{
return;
}
BackgroundType bg = p->getBackgroundType();
GtkWidget* paperColor = win->get("menuJournalPaperColor");
GtkWidget* pageSize = win->get("menuJournalPaperFormat");
if (BACKGROUND_TYPE_NONE != bg && BACKGROUND_TYPE_LINED != bg &&
BACKGROUND_TYPE_RULED != bg && BACKGROUND_TYPE_GRAPH != bg)
{
gtk_widget_set_sensitive(paperColor, false);
}
else
{
gtk_widget_set_sensitive(paperColor, true);
}
// PDF page size is defined, you cannot change it
gtk_widget_set_sensitive(pageSize, bg != BACKGROUND_TYPE_PDF);
}
void Control::paperFormat()
{
XOJ_CHECK_TYPE(Control);
PageRef page = getCurrentPage();
if (!page.isValid() || page->getBackgroundType() == BACKGROUND_TYPE_PDF)
{
return;
}
clearSelectionEndText();
FormatDialog* dlg = new FormatDialog(this->gladeSearchPath, settings, page->getWidth(), page->getHeight());
dlg->show(GTK_WINDOW(this->win->getWindow()));
double width = dlg->getWidth();
double height = dlg->getHeight();
if (width > 0)
{
this->doc->lock();
this->doc->setPageSize(page, width, height);
this->doc->unlock();
}
delete dlg;
}
void Control::changePageBackgroundColor()
{
XOJ_CHECK_TYPE(Control);
int pNr = getCurrentPageNo();
this->doc->lock();
PageRef p = this->doc->getPage(pNr);
this->doc->unlock();
if (!p.isValid())
{
return;
}
clearSelectionEndText();
BackgroundType bg = p->getBackgroundType();
if (BACKGROUND_TYPE_NONE != bg && BACKGROUND_TYPE_LINED != bg &&
BACKGROUND_TYPE_RULED != bg && BACKGROUND_TYPE_GRAPH != bg)
{
return;
}
SelectBackgroundColorDialog* dlg = new SelectBackgroundColorDialog(this->gladeSearchPath, this);
dlg->show(GTK_WINDOW(this->win->getWindow()));
int color = dlg->getSelectedColor();
if (color == -2)
{
dlg->showColorchooser();
color = dlg->getSelectedColor();
}
if (color != -1)
{
p->setBackgroundColor(color);
firePageChanged(pNr);
settings->setPageBackgroundColor(color);
}
delete dlg;
}
void Control::deleteCurrentLayer()
{
XOJ_CHECK_TYPE(Control);
clearSelectionEndText();
PageRef p = getCurrentPage();
int pId = getCurrentPageNo();
if (!p.isValid())
{
return;
}
int lId = p->getSelectedLayerId();
if (lId < 1)
{
return;
}
Layer* l = p->getSelectedLayer();
p->removeLayer(l);
if (win)
{
win->getXournal()->layerChanged(pId);
win->updateLayerCombobox();
}
undoRedo->addUndoAction(new RemoveLayerUndoAction(p, l, lId - 1));
this->resetShapeRecognizer();
}
void Control::calcZoomFitSize()
{
XOJ_CHECK_TYPE(Control);
if (this->doc && this->win)
{
PageRef p = getCurrentPage();
if (!p.isValid())
{
return;
}
double width = p->getWidth() + 20;
GtkAllocation allocation = {0};
gtk_widget_get_allocation(win->getXournal()->getWidget(), &allocation);
double factor = ((double) allocation.width) / width;
zoom->setZoomFit(factor);
}
}
void Control::zoomFit()
{
XOJ_CHECK_TYPE(Control);
calcZoomFitSize();
zoom->zoomFit();
}
void Control::setViewTwoPages(bool twoPages)
{
XOJ_CHECK_TYPE(Control);
settings->setShowTwoPages(twoPages);
fireActionSelected(GROUP_TWOPAGES, twoPages ? ACTION_VIEW_TWO_PAGES : ACTION_NOT_SELECTED);
int currentPage = getCurrentPageNo();
win->getXournal()->layoutPages();
scrollHandler->scrollToPage(currentPage);
}
void Control::setViewPresentationMode(bool presentationMode)
{
XOJ_CHECK_TYPE(Control);
settings->setPresentationMode(presentationMode);
fireActionSelected(GROUP_PRESENTATION_MODE, presentationMode ? ACTION_VIEW_PRESENTATION_MODE : ACTION_NOT_SELECTED);
int currentPage = getCurrentPageNo();
win->getXournal()->layoutPages();
scrollHandler->scrollToPage(currentPage);
}
void Control::setPageInsertType(PageInsertType type)
{
XOJ_CHECK_TYPE(Control);
settings->setPageInsertType(type);
fireActionSelected(GROUP_PAGE_INSERT_TYPE, (ActionType) (type - PAGE_INSERT_TYPE_PLAIN + ACTION_NEW_PAGE_PLAIN));
}
bool Control::invokeCallback(CallbackData* cb)
{
gdk_threads_enter();
XOJ_CHECK_TYPE_OBJ(cb->control, Control);
ZoomControl* zoom = cb->control->getZoomControl();
switch (cb->type)
{
case ACTION_ZOOM_100:
zoom->zoom100();
break;
case ACTION_ZOOM_FIT:
cb->control->zoomFit();
break;
case ACTION_ZOOM_IN:
zoom->zoomIn();
break;
case ACTION_ZOOM_OUT:
zoom->zoomOut();
break;
}
delete cb;
gdk_threads_leave();
return false;
}
int Control::getCurrentPageNo()
{
XOJ_CHECK_TYPE(Control);
if (this->win)
{
return this->win->getXournal()->getCurrentPage();
}
return 0;
}
bool Control::searchTextOnPage(string text, int p, int* occures,
double* top)
{
XOJ_CHECK_TYPE(Control);
return getWindow()->getXournal()->searchTextOnPage(text, p, occures, top);
}
PageRef Control::getCurrentPage()
{
XOJ_CHECK_TYPE(Control);
int page = this->win->getXournal()->getCurrentPage();
this->doc->lock();
PageRef p = this->doc->getPage(page);
this->doc->unlock();
return p;
}
void Control::fileOpened(const char* uri)
{
XOJ_CHECK_TYPE(Control);
openFile(uri);
win->updateLayerCombobox();
}
void Control::undoRedoChanged()
{
XOJ_CHECK_TYPE(Control);
fireEnableAction(ACTION_UNDO, undoRedo->canUndo());
fireEnableAction(ACTION_REDO, undoRedo->canRedo());
win->setUndoDescription(undoRedo->undoDescription());
win->setRedoDescription(undoRedo->redoDescription());
updateWindowTitle();
}
void Control::undoRedoPageChanged(PageRef page)
{
XOJ_CHECK_TYPE(Control);
for (XojPage* p : this->changedPages)
{
if (p == (XojPage*) page)
{
return;
}
}
XojPage* p = (XojPage*) page;
this->changedPages.push_back(p);
p->reference();
}
void Control::selectTool(ToolType type)
{
XOJ_CHECK_TYPE(Control);
toolHandler->selectTool(type);
}
void Control::selectDefaultTool()
{
XOJ_CHECK_TYPE(Control);
ButtonConfig* cfg = settings->getDefaultButtonConfig();
cfg->acceptActions(toolHandler);
}
void Control::toolChanged()
{
XOJ_CHECK_TYPE(Control);
ToolType type = toolHandler->getToolType();
// Convert enum values, enums has to be in the same order!
ActionType at = (ActionType) (type - TOOL_PEN + ACTION_TOOL_PEN);
fireActionSelected(GROUP_TOOL, at);
fireEnableAction(ACTION_SELECT_COLOR, toolHandler->isEnableColor());
fireEnableAction(ACTION_SELECT_COLOR_CUSTOM, toolHandler->isEnableColor());
fireEnableAction(ACTION_RULER, toolHandler->isEnableRuler());
fireEnableAction(ACTION_TOOL_DRAW_RECT, toolHandler->isEnableRectangle());
fireEnableAction(ACTION_TOOL_DRAW_CIRCLE, toolHandler->isEnableCircle());
fireEnableAction(ACTION_TOOL_DRAW_ARROW, toolHandler->isEnableArrow());
fireEnableAction(ACTION_SHAPE_RECOGNIZER, toolHandler->isEnableShapreRecognizer());
bool enableSize = toolHandler->isEnableSize();
fireEnableAction(ACTION_SIZE_MEDIUM, enableSize);
fireEnableAction(ACTION_SIZE_THICK, enableSize);
fireEnableAction(ACTION_SIZE_FINE, enableSize);
fireEnableAction(ACTION_SIZE_VERY_THICK, enableSize);
fireEnableAction(ACTION_SIZE_VERY_THIN, enableSize);
if (enableSize)
{
toolSizeChanged();
}
// Update color
if (toolHandler->isEnableColor())
{
toolColorChanged();
}
fireActionSelected(GROUP_SHAPE_RECOGNIZER,
toolHandler->isShapeRecognizer() ? ACTION_SHAPE_RECOGNIZER : ACTION_NOT_SELECTED);
fireActionSelected(GROUP_RULER,
toolHandler->isRuler() ? ACTION_RULER : ACTION_NOT_SELECTED);
fireActionSelected(GROUP_RULER,
toolHandler->isRectangle() ? ACTION_TOOL_DRAW_RECT : ACTION_NOT_SELECTED);
fireActionSelected(GROUP_RULER,
toolHandler->isCircle() ? ACTION_TOOL_DRAW_CIRCLE : ACTION_NOT_SELECTED);
fireActionSelected(GROUP_RULER,
toolHandler->isArrow() ? ACTION_TOOL_DRAW_ARROW : ACTION_NOT_SELECTED);
getCursor()->updateCursor();
if (type != TOOL_TEXT)
{
if (win)
{
win->getXournal()->endTextAllPages();
}
}
}
void Control::eraserSizeChanged()
{
XOJ_CHECK_TYPE(Control);
switch (toolHandler->getEraserSize())
{
case TOOL_SIZE_FINE:
fireActionSelected(GROUP_ERASER_SIZE, ACTION_TOOL_ERASER_SIZE_FINE);
break;
case TOOL_SIZE_MEDIUM:
fireActionSelected(GROUP_ERASER_SIZE, ACTION_TOOL_ERASER_SIZE_MEDIUM);
break;
case TOOL_SIZE_THICK:
fireActionSelected(GROUP_ERASER_SIZE, ACTION_TOOL_ERASER_SIZE_THICK);
break;
}
}
void Control::penSizeChanged()
{
XOJ_CHECK_TYPE(Control);
switch (toolHandler->getPenSize())
{
case TOOL_SIZE_VERY_FINE:
fireActionSelected(GROUP_PEN_SIZE, ACTION_TOOL_PEN_SIZE_VERY_THIN);
break;
case TOOL_SIZE_FINE:
fireActionSelected(GROUP_PEN_SIZE, ACTION_TOOL_PEN_SIZE_FINE);
break;
case TOOL_SIZE_MEDIUM:
fireActionSelected(GROUP_PEN_SIZE, ACTION_TOOL_PEN_SIZE_MEDIUM);
break;
case TOOL_SIZE_THICK:
fireActionSelected(GROUP_PEN_SIZE, ACTION_TOOL_PEN_SIZE_THICK);
break;
case TOOL_SIZE_VERY_THICK:
fireActionSelected(GROUP_PEN_SIZE, ACTION_TOOL_PEN_SIZE_VERY_THICK);
break;
}
}
void Control::hilighterSizeChanged()
{
XOJ_CHECK_TYPE(Control);
switch (toolHandler->getHilighterSize())
{
case TOOL_SIZE_FINE:
fireActionSelected(GROUP_HILIGHTER_SIZE, ACTION_TOOL_HILIGHTER_SIZE_FINE);
break;
case TOOL_SIZE_MEDIUM:
fireActionSelected(GROUP_HILIGHTER_SIZE, ACTION_TOOL_HILIGHTER_SIZE_MEDIUM);
break;
case TOOL_SIZE_THICK:
fireActionSelected(GROUP_HILIGHTER_SIZE, ACTION_TOOL_HILIGHTER_SIZE_THICK);
break;
}
}
void Control::toolSizeChanged()
{
XOJ_CHECK_TYPE(Control);
if (toolHandler->getToolType() == TOOL_PEN)
{
penSizeChanged();
}
else if (toolHandler->getToolType() == TOOL_ERASER)
{
eraserSizeChanged();
}
else if (toolHandler->getToolType() == TOOL_HILIGHTER)
{
hilighterSizeChanged();
}
switch (toolHandler->getSize())
{
case TOOL_SIZE_NONE:
fireActionSelected(GROUP_SIZE, ACTION_NONE);
break;
case TOOL_SIZE_VERY_FINE:
fireActionSelected(GROUP_SIZE, ACTION_SIZE_VERY_THICK);
break;
case TOOL_SIZE_FINE:
fireActionSelected(GROUP_SIZE, ACTION_SIZE_FINE);
break;
case TOOL_SIZE_MEDIUM:
fireActionSelected(GROUP_SIZE, ACTION_SIZE_MEDIUM);
break;
case TOOL_SIZE_THICK:
fireActionSelected(GROUP_SIZE, ACTION_SIZE_THICK);
break;
case TOOL_SIZE_VERY_THICK:
fireActionSelected(GROUP_SIZE, ACTION_SIZE_VERY_THIN);
break;
}
}
void Control::toolColorChanged()
{
XOJ_CHECK_TYPE(Control);
fireActionSelected(GROUP_COLOR, ACTION_SELECT_COLOR);
getCursor()->updateCursor();
if (this->win && toolHandler->getColor() != -1)
{
EditSelection* sel = this->win->getXournal()->getSelection();
if (sel)
{
UndoAction* undo = sel->setColor(toolHandler->getColor());
undoRedo->addUndoAction(undo);
}
TextEditor* edit = getTextEditor();
if (this->toolHandler->getToolType() == TOOL_TEXT && edit != NULL)
{
UndoAction* undo = edit->setColor(toolHandler->getColor());
undoRedo->addUndoAction(undo);
}
}
}
void Control::setCustomColorSelected()
{
XOJ_CHECK_TYPE(Control);
fireActionSelected(GROUP_COLOR, ACTION_SELECT_COLOR_CUSTOM);
}
void Control::showSettings()
{
XOJ_CHECK_TYPE(Control);
bool xeventEnabled = settings->isUseXInput();
int selectionColor = settings->getSelectionColor();
bool verticalSpace = settings->getAddVerticalSpace();
bool horizontalSpace = settings->getAddHorizontalSpace();
bool bigCursor = settings->isShowBigCursor();
SettingsDialog* dlg = new SettingsDialog(this->gladeSearchPath, settings);
dlg->show(GTK_WINDOW(this->win->getWindow()));
if (xeventEnabled != settings->isUseXInput())
{
win->getXournal()->updateXEvents();
}
if (selectionColor != settings->getSelectionColor())
{
win->getXournal()->forceUpdatePagenumbers();
}
if (verticalSpace != settings->getAddVerticalSpace() || horizontalSpace != settings->getAddHorizontalSpace())
{
int currentPage = getCurrentPageNo();
win->getXournal()->layoutPages();
scrollHandler->scrollToPage(currentPage);
}
if (bigCursor != settings->isShowBigCursor())
{
getCursor()->updateCursor();
}
win->updateScrollbarSidebarPosition();
enableAutosave(settings->isAutosaveEnabled());
this->zoom->setZoom100(settings->getDisplayDpi() / 72.0);
delete dlg;
}
bool Control::newFile()
{
XOJ_CHECK_TYPE(Control);
if (!this->close())
{
return false;
}
Document newDoc(this);
this->doc->lock();
*doc = newDoc;
this->doc->unlock();
//CPPCHECK what is type assigment for?
PageInsertType type = settings->getPageInsertType();
if (type != PAGE_INSERT_TYPE_PLAIN && type != PAGE_INSERT_TYPE_LINED &&
type != PAGE_INSERT_TYPE_RULED && type != PAGE_INSERT_TYPE_GRAPH)
{
type = PAGE_INSERT_TYPE_LINED;
}
addDefaultPage();
fireDocumentChanged(DOCUMENT_CHANGE_COMPLETE);
fileLoaded();
return true;
}
bool Control::openFile(path filename, int scrollToPage)
{
XOJ_CHECK_TYPE(Control);
if (!this->close())
{
return false;
}
if (filename.empty())
{
bool attachPdf = false;
filename = XojOpenDlg::showOpenDialog((GtkWindow*) *win, this->settings, false, attachPdf);
cout << _F("Filename: {1}") % filename.string() << endl;
if (filename.empty())
{
return false;
}
}
LoadHandler h;
if (filename.extension() == ".pdf")
{
if (settings->isAutloadPdfXoj())
{
path f = path(filename).replace_extension(".pdf.xoj");
Document* tmp = h.loadDocument(f.string());
if (tmp)
{
this->doc->lock();
this->doc->clearDocument();
*this->doc = *tmp;
this->doc->unlock();
fileLoaded(scrollToPage);
return true;
}
else
{
return false;
}
}
bool an = annotatePdf(filename, false, false);
fileLoaded(scrollToPage);
return an;
}
Document* tmp = h.loadDocument(filename.string());
if ((tmp != NULL && h.isAttachedPdfMissing()) || !h.getMissingPdfFilename().empty())
{
// give the user a second chance to select a new PDF file, or to discard the PDF
GtkWidget* dialog = gtk_message_dialog_new((GtkWindow*) *getWindow(),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
h.isAttachedPdfMissing()
? _C("The attached background PDF could not be found.")
: _C("The background PDF could not be found."));
gtk_dialog_add_button(GTK_DIALOG(dialog), _C("Select another PDF"), 1);
gtk_dialog_add_button(GTK_DIALOG(dialog), _C("Remove PDF Background"), 2);
gtk_dialog_add_button(GTK_DIALOG(dialog), _C("Cancel"), 3);
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(this->getWindow()->getWindow()));
int res = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
if (res == 2) // remove PDF background
{
h.removePdfBackground();
tmp = h.loadDocument(filename.string());
}
else if (res == 1) // select another PDF background
{
bool attachToDocument = false;
path pdfFilename = XojOpenDlg::showOpenDialog((GtkWindow*) *win, this->settings, true, attachToDocument);
if (!pdfFilename.empty())
{
h.setPdfReplacement(pdfFilename.string(), attachToDocument);
tmp = h.loadDocument(filename.string());
}
}
}
if (!tmp)
{
GtkWidget* dialog = gtk_message_dialog_new((GtkWindow*) *win,
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK, "%s\n%s",
FC(_F("Error opening file \"{1}\"") % filename),
h.getLastError().c_str());
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(this->getWindow()->getWindow()));
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
fileLoaded(scrollToPage);
return false;
}
else
{
this->doc->lock();
this->doc->clearDocument();
*this->doc = *tmp;
this->doc->unlock();
}
fileLoaded(scrollToPage);
return true;
}
void Control::fileLoaded(int scrollToPage)
{
XOJ_CHECK_TYPE(Control);
this->doc->lock();
path file = this->doc->getEvMetadataFilename();
this->doc->unlock();
if (!file.empty())
{
double zoom = 1;
if (this->metadata->getDouble(file, "zoom", zoom))
{
this->zoom->setZoom(zoom);
}
else
{
this->zoom->zoomFit();
}
int scrollPageMetadata = 0;
if (scrollToPage >= 0)
{
scrollHandler->scrollToPage(scrollToPage);
}
else if (this->metadata->getInt(file, "page", scrollPageMetadata))
{
scrollHandler->scrollToPage(scrollPageMetadata);
}
recent->addRecentFileFilename(file);
}
else
{
this->zoom->zoomFit();
}
updateWindowTitle();
win->updateLayerCombobox();
win->getXournal()->forceUpdatePagenumbers();
getCursor()->updateCursor();
updateDeletePageButton();
}
bool Control::annotatePdf(path filename, bool attachPdf, bool attachToDocument)
{
XOJ_CHECK_TYPE(Control);
if (!this->close())
{
return false;
}
if (filename.empty())
{
filename = XojOpenDlg::showOpenDialog((GtkWindow*) *win, this->settings, true, attachToDocument);
if (filename.empty())
{
return false;
}
}
getCursor()->setCursorBusy(true);
bool res = this->doc->readPdf(filename, true, attachToDocument);
if (res)
{
int page = 0;
this->recent->addRecentFileFilename(filename.c_str());
this->doc->lock();
path file = this->doc->getEvMetadataFilename();
this->doc->unlock();
this->metadata->getInt(file, "page", page);
this->scrollHandler->scrollToPage(page);
}
else
{
this->doc->lock();
string errMsg = doc->getLastErrorMsg();
this->doc->unlock();
GtkWidget* dialog = gtk_message_dialog_new((GtkWindow*) *win,
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK, "%s",
FC(_F("Error annotate PDF file \"{1}\"\n{2}") % filename % errMsg));
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(this->getWindow()->getWindow()));
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
getCursor()->setCursorBusy(false);
fireDocumentChanged(DOCUMENT_CHANGE_COMPLETE);
getCursor()->updateCursor();
return true;
}
void Control::print()
{
XOJ_CHECK_TYPE(Control);
PrintHandler print;
this->doc->lock();
print.print(this->doc, getCurrentPageNo());
this->doc->unlock();
}
void Control::block(string name)
{
XOJ_CHECK_TYPE(Control);
if (this->isBlocking)
{
return;
}
// Disable all gui Control, to get full control over the application
win->setControlTmpDisabled(true);
getCursor()->setCursorBusy(true);
disableSidebarTmp(true);
this->statusbar = this->win->get("statusbar");
this->lbState = GTK_LABEL(this->win->get("lbState"));
this->pgState = GTK_PROGRESS_BAR(this->win->get("pgState"));
gtk_label_set_text(this->lbState, name.c_str());
gtk_widget_show(this->statusbar);
this->maxState = 100;
this->isBlocking = true;
}
void Control::unblock()
{
XOJ_CHECK_TYPE(Control);
if (!this->isBlocking)
{
return;
}
this->win->setControlTmpDisabled(false);
getCursor()->setCursorBusy(false);
disableSidebarTmp(false);
gtk_widget_hide(this->statusbar);
this->isBlocking = false;
}
void Control::setMaximumState(int max)
{
XOJ_CHECK_TYPE(Control);
this->maxState = max;
}
void Control::setCurrentState(int state)
{
XOJ_CHECK_TYPE(Control);
gdk_threads_enter();
gtk_progress_bar_set_fraction(this->pgState, gdouble(state) / this->maxState);
gdk_threads_leave();
}
bool Control::save(bool synchron)
{
XOJ_CHECK_TYPE(Control);
this->doc->lock();
path filename = this->doc->getFilename();
this->doc->unlock();
if (filename.empty())
{
if (!showSaveDialog())
{
return false;
}
}
SaveJob* job = new SaveJob(this);
bool result = true;
if (synchron)
{
result = job->save();
unblock();
}
else
{
this->scheduler->addJob(job, JOB_PRIORITY_URGENT);
}
job->unref();
return result;
}
bool Control::showSaveDialog()
{
XOJ_CHECK_TYPE(Control);
GtkWidget* dialog = gtk_file_chooser_dialog_new(_C("Save File"),
(GtkWindow*) *win, GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE,
GTK_RESPONSE_OK, NULL);
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dialog), true);
GtkFileFilter* filterXoj = gtk_file_filter_new();
gtk_file_filter_set_name(filterXoj, _C("Xournal files"));
gtk_file_filter_add_pattern(filterXoj, "*.xoj");
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filterXoj);
if (!settings->getLastSavePath().empty())
{
gtk_file_chooser_set_current_folder_uri(GTK_FILE_CHOOSER(dialog), settings->getLastSavePath().c_str());
}
string saveFilename = "";
this->doc->lock();
if (!doc->getFilename().empty())
{
saveFilename = doc->getFilename().filename().string();
}
else if (!doc->getPdfFilename().empty())
{
saveFilename = doc->getPdfFilename().filename().replace_extension(".pdf.xoj").string();
}
else
{
time_t curtime = time(NULL);
char stime[128];
strftime(stime, sizeof(stime), settings->getDefaultSaveName().c_str(), localtime(&curtime));
saveFilename = stime;
}
this->doc->unlock();
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), saveFilename.c_str());
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), true);
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(this->getWindow()->getWindow()));
if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK)
{
gtk_widget_destroy(dialog);
return false;
}
char* name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
string filename = name;
char* folder = gtk_file_chooser_get_current_folder_uri(GTK_FILE_CHOOSER(dialog));
settings->setLastSavePath(folder);
g_free(folder);
g_free(name);
gtk_widget_destroy(dialog);
this->doc->lock();
this->metadata->copy(this->doc->getFilename().string(), filename);
this->metadata->save();
this->doc->setFilename(path(filename));
this->doc->unlock();
return true;
}
void Control::updateWindowTitle()
{
XOJ_CHECK_TYPE(Control);
string title = "";
this->doc->lock();
if (doc->getFilename().empty())
{
if (doc->getPdfFilename().empty())
{
title = _("Unsaved Document");
}
else
{
if (undoRedo->isChanged())
{
title += "*";
}
title += doc->getPdfFilename().string();
}
}
else
{
if (undoRedo->isChanged())
{
title += "*";
}
title += doc->getFilename().filename().string();
}
this->doc->unlock();
title += " - Xournal++";
gtk_window_set_title((GtkWindow*) *win, title.c_str());
}
void Control::exportAsPdf()
{
XOJ_CHECK_TYPE(Control);
PdfExportJob* job = new PdfExportJob(this);
if (job->showFilechooser())
{
this->scheduler->addJob(job, JOB_PRIORITY_NONE);
}
else
{
// The job blocked, so we have to unblock, because the job unblocks only after run
unblock();
}
job->unref();
}
void Control::exportAs()
{
XOJ_CHECK_TYPE(Control);
ExportHandler handler;
handler.runExportWithDialog(this->gladeSearchPath, this->settings, this->doc, this, getCurrentPageNo());
}
bool Control::saveAs()
{
XOJ_CHECK_TYPE(Control);
if (!showSaveDialog())
{
return false;
}
this->doc->lock();
path filename = doc->getFilename();
this->doc->unlock();
if (filename.empty())
{
return false;
}
// no lock needed, this is an uncritical operation
this->doc->setCreateBackupOnSave(false);
return save();
}
void Control::quit()
{
XOJ_CHECK_TYPE(Control);
if (!this->close(true))
{
return;
}
this->scheduler->lock();
settings->save();
this->scheduler->removeAllJobs();
this->scheduler->unlock();
gtk_main_quit();
}
bool Control::close(bool destroy)
{
XOJ_CHECK_TYPE(Control);
clearSelectionEndText();
if (undoRedo->isChanged())
{
GtkWidget* dialog = gtk_message_dialog_new((GtkWindow*) *getWindow(), GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, "%s",
_C("This document is not saved yet."));
gtk_dialog_add_button(GTK_DIALOG(dialog), _C("Save"), 1);
gtk_dialog_add_button(GTK_DIALOG(dialog), _C("Discard"), 2);
gtk_dialog_add_button(GTK_DIALOG(dialog), _C("Cancel"), 3);
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(this->getWindow()->getWindow()));
int resNotSaved = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
// save
if (resNotSaved == 1)
{
if (this->save(true))
{
return true;
}
else
{
// if not saved cancel, else close
return false;
}
}
// cancel or closed
if (resNotSaved != 2) // 2 = discard
{
return false;
}
}
if (!doc->getFilename().empty())
{
namespace bf = boost::filesystem;
if (!bf::exists(this->doc->getFilename()))
{
GtkWidget* dialog = gtk_message_dialog_new((GtkWindow*) *getWindow(), GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, "%s",
_C("Document file was removed."));
gtk_dialog_add_button(GTK_DIALOG(dialog), _C("Save As"), 1);
gtk_dialog_add_button(GTK_DIALOG(dialog), _C("Discard"), 2);
gtk_dialog_add_button(GTK_DIALOG(dialog), _C("Cancel"), 3);
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(this->getWindow()->getWindow()));
int resDocRemoved = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
if (resDocRemoved == 1)
{
if (this->saveAs())
{
return true;
}
else
{
// if not saved cancel, else close
return false;
}
}
// cancel or closed
if (resDocRemoved != 2) // 2 = discard
{
return false;
}
}
}
undoRedo->clearContents();
this->doc->lock();
this->doc->clearDocument(destroy);
this->doc->unlock();
//updateWindowTitle();
undoRedoChanged();
return true;
}
void Control::resetShapeRecognizer()
{
XOJ_CHECK_TYPE(Control);
if (this->win)
{
this->win->getXournal()->resetShapeRecognizer();
}
}
void Control::showAbout()
{
XOJ_CHECK_TYPE(Control);
AboutDialog dlg(this->gladeSearchPath);
dlg.show(GTK_WINDOW(this->win->getWindow()));
}
void Control::clipboardCutCopyEnabled(bool enabled)
{
XOJ_CHECK_TYPE(Control);
fireEnableAction(ACTION_CUT, enabled);
fireEnableAction(ACTION_COPY, enabled);
}
void Control::clipboardPasteEnabled(bool enabled)
{
XOJ_CHECK_TYPE(Control);
fireEnableAction(ACTION_PASTE, enabled);
}
void Control::clipboardPasteText(string text)
{
XOJ_CHECK_TYPE(Control);
Text* t = new Text();
t->setText(text);
t->setFont(settings->getFont());
t->setColor(toolHandler->getColor());
clipboardPaste(t);
}
void Control::clipboardPasteImage(GdkPixbuf* img)
{
XOJ_CHECK_TYPE(Control);
Image* image = new Image();
image->setImage(img);
int width = gdk_pixbuf_get_width(img);
int height = gdk_pixbuf_get_height(img);
image->setWidth(width);
image->setHeight(height);
clipboardPaste(image);
}
void Control::clipboardPasteTex(GdkPixbuf* img, const char* text, int textLength)
{
XOJ_CHECK_TYPE(Control);
TexImage* image = new TexImage();
image->setImage(img);
int width = gdk_pixbuf_get_width(img);
int height = gdk_pixbuf_get_height(img);
image->setWidth(width);
image->setHeight(height);
image->setText(string(text, textLength));
clipboardPaste(image);
}
void Control::clipboardPaste(Element* e)
{
XOJ_CHECK_TYPE(Control);
double x = 0;
double y = 0;
int pageNr = getCurrentPageNo();
if (pageNr == -1)
{
return;
}
PageView* view = win->getXournal()->getViewFor(pageNr);
if (view == NULL)
{
return;
}
this->doc->lock();
PageRef page = this->doc->getPage(pageNr);
Layer* layer = page->getSelectedLayer();
win->getXournal()->getPasteTarget(x, y);
double width = e->getElementWidth();
double height = e->getElementHeight();
e->setX(x - width / 2);
e->setY(y - height / 2);
layer->addElement(e);
this->doc->unlock();
undoRedo->addUndoAction(new InsertUndoAction(page, layer, e));
EditSelection* selection = new EditSelection(this->undoRedo, e, view, page);
win->getXournal()->setSelection(selection);
}
void Control::clipboardPasteXournal(ObjectInputStream& in)
{
XOJ_CHECK_TYPE(Control);
int pNr = getCurrentPageNo();
if (pNr == -1 && win != NULL)
{
return;
}
this->doc->lock();
PageRef page = this->doc->getPage(pNr);
Layer* layer = page->getSelectedLayer();
PageView* view = win->getXournal()->getViewFor(pNr);
if (!view || !page)
{
this->doc->unlock();
return;
}
EditSelection* selection = NULL;
Element* element = NULL;
try
{
string version = in.readString();
if (version != PROJECT_STRING)
{
g_warning("Paste from Xournal Version %s to Xournal Version %s", version.c_str(), PROJECT_STRING);
}
selection = new EditSelection(this->undoRedo, page, view);
in >> selection;
// document lock not needed anymore, because we don't change the document, we only change the selection
this->doc->unlock();
int count = in.readInt();
AddUndoAction* pasteAddUndoAction = new AddUndoAction(page, false);
//this will undo a group of elements that are inserted
for (int i = 0; i < count; i++)
{
string name = in.getNextObjectName();
element = NULL;
if (name == "Stroke")
{
element = new Stroke();
}
else if (name == "Image")
{
element = new Image();
}
else if (name == "TexImage")
{
element = new TexImage();
}
else if (name == "Text")
{
element = new Text();
}
else
{
throw INPUT_STREAM_EXCEPTION("Get unknown object {1}", name);
}
in >> element;
//undoRedo->addUndoAction(new InsertUndoAction(page, layer, element, view));
pasteAddUndoAction->addElement(layer, element, layer->indexOf(element));
selection->addElement(element);
element = NULL;
}
undoRedo->addUndoAction(pasteAddUndoAction);
win->getXournal()->setSelection(selection);
}
catch (std::exception& e)
{
g_warning("could not paste, Exception occurred: %s", e.what());
Stacktrace::printStracktrace();
// cleanup
if (element)
{
delete element;
}
if (selection)
{
for (Element* e : *selection->getElements()) delete e;
delete selection;
}
}
}
void Control::deleteSelection()
{
XOJ_CHECK_TYPE(Control);
if (win)
{
win->getXournal()->deleteSelection();
}
}
void Control::clearSelection()
{
XOJ_CHECK_TYPE(Control);
if (this->win)
{
this->win->getXournal()->clearSelection();
}
}
void Control::setClipboardHandlerSelection(EditSelection* selection)
{
XOJ_CHECK_TYPE(Control);
if (this->clipboardHandler)
{
this->clipboardHandler->setSelection(selection);
}
}
void Control::setCopyPasteEnabled(bool enabled)
{
XOJ_CHECK_TYPE(Control);
this->clipboardHandler->setCopyPasteEnabled(enabled);
}
void Control::setToolSize(ToolSize size)
{
XOJ_CHECK_TYPE(Control);
EditSelection* sel = NULL;
if (this->win)
{
sel = this->win->getXournal()->getSelection();
}
if (sel)
{
UndoAction* undo = sel->setSize(size, toolHandler->getToolThickness(TOOL_PEN),
toolHandler->getToolThickness(TOOL_HILIGHTER),
toolHandler->getToolThickness(TOOL_ERASER));
if (undo)
{
undoRedo->addUndoAction(undo);
}
}
this->toolHandler->setSize(size);
}
void Control::fontChanged()
{
XOJ_CHECK_TYPE(Control);
XojFont font = win->getFontButtonFont();
settings->setFont(font);
EditSelection* sel = NULL;
if (this->win)
{
sel = this->win->getXournal()->getSelection();
}
if (sel)
{
UndoAction* undo = sel->setFont(font);
if (undo)
{
undoRedo->addUndoAction(undo);
}
}
TextEditor* editor = getTextEditor();
if (editor)
{
editor->setFont(font);
}
}
//The core handler for inserting latex
void Control::runLatex()
{
XOJ_CHECK_TYPE(Control);
#ifdef ENABLE_MATHTEX
this->doc->lock();
int pageNr = getCurrentPageNo();
if (pageNr == -1)
{
return;
}
PageView* view = win->getXournal()->getViewFor(pageNr);
if (view == NULL)
{
return;
}
//we get the selection
PageRef page = this->doc->getPage(pageNr);
Layer* layer = page->getSelectedLayer();
TexImage* img = view->getSelectedTex();
double imgx = 10;
double imgy = 10;
double imgheight = 0;
double imgwidth = 0;
string imgTex;
if (img)
{
//this will get the position of the Latex properly
EditSelection* theSelection = win->getXournal()->getSelection();
//imgx = img->getX();
//imgy = img->getY();
imgx = theSelection->getXOnView();
imgy = theSelection->getYOnView();
imgheight = img->getElementHeight();
imgwidth = img->getElementWidth();
//fix this typecast:
imgTex = img->getText();
}
//now call the image handlers
this->doc->unlock();
//need to do this otherwise we can't remove the image for its replacement
clearSelectionEndText();
LatexGlade* mytex = new LatexGlade(this->gladeSearchPath);
//determine if we should set a specific string
mytex->setTex(imgTex);
mytex->show(GTK_WINDOW(this->win->getWindow()));
string tmp = mytex->getTex();
delete mytex;
cout << tmp << endl;
if (tmp.empty())
{
return;
}
if (img)
{
layer->removeElement((Element*) img, false);
view->rerenderElement(img);
delete img;
img = NULL;
}
//now do all the LatexAction stuff
LatexAction texAction(tmp, imgheight * imgwidth);
texAction.runCommand();
this->doc->lock();
GFile* mygfile = g_file_new_for_path(texAction.getFileName().c_str());
cout << "About to insert image...";
GError* err = NULL;
GFileInputStream* in = g_file_read(mygfile, NULL, &err);
g_object_unref(mygfile);
if (err)
{
this->doc->unlock();
cerr << _F("Could not retrieve LaTeX image file: {1}") % err->message << endl;
g_error_free(err);
return;
}
GdkPixbuf* pixbuf = NULL;
pixbuf = gdk_pixbuf_new_from_stream(G_INPUT_STREAM(in), NULL, &err);
g_input_stream_close(G_INPUT_STREAM(in), NULL, NULL);
img = new TexImage();
img->setX(imgx);
img->setY(imgy);
img->setImage(pixbuf);
img->setText(tmp);
if (imgheight)
{
double ratio = gdk_pixbuf_get_width(pixbuf) / gdk_pixbuf_get_height(pixbuf);
if (ratio == 0)
{
if (imgwidth == 0)
{
img->setWidth(10);
}
else
{
img->setWidth(imgwidth);
}
}
else
{
img->setWidth(imgheight * ratio);
}
img->setHeight(imgheight);
}
else
{
img->setWidth(gdk_pixbuf_get_width(pixbuf));
img->setHeight(gdk_pixbuf_get_height(pixbuf));
}
layer->addElement(img);
view->rerenderElement(img);
cout << "Image inserted!" << endl;
this->doc->unlock();
undoRedo->addUndoAction(new InsertUndoAction(page, layer, img));
#else
cout << "Mathtex is disabled. Recompile with ./configure --enable-mathtex, "
"ensuring you have the mathtex command on your system." << endl;
#endif // ENABLE_MATHTEX
}
/**
* GETTER / SETTER
*/
UndoRedoHandler* Control::getUndoRedoHandler()
{
XOJ_CHECK_TYPE(Control);
return this->undoRedo;
}
ZoomControl* Control::getZoomControl()
{
XOJ_CHECK_TYPE(Control);
return this->zoom;
}
Cursor* Control::getCursor()
{
XOJ_CHECK_TYPE(Control);
return this->cursor;
}
RecentManager* Control::getRecentManager()
{
XOJ_CHECK_TYPE(Control);
return this->recent;
}
Document* Control::getDocument()
{
XOJ_CHECK_TYPE(Control);
return this->doc;
}
ToolHandler* Control::getToolHandler()
{
XOJ_CHECK_TYPE(Control);
return this->toolHandler;
}
XournalScheduler* Control::getScheduler()
{
XOJ_CHECK_TYPE(Control);
return this->scheduler;
}
MainWindow* Control::getWindow()
{
XOJ_CHECK_TYPE(Control);
return this->win;
}
bool Control::isFullscreen()
{
XOJ_CHECK_TYPE(Control);
return this->fullscreen;
}
TextEditor* Control::getTextEditor()
{
XOJ_CHECK_TYPE(Control);
if (this->win)
{
return this->win->getXournal()->getTextEditor();
}
return NULL;
}
GladeSearchpath* Control::getGladeSearchPath()
{
XOJ_CHECK_TYPE(Control);
return this->gladeSearchPath;
}
Settings* Control::getSettings()
{
XOJ_CHECK_TYPE(Control);
return settings;
}
ScrollHandler* Control::getScrollHandler()
{
XOJ_CHECK_TYPE(Control);
return this->scrollHandler;
}
MetadataManager* Control::getMetadataManager()
{
XOJ_CHECK_TYPE(Control);
return this->metadata;
}
Sidebar* Control::getSidebar()
{
XOJ_CHECK_TYPE(Control);
return this->sidebar;
}