From c57770233909ae5a02847bdbd94c08a448e86d02 Mon Sep 17 00:00:00 2001 From: Matteo Galletta Date: Sun, 1 Oct 2023 11:47:02 +0200 Subject: [PATCH 1/2] Workspace sidebar --- .../control/workspace/WorkspaceHandler.cpp | 99 ++++++++++ src/core/control/workspace/WorkspaceHandler.h | 45 +++++ .../workspace/WorkspaceHandlerListener.cpp | 10 + .../workspace/WorkspaceHandlerListener.h | 31 ++++ src/core/gui/Workspace.cpp | 172 ++++++++++++++++++ src/core/gui/Workspace.h | 64 +++++++ 6 files changed, 421 insertions(+) create mode 100644 src/core/control/workspace/WorkspaceHandler.cpp create mode 100644 src/core/control/workspace/WorkspaceHandler.h create mode 100644 src/core/control/workspace/WorkspaceHandlerListener.cpp create mode 100644 src/core/control/workspace/WorkspaceHandlerListener.h create mode 100644 src/core/gui/Workspace.cpp create mode 100644 src/core/gui/Workspace.h diff --git a/src/core/control/workspace/WorkspaceHandler.cpp b/src/core/control/workspace/WorkspaceHandler.cpp new file mode 100644 index 000000000000..69cf091bd2f9 --- /dev/null +++ b/src/core/control/workspace/WorkspaceHandler.cpp @@ -0,0 +1,99 @@ +#include +#include +#include +#include // for __shared_ptr_access, make... +#include // for move +#include // for vector + +#include "WorkspaceHandler.h" +#include "WorkspaceHandlerListener.h" + +WorkspaceHandler::WorkspaceHandler(fs::path filepath): filepath(filepath) {} + +WorkspaceHandler::~WorkspaceHandler() { + this->removeAllListeners(); +} + +void WorkspaceHandler::addListener(WorkspaceHandlerListener* listener) { this->listeners.emplace_back(listener); } + +void WorkspaceHandler::removeAllListeners() { this->listeners.clear(); } + +bool WorkspaceHandler::addFolder(fs::path folderPath) { + + if (!fs::is_directory(folderPath)) { + g_warning("The added workspace folder path %s does not exist", folderPath.c_str()); + return false; + } + + if (foldersPaths.find(folderPath) != foldersPaths.end()) { + g_info("The added workspace folder path %s is already added", folderPath.c_str()); + return false; + } + + foldersPaths.insert(folderPath); + for (const auto& listener: this->listeners) listener->addFolder(folderPath); + + save(); + return true; +} + +void WorkspaceHandler::closeAllFolders() { + + foldersPaths.clear(); + for (const auto &listener: this->listeners) listener->closeAllFolders(); + + save(); +} + +void WorkspaceHandler::load() { + if (!fs::exists(filepath)) { + g_warning("Workspace file %s does not exist. Regenerating.", filepath.string().c_str()); + save(); + return; + } + + std::ifstream file(filepath); + if (!file.is_open()) { + g_warning("Cannot open workspace file %s.", filepath.string().c_str()); + return; + } + + bool dirtyFile = false; + while (file) { + std::string line; + std::getline(file, line); + + if (line.empty()) + continue; + + fs::path filePath = fs::path(line); + if (fs::exists(filePath) && fs::is_directory(filePath)) { + foldersPaths.insert(filePath); + addFolder(filePath); + } + else { + g_warning("The workspace file contains an inexisting/invalid path %s", line.c_str()); + dirtyFile = true; + } + } + + file.close(); + if (dirtyFile) + save(); +} + +void WorkspaceHandler::save() { + std::ofstream file(filepath); + + for (const auto& path: foldersPaths) + file << path.generic_string() << std::endl; + + file.close(); +} + +std::set WorkspaceHandler::getFoldersPaths() { + return foldersPaths; +} +int WorkspaceHandler::getFoldersCount() { + return foldersPaths.size(); +} \ No newline at end of file diff --git a/src/core/control/workspace/WorkspaceHandler.h b/src/core/control/workspace/WorkspaceHandler.h new file mode 100644 index 000000000000..ff4e001358af --- /dev/null +++ b/src/core/control/workspace/WorkspaceHandler.h @@ -0,0 +1,45 @@ +/* + * Xournal++ + * + * A tool + * + * @author Xournal++ Team + * https://github.com/xournalpp/xournalpp + * + * @license GNU GPLv2 or later + */ + +#pragma once + +#include +#include +#include + +class WorkspaceHandlerListener; + +class WorkspaceHandler { +public: + + WorkspaceHandler(fs::path filepath); + ~WorkspaceHandler(); + +public: + void addListener(WorkspaceHandlerListener* listener); + void removeAllListeners(); + + bool addFolder(fs::path folderPath); + void closeAllFolders(); + +public: + void load(); + void save(); + + std::set getFoldersPaths(); + int getFoldersCount(); + +private: + fs::path filepath; + std::vector listeners; + std::set foldersPaths; + +}; diff --git a/src/core/control/workspace/WorkspaceHandlerListener.cpp b/src/core/control/workspace/WorkspaceHandlerListener.cpp new file mode 100644 index 000000000000..fddd9fcfc89b --- /dev/null +++ b/src/core/control/workspace/WorkspaceHandlerListener.cpp @@ -0,0 +1,10 @@ +#include "WorkspaceHandler.h" +#include "WorkspaceHandlerListener.h" + +WorkspaceHandlerListener::WorkspaceHandlerListener(): handler(nullptr) {} +WorkspaceHandlerListener::~WorkspaceHandlerListener() {} + +void WorkspaceHandlerListener::registerListener(WorkspaceHandler* handler) { + this->handler = handler; + handler->addListener(this); +} diff --git a/src/core/control/workspace/WorkspaceHandlerListener.h b/src/core/control/workspace/WorkspaceHandlerListener.h new file mode 100644 index 000000000000..803fa88b5e40 --- /dev/null +++ b/src/core/control/workspace/WorkspaceHandlerListener.h @@ -0,0 +1,31 @@ +/* + * Xournal++ + * + * Layer Controller listener + * + * @author Xournal++ Team + * https://github.com/xournalpp/xournalpp + * + * @license GNU GPLv2 or later + */ + +#pragma once + +#include + +class WorkspaceHandler; + +class WorkspaceHandlerListener { +public: + WorkspaceHandlerListener(); + virtual ~WorkspaceHandlerListener(); + +public: + void registerListener(WorkspaceHandler* handler); + + virtual void addFolder(fs::path folderPath) = 0; + virtual void closeAllFolders() = 0; + +private: + WorkspaceHandler* handler; +}; diff --git a/src/core/gui/Workspace.cpp b/src/core/gui/Workspace.cpp new file mode 100644 index 000000000000..71737e04d007 --- /dev/null +++ b/src/core/gui/Workspace.cpp @@ -0,0 +1,172 @@ +#include "Workspace.h" + +#include // for int64_t +#include // for std::make_unique and std::make_shared +#include +#include // for string + +#include +#include // for gdk_display_get... +#include // for G_CALLBACK, g_s... +#include // for gtk_toggle_tool_button_new... + +#include "control/Control.h" // for Control +#include "control/settings/Settings.h" // for Settings +#include "control/workspace/WorkspaceHandler.h" +#include "gui/GladeGui.h" // for GladeGui +#include "model/Document.h" // for Document +#include "model/XojPage.h" // for XojPage +#include "pdf/base/XojPdfPage.h" // for XojPdfPageSPtr +#include "util/Util.h" // for npos +#include "util/XojMsgBox.h" +#include "util/i18n.h" // for _, FC, _F + +enum +{ + COL_NAME = 0, + COL_FULLPATH, + NUM_COLS +}; + +Workspace::Workspace(GladeGui* gui, Control* control, WorkspaceHandler* workspaceHandler): + control(control), gui(gui), workspaceHandler(workspaceHandler) { + + this->workspaceSidebar = gui->get("workspaceSidebar"); + + //this->folderPath = "/home/teogalletta/Documents/my-obsidian-vault/100 university"; + this->createViewAndStore(); + + gtk_container_add(GTK_CONTAINER(this->workspaceSidebar), treeView); + + //gtk_viewport_set_shadow_type(GTK_VIEWPORT(gui->get("workspaceSidebarContainer")), GTK_SHADOW_IN); + + gtk_widget_show_all(this->workspaceSidebar); + + workspaceHandler->addListener(this); + for (const auto& path: workspaceHandler->getFoldersPaths()) + addFolder(path); +} + + +Workspace::~Workspace() {} + +void Workspace::fillTreeFromFolderPath(GtkTreeStore* store, GtkTreeIter* parent, std::string folderPath) { + + if (!fs::is_directory(fs::path(folderPath))) { + g_warning("The workspace folder path %s does not exist", folderPath.c_str()); + return; + } + + // to order the filenames + std::set entries; + for (const auto& entry : fs::directory_iterator(folderPath)) + entries.insert(entry); + + for (const auto& entry : entries) { + + fs::path entryPath = entry.path(); + fs::path entryFilename = entryPath.filename(); + + GtkTreeIter iter; + if (entry.is_directory() || entryPath.extension() == ".pdf" || entryPath.extension() == ".xopp") { + gtk_tree_store_append(store, &iter, parent); + gtk_tree_store_set(store, &iter, COL_NAME, entryFilename.generic_string().c_str(), COL_FULLPATH, entryPath.c_str(), -1); + } + + if (entry.is_directory()) { + fillTreeFromFolderPath(store, &iter, entryPath); + } + + } +} + +void Workspace::createViewAndStore() { + + treeView = gtk_tree_view_new(); + + g_signal_connect(treeView, "row-activated", G_CALLBACK(treeViewRowClicked), this); + + GtkCellRenderer* renderer; + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeView), -1, "Name", renderer, "text", 0, nullptr); + //g_signal_connect(renderer, "cell-data-func", G_CALLBACK(setRootFolderTextBold), nullptr); + + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeView), false); + + store = gtk_tree_store_new(NUM_COLS, G_TYPE_STRING, G_TYPE_STRING); + GtkTreeModel* model = GTK_TREE_MODEL(store); + gtk_tree_view_set_model(GTK_TREE_VIEW(treeView), model); + g_object_unref(model); +} + +auto Workspace::getControl() -> Control* { return this->control; } + +void Workspace::addFolder(fs::path folderPath) { + + GtkTreeIter iter; + gtk_tree_store_append(store, &iter, nullptr); + gtk_tree_store_set(store, &iter, COL_NAME, fs::path(folderPath).filename().c_str(), -1); + fillTreeFromFolderPath(store, &iter, folderPath); + + gtk_widget_show_all(GTK_WIDGET(workspaceSidebar)); +} + +void Workspace::removeFolder(fs::path folderPath) {} + +void Workspace::treeViewRowClicked(GtkTreeView* treeView, GtkTreePath* path, GtkTreeViewColumn* column, Workspace* workspace) { + + GtkTreeModel* model = gtk_tree_view_get_model(treeView); + + GtkTreeIter iter; + if (gtk_tree_model_get_iter(model, &iter, path)) { + gchar* str; + gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, COL_FULLPATH, &str, -1); + + fs::path fsPath; + if (str != nullptr) // root folder + fsPath = fs::path(std::string(str)); + + if (str == nullptr || fs::is_directory(fsPath)) { + bool wasExpanded = gtk_tree_view_row_expanded(treeView, path); + if (wasExpanded) + gtk_tree_view_collapse_row(treeView, path); + else + gtk_tree_view_expand_row(treeView, path, false); + } + else { + workspace->control->openFile(fsPath); + } + + g_free(str); + } + +} +/* +void Workspace::setRootFolderTextBold(GtkTreeViewColumn *column, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, void* _ptr) { + gchar* text; + gtk_tree_model_get(model, iter, COL_FULLPATH, &text, -1); + + if (text != nullptr) + return; + + // Creiamo una tag di stile Pango per il testo in grassetto + PangoAttrList* attrs = pango_attr_list_new(); + PangoAttribute* attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD); + pango_attr_list_insert(attrs, attr); + + // Impostiamo il testo nel renderer con il tag di stile Pango + g_object_set(renderer, "text", text, "attributes", attrs, nullptr); + + g_free(text); + pango_attr_list_unref(attrs); +}*/ + +void Workspace::saveSize() { + if (this->control->getSettings()->isWorkspaceVisible()) { + GtkAllocation alloc; + gtk_widget_get_allocation(this->workspaceSidebar, &alloc); + + this->control->getSettings()->setWorkspaceWidth(alloc.width); + } +} diff --git a/src/core/gui/Workspace.h b/src/core/gui/Workspace.h new file mode 100644 index 000000000000..c6c7c96e5efe --- /dev/null +++ b/src/core/gui/Workspace.h @@ -0,0 +1,64 @@ +/* + * Xournal++ + * + * The Sidebar + * + * @author Xournal++ Team + * https://github.com/xournalpp/xournalpp + * + * @license GNU GPLv2 or later + */ + +#pragma once + +#include // for string +#include // for size_t +#include // for unique_ptr +#include // for vector + +#include // for GtkWidget, Gtk... +#include "control/workspace/WorkspaceHandlerListener.h" + +class Control; +class GladeGui; +class WorkspaceHandler; + +class Workspace: + public WorkspaceHandlerListener { +public: + Workspace(GladeGui* gui, Control* control, WorkspaceHandler* workspaceHandler); + ~Workspace(); + + Control* getControl(); + +public: + void addFolder(fs::path folderPath); + void removeFolder(fs::path folderPath); + + void saveSize(); + +private: + void createViewAndStore(); + void fillTreeFromFolderPath(GtkTreeStore* store, GtkTreeIter* parent, std::string folderPath); + + static void treeViewRowClicked(GtkTreeView* self, GtkTreePath* path, GtkTreeViewColumn* column, Workspace* workspace); + + Control* control = nullptr; + + GladeGui* gui = nullptr; + + /** + * The workspaceSidebar widget + */ + GtkWidget* workspaceSidebar = nullptr; + + /** + * The GTK tree view widget + */ + GtkWidget* treeView = nullptr; + + WorkspaceHandler* workspaceHandler = nullptr; + + GtkTreeStore* store; +}; + From d6b7d5df081d36cac31f2d35e6764b860f0899af Mon Sep 17 00:00:00 2001 From: Matteo Galletta Date: Sun, 1 Oct 2023 11:47:02 +0200 Subject: [PATCH 2/2] Workspace sidebar --- CMakeLists.txt | 3 +- cmake/README.md | 1 + src/config-dev.h.in | 4 + src/core/control/Control.cpp | 46 +- src/core/control/Control.h | 16 +- src/core/control/settings/Settings.cpp | 34 + src/core/control/settings/Settings.h | 18 +- src/core/control/settings/ViewModes.cpp | 23 +- src/core/control/settings/ViewModes.h | 20 +- src/core/control/stockdlg/XojOpenDlg.cpp | 33 +- src/core/control/stockdlg/XojOpenDlg.h | 3 +- .../control/workspace/WorkspaceHandler.cpp | 5 +- src/core/control/workspace/WorkspaceHandler.h | 2 +- .../workspace/WorkspaceHandlerListener.h | 2 +- src/core/enums/ActionType.enum.h | 2 + .../enums/generated/ActionType.generated.cpp | 16 + src/core/gui/MainWindow.cpp | 49 + src/core/gui/MainWindow.h | 10 + src/core/gui/Workspace.cpp | 59 +- src/core/gui/Workspace.h | 13 +- src/core/gui/dialog/SettingsDialog.cpp | 6 + src/core/gui/sidebar/Sidebar.cpp | 8 +- .../gui/toolbarMenubar/ToolMenuHandler.cpp | 2 + ui/main.glade | 980 ++++++++++-------- ui/settings.glade | 30 + 25 files changed, 889 insertions(+), 496 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a9ca930e72e..cfc9cd572e56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -237,6 +237,7 @@ mark_as_advanced(FORCE ) # Advanced development config +set(DEV_WORKSPACE_FILE "workspaces.txt" CACHE STRING "Workspace folders list file name") set(DEV_TOOLBAR_CONFIG "toolbar.ini" CACHE STRING "Toolbar config file name") set(DEV_SETTINGS_XML_FILE "settings.xml" CACHE STRING "Settings file name") set(DEV_PALETTE_FILE "palette.gpl" CACHE STRING "Color Palette") @@ -253,7 +254,7 @@ endif () mark_as_advanced(FORCE DEV_TOOLBAR_CONFIG DEV_SETTINGS_XML_FILE DEV_PRINT_CONFIG_FILE DEV_METADATA_FILE - DEV_ENABLE_GCOV DEV_CHECK_GTK3_COMPAT + DEV_ENABLE_GCOV DEV_CHECK_GTK3_COMPAT DEV_WORKSPACE_FILE ) configure_file( diff --git a/cmake/README.md b/cmake/README.md index 2161bd427830..39e224196a2f 100644 --- a/cmake/README.md +++ b/cmake/README.md @@ -34,6 +34,7 @@ Here you can find complete list of Xournal++ CMake flags (sorted by categories). | `DEV_METADATA_MAX_ITEMS` *[A]* | 50 | Maximal amount of metadata elements | `DEV_PRINT_CONFIG_FILE` *[A]* | print-config.ini | Print config file name | `DEV_SETTINGS_XML_FILE` *[A]* | settings.xml | Settings file name +| `DEV_WORKSPACE_FILE` *[A]* | workspace.txt | Workspace folders list file name | `DEV_TOOLBAR_CONFIG` *[A]* | toolbar.ini | Toolbar config file name | `DEV_ERRORLOG_DIR` *[A]* | errorlogs | Directory where errorlogfiles will be placed diff --git a/src/config-dev.h.in b/src/config-dev.h.in index e3e9c4de08e6..94e393f1ff1d 100644 --- a/src/config-dev.h.in +++ b/src/config-dev.h.in @@ -21,6 +21,10 @@ */ #define SETTINGS_XML_FILE "@DEV_SETTINGS_XML_FILE@" +/** + * Workspace file name + */ +#define WORKSPACE_FILE "@DEV_WORKSPACE_FILE@" /** * Gimp Palette File */ diff --git a/src/core/control/Control.cpp b/src/core/control/Control.cpp index 6e70342f1c6c..43b9ad93e77a 100644 --- a/src/core/control/Control.cpp +++ b/src/core/control/Control.cpp @@ -42,6 +42,7 @@ #include "gui/PdfFloatingToolbox.h" // for PdfF... #include "gui/PopupWindowWrapper.h" // for PopupWindowWrapper #include "gui/SearchBar.h" // for Sear... +#include "gui/Workspace.h" // for Work... #include "gui/XournalView.h" // for Xour... #include "gui/XournalppCursor.h" // for Xour... #include "gui/dialog/AboutDialog.h" // for Abou... @@ -99,6 +100,7 @@ #include "view/CompassView.h" // for Comp... #include "view/SetsquareView.h" // for Sets... #include "view/overlays/OverlayView.h" // for Over... +#include "workspace/WorkspaceHandler.h" #include "CrashHandler.h" // for emer... #include "LatexController.h" // for Late... @@ -108,6 +110,7 @@ #include "config-dev.h" // for SETT... #include "config.h" // for PROJ... + using std::string; Control::Control(GApplication* gtkApp, GladeSearchpath* gladeSearchPath, bool disableAudio): gtkApp(gtkApp) { @@ -124,8 +127,12 @@ Control::Control(GApplication* gtkApp, GladeSearchpath* gladeSearchPath, bool di this->lastGroup = GROUP_NOGROUP; this->lastEnabled = false; - auto name = Util::getConfigFile(SETTINGS_XML_FILE); - this->settings = new Settings(std::move(name)); + auto workspaceFilepath = Util::getConfigFile(WORKSPACE_FILE); + this->workspaceHandler = new WorkspaceHandler(std::move(workspaceFilepath)); + this->workspaceHandler->load(); + + auto settingsFilepath = Util::getConfigFile(SETTINGS_XML_FILE); + this->settings = new Settings(std::move(settingsFilepath)); this->settings->load(); this->applyPreferredLanguage(); @@ -187,6 +194,10 @@ Control::~Control() { this->toolHandler = nullptr; delete this->sidebar; this->sidebar = nullptr; + delete this->workspaceHandler; + this->workspaceHandler = nullptr; + delete this->workspace; + this->workspace = nullptr; delete this->doc; this->doc = nullptr; delete this->searchBar; @@ -295,12 +306,14 @@ void Control::saveSettings() { this->settings->setMainWndMaximized(this->win->isMaximized()); this->sidebar->saveSize(); + this->workspace->saveSize(); } void Control::initWindow(MainWindow* win) { selectTool(toolHandler->getToolType()); this->win = win; this->sidebar = new Sidebar(win, this); + this->workspace = new Workspace(win, this, this->workspaceHandler); XojMsgBox::setDefaultWindow(getGtkWindow()); @@ -428,6 +441,12 @@ void Control::actionPerformed(ActionType type, ActionGroup group, GtkToolButton* case ACTION_OPEN: openFile(); break; + case ACTION_OPEN_FOLDER: + openFolder(); + break; + case ACTION_CLOSE_ALL_FOLDERS: + closeAllFolders(); + break; case ACTION_ANNOTATE_PDF: clearSelectionEndText(); annotatePdf("", false, false); @@ -2453,6 +2472,25 @@ auto Control::openFile(fs::path filepath, int scrollToPage, bool forceOpen) -> b return true; } +void Control::openFolder() { + + XojOpenDlg dlg(getGtkWindow(), this->settings, "Add folder to workspace"); + fs::path folderPath = dlg.showOpenFolderDialog(); + g_message("%s", (_F("folder: {1}") % folderPath.string()).c_str()); + + if (workspaceHandler->addFolder(std::move(folderPath))) { + win->setWorkspaceVisible(true); + } +} + +void Control::closeAllFolders(bool closeWorkspaceSidebar) { + + workspaceHandler->closeAllFolders(); + + if (closeWorkspaceSidebar) + win->setWorkspaceVisible(false); +} + auto Control::loadPdf(const fs::path& filepath, int scrollToPage) -> bool { LoadHandler loadHandler; @@ -2956,6 +2994,7 @@ auto Control::loadViewMode(ViewModeId mode) -> bool { this->win->setMenubarVisible(settings->isMenubarVisible()); this->win->setToolbarVisible(settings->isToolbarVisible()); this->win->setSidebarVisible(settings->isSidebarVisible()); + this->win->setWorkspaceVisible(settings->isWorkspaceVisible()); setFullscreen(settings->isFullscreen()); return false; } @@ -3320,6 +3359,9 @@ auto Control::getMetadataManager() const -> MetadataManager* { return this->meta auto Control::getSidebar() const -> Sidebar* { return this->sidebar; } +auto Control::getWorkspaceHandler() const -> WorkspaceHandler* { return this->workspaceHandler; } +auto Control::getWorkspace() const -> Workspace* { return this->workspace; } + auto Control::getSearchBar() const -> SearchBar* { return this->searchBar; } auto Control::getAudioController() const -> AudioController* { return this->audioController; } diff --git a/src/core/control/Control.h b/src/core/control/Control.h index 027b5c378512..f61acdc31698 100644 --- a/src/core/control/Control.h +++ b/src/core/control/Control.h @@ -11,11 +11,11 @@ #pragma once -#include // for size_t -#include // for unique_ptr +#include // for size_t +#include // for unique_ptr #include // for optional -#include // for string, allocator -#include // for vector +#include // for string, allocator +#include // for vector #include // for GdkPixbuf #include // for GApplication @@ -41,6 +41,8 @@ class GeometryToolController; class AudioController; class FullscreenHandler; +class WorkspaceHandler; +class Workspace; class Sidebar; class GladeSearchpath; class MetadataManager; @@ -90,6 +92,8 @@ class Control: // Menu File bool newFile(std::string pageTemplate = "", fs::path filepath = {}); bool openFile(fs::path filepath = "", int scrollToPage = -1, bool forceOpen = false); + void openFolder(); + void closeAllFolders(bool closeWorkspaceSidebar = true); bool annotatePdf(fs::path filepath, bool attachPdf, bool attachToDocument); void print(); void exportAsPdf(); @@ -264,6 +268,7 @@ class Control: MetadataManager* getMetadataManager() const; Settings* getSettings() const; + WorkspaceHandler* getWorkspaceHandler() const; ToolHandler* getToolHandler() const; ZoomControl* getZoomControl() const; Document* getDocument() const; @@ -275,6 +280,7 @@ class Control: size_t getCurrentPageNo() const; XournalppCursor* getCursor() const; Sidebar* getSidebar() const; + Workspace* getWorkspace() const; SearchBar* getSearchBar() const; AudioController* getAudioController() const; PageTypeHandler* getPageTypes() const; @@ -392,9 +398,11 @@ class Control: Document* doc = nullptr; + Workspace* workspace = nullptr; Sidebar* sidebar = nullptr; SearchBar* searchBar = nullptr; + WorkspaceHandler* workspaceHandler; ToolHandler* toolHandler; ActionType lastAction; diff --git a/src/core/control/settings/Settings.cpp b/src/core/control/settings/Settings.cpp index 8b84839060da..4c7f6bff51b6 100644 --- a/src/core/control/settings/Settings.cpp +++ b/src/core/control/settings/Settings.cpp @@ -92,6 +92,9 @@ void Settings::loadDefault() { this->sidebarWidth = 150; this->sidebarNumberingStyle = SidebarNumberingStyle::DEFAULT; + this->workspaceWidth = 200; + this->showWorkspace = false; + this->showToolbar = true; this->selectedToolbar = DEFAULT_TOOLBAR; @@ -246,6 +249,7 @@ auto Settings::loadViewMode(ViewModeId mode) -> bool { menubarVisible = viewMode.showMenubar; showToolbar = viewMode.showToolbar; showSidebar = viewMode.showSidebar; + showWorkspace = viewMode.showWorkspace; this->activeViewMode = mode; return true; } @@ -410,6 +414,10 @@ void Settings::parseItem(xmlDocPtr doc, xmlNodePtr cur) { this->maximized = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("showToolbar")) == 0) { this->showToolbar = xmlStrcmp(value, reinterpret_cast("true")) == 0; + } else if (xmlStrcmp(name, reinterpret_cast("showWorkspace")) == 0) { + this->showWorkspace = xmlStrcmp(value, reinterpret_cast("true")) == 0; + } else if (xmlStrcmp(name, reinterpret_cast("workspaceWidth")) == 0) { + this->workspaceWidth = std::max(g_ascii_strtoll(reinterpret_cast(value), nullptr, 10), 50); } else if (xmlStrcmp(name, reinterpret_cast("filepathShownInTitlebar")) == 0) { this->filepathShownInTitlebar = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("pageNumberShownInTitlebar")) == 0) { @@ -972,6 +980,9 @@ void Settings::save() { SAVE_BOOL_PROP(showToolbar); + SAVE_BOOL_PROP(showWorkspace); + SAVE_INT_PROP(workspaceWidth); + SAVE_BOOL_PROP(showSidebar); SAVE_INT_PROP(sidebarWidth); xmlNode = saveProperty("sidebarNumberingStyle", static_cast(sidebarNumberingStyle), root); @@ -1950,6 +1961,17 @@ void Settings::setSidebarVisible(bool visible) { save(); } +auto Settings::isWorkspaceVisible() const -> bool { return this->showWorkspace; } + +void Settings::setWorkspaceVisible(bool visible) { + if (this->showWorkspace == visible) { + return; + } + this->showWorkspace = visible; + save(); +} + + auto Settings::isToolbarVisible() const -> bool { return this->showToolbar; } void Settings::setToolbarVisible(bool visible) { @@ -1960,6 +1982,18 @@ void Settings::setToolbarVisible(bool visible) { save(); } +auto Settings::getWorkspaceWidth() const -> int { return this->workspaceWidth; } + +void Settings::setWorkspaceWidth(int width) { + width = std::max(width, 50); + + if (this->workspaceWidth == width) { + return; + } + this->workspaceWidth = width; + save(); +} + auto Settings::getSidebarWidth() const -> int { return this->sidebarWidth; } void Settings::setSidebarWidth(int width) { diff --git a/src/core/control/settings/Settings.h b/src/core/control/settings/Settings.h index 32dec42e5cd7..05a9e73102b4 100644 --- a/src/core/control/settings/Settings.h +++ b/src/core/control/settings/Settings.h @@ -216,9 +216,15 @@ class Settings { bool isSidebarVisible() const; void setSidebarVisible(bool visible); + bool isWorkspaceVisible() const; + void setWorkspaceVisible(bool visible); + bool isToolbarVisible() const; void setToolbarVisible(bool visible); + int getWorkspaceWidth() const; + void setWorkspaceWidth(int width); + int getSidebarWidth() const; void setSidebarWidth(int width); @@ -630,7 +636,17 @@ class Settings { bool showSidebar{}; /** - * If the sidebar is visible + * If the workspace sidebar is visible + */ + bool showWorkspace{}; + + /** + * The Width of the Workspace + */ + int workspaceWidth{}; + + /** + * If the toolbar is visible */ bool showToolbar{}; diff --git a/src/core/control/settings/ViewModes.cpp b/src/core/control/settings/ViewModes.cpp index acf5d7444415..5a67a01e644f 100644 --- a/src/core/control/settings/ViewModes.cpp +++ b/src/core/control/settings/ViewModes.cpp @@ -1,16 +1,18 @@ #include "ViewModes.h" -#include "util/StringUtils.h" #include +#include "util/StringUtils.h" + auto ViewMode::operator==(const ViewMode& other) const -> bool { return (this->goFullscreen == other.goFullscreen) && (this->showMenubar == other.showMenubar) && - (this->showToolbar == other.showToolbar) && (this->showSidebar == other.showSidebar); + (this->showToolbar == other.showToolbar) && (this->showSidebar == other.showSidebar) && + (this->showWorkspace == other.showWorkspace); } struct ViewMode settingsStringToViewMode(std::string viewModeString) { struct ViewMode viewMode; - for (const std::string& attr : StringUtils::split(viewModeString, ',')) { + for (const std::string& attr: StringUtils::split(viewModeString, ',')) { if (attr.compare(ATTR_GO_FULLSCREEN) == 0) { viewMode.goFullscreen = true; } else if (attr.compare(ATTR_SHOW_MENUBAR) == 0) { @@ -19,17 +21,22 @@ struct ViewMode settingsStringToViewMode(std::string viewModeString) { viewMode.showToolbar = true; } else if (attr.compare(ATTR_SHOW_SIDEBAR) == 0) { viewMode.showSidebar = true; + } else if (attr.compare(ATTR_SHOW_WORKSPACE) == 0) { + viewMode.showWorkspace = true; } } return viewMode; } const std::string viewModeToSettingsString(struct ViewMode viewMode) { - if (!(viewMode.goFullscreen || viewMode.showMenubar || viewMode.showToolbar || viewMode.showSidebar)) { + if (!(viewMode.goFullscreen || viewMode.showMenubar || viewMode.showToolbar || viewMode.showSidebar || + viewMode.showWorkspace)) { return ""; } - return ((viewMode.goFullscreen ? "," + static_cast(ATTR_GO_FULLSCREEN) : "") - + (viewMode.showMenubar ? "," + static_cast(ATTR_SHOW_MENUBAR) : "") - + (viewMode.showToolbar ? "," + static_cast(ATTR_SHOW_TOOLBAR) : "") - + (viewMode.showSidebar ? "," + static_cast(ATTR_SHOW_SIDEBAR) : "")).erase(0,1); + return ((viewMode.goFullscreen ? "," + static_cast(ATTR_GO_FULLSCREEN) : "") + + (viewMode.showMenubar ? "," + static_cast(ATTR_SHOW_MENUBAR) : "") + + (viewMode.showToolbar ? "," + static_cast(ATTR_SHOW_TOOLBAR) : "") + + (viewMode.showSidebar ? "," + static_cast(ATTR_SHOW_SIDEBAR) : "") + + (viewMode.showWorkspace ? "," + static_cast(ATTR_SHOW_WORKSPACE) : "")) + .erase(0, 1); } diff --git a/src/core/control/settings/ViewModes.h b/src/core/control/settings/ViewModes.h index 04360b7a774d..c4beb7196169 100644 --- a/src/core/control/settings/ViewModes.h +++ b/src/core/control/settings/ViewModes.h @@ -11,30 +11,28 @@ #pragma once -#include // for string -#include // for vector -#include // for unordered_map +#include // for string +#include // for unordered_map +#include // for vector using ViewModeId = size_t; // reserved default view mode ids -enum PresetViewModeIds { - VIEW_MODE_DEFAULT = 0, - VIEW_MODE_FULLSCREEN = 1, - VIEW_MODE_PRESENTATION = 2 -}; +enum PresetViewModeIds { VIEW_MODE_DEFAULT = 0, VIEW_MODE_FULLSCREEN = 1, VIEW_MODE_PRESENTATION = 2 }; // view mode attributes constexpr auto ATTR_GO_FULLSCREEN = "goFullscren"; -constexpr auto ATTR_SHOW_MENUBAR = "showMenubar"; -constexpr auto ATTR_SHOW_TOOLBAR = "showToolbar"; -constexpr auto ATTR_SHOW_SIDEBAR = "showSidebar"; +constexpr auto ATTR_SHOW_MENUBAR = "showMenubar"; +constexpr auto ATTR_SHOW_TOOLBAR = "showToolbar"; +constexpr auto ATTR_SHOW_SIDEBAR = "showSidebar"; +constexpr auto ATTR_SHOW_WORKSPACE = "showWorkspace"; struct ViewMode { bool goFullscreen{false}; bool showMenubar{false}; bool showToolbar{false}; bool showSidebar{false}; + bool showWorkspace{false}; bool operator==(const ViewMode& other) const; }; diff --git a/src/core/control/stockdlg/XojOpenDlg.cpp b/src/core/control/stockdlg/XojOpenDlg.cpp index 9d844608f67d..fe73dbd0718b 100644 --- a/src/core/control/stockdlg/XojOpenDlg.cpp +++ b/src/core/control/stockdlg/XojOpenDlg.cpp @@ -12,8 +12,8 @@ #include "util/XojPreviewExtractor.h" // for XojPreviewExtractor, PREVIEW_... #include "util/i18n.h" // for _ -XojOpenDlg::XojOpenDlg(GtkWindow* win, Settings* settings): win(win), settings(settings) { - dialog = gtk_file_chooser_dialog_new(_("Open file"), win, GTK_FILE_CHOOSER_ACTION_OPEN, _("_Cancel"), +XojOpenDlg::XojOpenDlg(GtkWindow* win, Settings* settings, const char* dialogTitle): win(win), settings(settings) { + dialog = gtk_file_chooser_dialog_new(_(dialogTitle), win, GTK_FILE_CHOOSER_ACTION_OPEN, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Open"), GTK_RESPONSE_OK, nullptr); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dialog), true); @@ -148,6 +148,35 @@ auto XojOpenDlg::showOpenDialog(bool pdf, bool& attachPdf) -> fs::path { return file; } +auto XojOpenDlg::showOpenFolderDialog() -> fs::path { + + gtk_file_chooser_set_action(GTK_FILE_CHOOSER(this->dialog), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); + + GtkWidget* image = gtk_image_new(); + gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(this->dialog), image); + g_signal_connect(dialog, "update-preview", G_CALLBACK(updatePreviewCallback), nullptr); + + auto lastOpenPath = this->settings->getLastOpenPath(); + if (!lastOpenPath.empty()) { + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(this->dialog), Util::toGFilename(lastOpenPath).c_str()); + } + + auto lastSavePath = this->settings->getLastSavePath(); + if (!lastSavePath.empty()) { + gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(this->dialog), lastSavePath.u8string().c_str(), nullptr); + } + + fs::path folder = runDialog(); + + if (!folder.empty()) { + g_message("lastOpenPath set"); + this->settings->setLastOpenPath(folder); + } + + + return folder; +} + void XojOpenDlg::updatePreviewCallback(GtkFileChooser* fileChooser, void* userData) { auto filepath = Util::fromGFilename(gtk_file_chooser_get_preview_filename(fileChooser)); diff --git a/src/core/control/stockdlg/XojOpenDlg.h b/src/core/control/stockdlg/XojOpenDlg.h index 4e209d35fa2f..489c6ac57209 100644 --- a/src/core/control/stockdlg/XojOpenDlg.h +++ b/src/core/control/stockdlg/XojOpenDlg.h @@ -20,11 +20,12 @@ class Settings; class XojOpenDlg { public: - XojOpenDlg(GtkWindow* win, Settings* settings); + XojOpenDlg(GtkWindow* win, Settings* settings, const char* dialogTitle = "Open file"); virtual ~XojOpenDlg(); public: fs::path showOpenDialog(bool pdf, bool& attachPdf); + fs::path showOpenFolderDialog(); fs::path showOpenTemplateDialog(); protected: diff --git a/src/core/control/workspace/WorkspaceHandler.cpp b/src/core/control/workspace/WorkspaceHandler.cpp index 69cf091bd2f9..9a29adec41a1 100644 --- a/src/core/control/workspace/WorkspaceHandler.cpp +++ b/src/core/control/workspace/WorkspaceHandler.cpp @@ -1,9 +1,6 @@ -#include #include #include -#include // for __shared_ptr_access, make... -#include // for move -#include // for vector +#include #include "WorkspaceHandler.h" #include "WorkspaceHandlerListener.h" diff --git a/src/core/control/workspace/WorkspaceHandler.h b/src/core/control/workspace/WorkspaceHandler.h index ff4e001358af..cc5de00451e6 100644 --- a/src/core/control/workspace/WorkspaceHandler.h +++ b/src/core/control/workspace/WorkspaceHandler.h @@ -1,7 +1,7 @@ /* * Xournal++ * - * A tool + * Workspace Handler * * @author Xournal++ Team * https://github.com/xournalpp/xournalpp diff --git a/src/core/control/workspace/WorkspaceHandlerListener.h b/src/core/control/workspace/WorkspaceHandlerListener.h index 803fa88b5e40..704f145fece4 100644 --- a/src/core/control/workspace/WorkspaceHandlerListener.h +++ b/src/core/control/workspace/WorkspaceHandlerListener.h @@ -1,7 +1,7 @@ /* * Xournal++ * - * Layer Controller listener + * Workspace Handler listener * * @author Xournal++ Team * https://github.com/xournalpp/xournalpp diff --git a/src/core/enums/ActionType.enum.h b/src/core/enums/ActionType.enum.h index 5d3bc675e059..72f821cdca3a 100644 --- a/src/core/enums/ActionType.enum.h +++ b/src/core/enums/ActionType.enum.h @@ -29,6 +29,8 @@ enum ActionType { // Menu file ACTION_NEW = 100, ACTION_OPEN, + ACTION_OPEN_FOLDER, + ACTION_CLOSE_ALL_FOLDERS, ACTION_ANNOTATE_PDF, ACTION_SAVE, ACTION_SAVE_AS, diff --git a/src/core/enums/generated/ActionType.generated.cpp b/src/core/enums/generated/ActionType.generated.cpp index 005823b9b604..bc75c75b7757 100644 --- a/src/core/enums/generated/ActionType.generated.cpp +++ b/src/core/enums/generated/ActionType.generated.cpp @@ -28,6 +28,14 @@ auto ActionType_fromString(const string& value) -> ActionType { return ACTION_OPEN; } + if (value == "ACTION_OPEN_FOLDER") { + return ACTION_OPEN_FOLDER; + } + + if (value == "ACTION_CLOSE_ALL_FOLDERS") { + return ACTION_CLOSE_ALL_FOLDERS; + } + if (value == "ACTION_ANNOTATE_PDF") { return ACTION_ANNOTATE_PDF; } @@ -682,6 +690,14 @@ auto ActionType_toString(ActionType value) -> string { return "ACTION_OPEN"; } + if (value == ACTION_OPEN_FOLDER) { + return "ACTION_OPEN_FOLDER"; + } + + if (value == ACTION_CLOSE_ALL_FOLDERS) { + return "ACTION_CLOSE_ALL_FOLDERS"; + } + if (value == ACTION_ANNOTATE_PDF) { return "ACTION_ANNOTATE_PDF"; } diff --git a/src/core/gui/MainWindow.cpp b/src/core/gui/MainWindow.cpp index e85f422e26c8..c63b237d5d65 100644 --- a/src/core/gui/MainWindow.cpp +++ b/src/core/gui/MainWindow.cpp @@ -14,6 +14,7 @@ #include "control/layer/LayerController.h" // for LayerController #include "control/settings/Settings.h" // for Settings #include "control/settings/SettingsEnums.h" // for SCROLLBAR_HIDE_HO... +#include "control/workspace/WorkspaceHandler.h" #include "control/zoom/ZoomControl.h" // for ZoomControl #include "enums/ActionType.enum.h" // for ACTION_DELETE_LAYER #include "gui/FloatingToolbox.h" // for FloatingToolbox @@ -29,6 +30,7 @@ #include "gui/toolbarMenubar/model/ToolbarModel.h" // for ToolbarModel #include "gui/widgets/SpinPageAdapter.h" // for SpinPageAdapter #include "gui/widgets/XournalWidget.h" // for gtk_xournal_get_l... +#include "gui/Workspace.h" #include "util/GListView.h" // for GListView, GListV... #include "util/PathUtil.h" // for getConfigFile #include "util/Util.h" // for execInUiThread, npos @@ -53,6 +55,9 @@ MainWindow::MainWindow(GladeSearchpath* gladeSearchPath, Control* control, GtkAp toolbar->populate(gladeSearchPath); menubar->populate(this); + panedWorkspaceContainerWidget.reset(get("panedWorkspaceContainer"), xoj::util::ref); + workspaceSidebarContainerWidget.reset(get("workspaceSidebarContainer"), xoj::util::ref); + workspaceSidebarWidget.reset(get("workspaceSidebar"), xoj::util::ref); panedContainerWidget.reset(get("panelMainContents"), xoj::util::ref); boxContainerWidget.reset(get("mainContentContainer"), xoj::util::ref); mainContentWidget.reset(get("boxContents"), xoj::util::ref); @@ -73,6 +78,7 @@ MainWindow::MainWindow(GladeSearchpath* gladeSearchPath, Control* control, GtkAp initXournalWidget(); + setWorkspaceVisible(control->getSettings()->isWorkspaceVisible()); setSidebarVisible(control->getSettings()->isSidebarVisible()); // Window handler @@ -95,6 +101,9 @@ MainWindow::MainWindow(GladeSearchpath* gladeSearchPath, Control* control, GtkAp GtkWidget* menuViewSidebarVisible = get("menuViewSidebarVisible"); g_signal_connect(menuViewSidebarVisible, "toggled", G_CALLBACK(viewShowSidebar), this); + GtkWidget* menuViewWorkspaceVisible = get("menuViewWorkspaceVisible"); + g_signal_connect(menuViewWorkspaceVisible, "toggled", G_CALLBACK(viewShowWorkspace), this); + GtkWidget* menuViewToolbarsVisible = get("menuViewToolbarsVisible"); g_signal_connect(menuViewToolbarsVisible, "toggled", G_CALLBACK(viewShowToolbar), this); @@ -391,6 +400,21 @@ void MainWindow::viewShowSidebar(GtkCheckMenuItem* checkmenuitem, MainWindow* wi win->setSidebarVisible(showSidebar); } +void MainWindow::viewShowWorkspace(GtkCheckMenuItem* checkmenuitem, MainWindow* win) { + bool showWorkspace = gtk_check_menu_item_get_active(checkmenuitem); + Settings* settings = win->control->getSettings(); + if (settings->isWorkspaceVisible() == showWorkspace) { + return; + } + if (settings->getActiveViewMode() == PresetViewModeIds::VIEW_MODE_DEFAULT) { + settings->setWorkspaceVisible(showWorkspace); + ViewMode viewMode = settings->getViewModes()[PresetViewModeIds::VIEW_MODE_DEFAULT]; + viewMode.showWorkspace = showWorkspace; + settings->setViewMode(PresetViewModeIds::VIEW_MODE_DEFAULT, viewMode); + } + win->setWorkspaceVisible(showWorkspace); +} + void MainWindow::viewShowToolbar(GtkCheckMenuItem* checkmenuitem, MainWindow* win) { bool showToolbar = gtk_check_menu_item_get_active(checkmenuitem); Settings* settings = win->control->getSettings(); @@ -534,6 +558,26 @@ void MainWindow::setSidebarVisible(bool visible) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), visible); } +void MainWindow::setWorkspaceVisible(bool visible) { + Settings* settings = control->getSettings(); + settings->setWorkspaceVisible(visible); + if (!visible && (control->getWorkspace() != nullptr)) { + saveWorkspaceSize(); + } + + gtk_widget_set_visible(workspaceSidebarContainerWidget.get(), visible); + + bool showMenuItem = control->getWorkspaceHandler()->getFoldersCount() > 0 || visible; + gtk_widget_set_sensitive(get("menuCloseAllFoldersWorkspace"), showMenuItem); + + if (visible) { + gtk_paned_set_position(GTK_PANED(panedWorkspaceContainerWidget.get()), settings->getWorkspaceWidth()); + } + + GtkWidget* w = get("menuViewWorkspaceVisible"); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), visible); +} + void MainWindow::setToolbarVisible(bool visible) { Settings* settings = control->getSettings(); @@ -553,6 +597,11 @@ void MainWindow::saveSidebarSize() { this->control->getSettings()->setSidebarWidth(gtk_paned_get_position(GTK_PANED(panedContainerWidget.get()))); } +void MainWindow::saveWorkspaceSize() { + this->control->getSettings()->setWorkspaceWidth( + gtk_paned_get_position(GTK_PANED(panedWorkspaceContainerWidget.get()))); +} + void MainWindow::setMaximized(bool maximized) { this->maximized = maximized; } auto MainWindow::isMaximized() const -> bool { return this->maximized; } diff --git a/src/core/gui/MainWindow.h b/src/core/gui/MainWindow.h index df90b5cef446..977cb57cf5c6 100644 --- a/src/core/gui/MainWindow.h +++ b/src/core/gui/MainWindow.h @@ -74,6 +74,7 @@ class MainWindow: public GladeGui, public LayerCtrlListener { XojFont getFontButtonFont() const; void saveSidebarSize(); + void saveWorkspaceSize(); void setMaximized(bool maximized); bool isMaximized() const; @@ -84,6 +85,7 @@ class MainWindow: public GladeGui, public LayerCtrlListener { void setMenubarVisible(bool visible); void setSidebarVisible(bool visible); + void setWorkspaceVisible(bool visible); void setToolbarVisible(bool visible); Control* getControl() const; @@ -147,6 +149,11 @@ class MainWindow: public GladeGui, public LayerCtrlListener { */ static void viewShowSidebar(GtkCheckMenuItem* checkmenuitem, MainWindow* win); + /** + * Workspace show / hidden + */ + static void viewShowWorkspace(GtkCheckMenuItem* checkmenuitem, MainWindow* win); + /** * Toolbar show / hidden */ @@ -199,7 +206,10 @@ class MainWindow: public GladeGui, public LayerCtrlListener { bool sidebarVisible = true; + xoj::util::WidgetSPtr panedWorkspaceContainerWidget; + xoj::util::WidgetSPtr workspaceSidebarContainerWidget; xoj::util::WidgetSPtr boxContainerWidget; + xoj::util::WidgetSPtr workspaceSidebarWidget; xoj::util::WidgetSPtr panedContainerWidget; xoj::util::WidgetSPtr mainContentWidget; xoj::util::WidgetSPtr sidebarWidget; diff --git a/src/core/gui/Workspace.cpp b/src/core/gui/Workspace.cpp index 71737e04d007..1149ef5329b4 100644 --- a/src/core/gui/Workspace.cpp +++ b/src/core/gui/Workspace.cpp @@ -1,11 +1,8 @@ #include "Workspace.h" -#include // for int64_t -#include // for std::make_unique and std::make_shared #include #include // for string -#include #include // for gdk_display_get... #include // for G_CALLBACK, g_s... #include // for gtk_toggle_tool_button_new... @@ -14,12 +11,7 @@ #include "control/settings/Settings.h" // for Settings #include "control/workspace/WorkspaceHandler.h" #include "gui/GladeGui.h" // for GladeGui -#include "model/Document.h" // for Document -#include "model/XojPage.h" // for XojPage #include "pdf/base/XojPdfPage.h" // for XojPdfPageSPtr -#include "util/Util.h" // for npos -#include "util/XojMsgBox.h" -#include "util/i18n.h" // for _, FC, _F enum { @@ -33,12 +25,12 @@ Workspace::Workspace(GladeGui* gui, Control* control, WorkspaceHandler* workspac this->workspaceSidebar = gui->get("workspaceSidebar"); - //this->folderPath = "/home/teogalletta/Documents/my-obsidian-vault/100 university"; this->createViewAndStore(); gtk_container_add(GTK_CONTAINER(this->workspaceSidebar), treeView); - //gtk_viewport_set_shadow_type(GTK_VIEWPORT(gui->get("workspaceSidebarContainer")), GTK_SHADOW_IN); + g_signal_connect(gui->get("buttonAddFolderWorkspace"), "clicked", G_CALLBACK(buttonAddFolderWorkspaceClicked), this); + g_signal_connect(gui->get("buttonCloseWorkspace"), "clicked", G_CALLBACK(buttonCloseWorkspaceClicked), this); gtk_widget_show_all(this->workspaceSidebar); @@ -47,9 +39,16 @@ Workspace::Workspace(GladeGui* gui, Control* control, WorkspaceHandler* workspac addFolder(path); } - Workspace::~Workspace() {} +void Workspace::buttonAddFolderWorkspaceClicked(GtkButton* button, Workspace* workspace) { + workspace->control->openFolder(); +} + +void Workspace::buttonCloseWorkspaceClicked(GtkButton* button, Workspace* workspace) { + workspace->control->closeAllFolders(false); +} + void Workspace::fillTreeFromFolderPath(GtkTreeStore* store, GtkTreeIter* parent, std::string folderPath) { if (!fs::is_directory(fs::path(folderPath))) { @@ -57,6 +56,8 @@ void Workspace::fillTreeFromFolderPath(GtkTreeStore* store, GtkTreeIter* parent, return; } + const std::set exts = {".xopp", ".xoj", ".pdf", ".xopt", ".moj"}; + // to order the filenames std::set entries; for (const auto& entry : fs::directory_iterator(folderPath)) @@ -68,7 +69,7 @@ void Workspace::fillTreeFromFolderPath(GtkTreeStore* store, GtkTreeIter* parent, fs::path entryFilename = entryPath.filename(); GtkTreeIter iter; - if (entry.is_directory() || entryPath.extension() == ".pdf" || entryPath.extension() == ".xopp") { + if (entry.is_directory() || exts.find(entryPath.extension()) != exts.end()) { gtk_tree_store_append(store, &iter, parent); gtk_tree_store_set(store, &iter, COL_NAME, entryFilename.generic_string().c_str(), COL_FULLPATH, entryPath.c_str(), -1); } @@ -90,8 +91,7 @@ void Workspace::createViewAndStore() { renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeView), -1, "Name", renderer, "text", 0, nullptr); - //g_signal_connect(renderer, "cell-data-func", G_CALLBACK(setRootFolderTextBold), nullptr); - + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeView), false); store = gtk_tree_store_new(NUM_COLS, G_TYPE_STRING, G_TYPE_STRING); @@ -109,10 +109,19 @@ void Workspace::addFolder(fs::path folderPath) { gtk_tree_store_set(store, &iter, COL_NAME, fs::path(folderPath).filename().c_str(), -1); fillTreeFromFolderPath(store, &iter, folderPath); + gtk_widget_set_sensitive(gui->get("menuCloseAllFoldersWorkspace"), true); + gtk_widget_show_all(GTK_WIDGET(workspaceSidebar)); } -void Workspace::removeFolder(fs::path folderPath) {} +void Workspace::closeAllFolders() { + + gtk_tree_store_clear(store); + + //gtk_widget_set_sensitive(gui->get("menuCloseAllFoldersWorkspace"), false); + + gtk_widget_show_all(GTK_WIDGET(workspaceSidebar)); +} void Workspace::treeViewRowClicked(GtkTreeView* treeView, GtkTreePath* path, GtkTreeViewColumn* column, Workspace* workspace) { @@ -135,6 +144,7 @@ void Workspace::treeViewRowClicked(GtkTreeView* treeView, GtkTreePath* path, Gtk gtk_tree_view_expand_row(treeView, path, false); } else { + workspace->control->close(true, true); workspace->control->openFile(fsPath); } @@ -142,25 +152,6 @@ void Workspace::treeViewRowClicked(GtkTreeView* treeView, GtkTreePath* path, Gtk } } -/* -void Workspace::setRootFolderTextBold(GtkTreeViewColumn *column, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, void* _ptr) { - gchar* text; - gtk_tree_model_get(model, iter, COL_FULLPATH, &text, -1); - - if (text != nullptr) - return; - - // Creiamo una tag di stile Pango per il testo in grassetto - PangoAttrList* attrs = pango_attr_list_new(); - PangoAttribute* attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD); - pango_attr_list_insert(attrs, attr); - - // Impostiamo il testo nel renderer con il tag di stile Pango - g_object_set(renderer, "text", text, "attributes", attrs, nullptr); - - g_free(text); - pango_attr_list_unref(attrs); -}*/ void Workspace::saveSize() { if (this->control->getSettings()->isWorkspaceVisible()) { diff --git a/src/core/gui/Workspace.h b/src/core/gui/Workspace.h index c6c7c96e5efe..1291b0decb8c 100644 --- a/src/core/gui/Workspace.h +++ b/src/core/gui/Workspace.h @@ -1,7 +1,7 @@ /* * Xournal++ * - * The Sidebar + * The Workspace * * @author Xournal++ Team * https://github.com/xournalpp/xournalpp @@ -12,8 +12,6 @@ #pragma once #include // for string -#include // for size_t -#include // for unique_ptr #include // for vector #include // for GtkWidget, Gtk... @@ -33,7 +31,7 @@ class Workspace: public: void addFolder(fs::path folderPath); - void removeFolder(fs::path folderPath); + void closeAllFolders(); void saveSize(); @@ -41,8 +39,11 @@ class Workspace: void createViewAndStore(); void fillTreeFromFolderPath(GtkTreeStore* store, GtkTreeIter* parent, std::string folderPath); - static void treeViewRowClicked(GtkTreeView* self, GtkTreePath* path, GtkTreeViewColumn* column, Workspace* workspace); - + static void buttonAddFolderWorkspaceClicked(GtkButton* button, Workspace* workspace); + static void buttonCloseWorkspaceClicked(GtkButton* button, Workspace* workspace); + + static void treeViewRowClicked(GtkTreeView* treeView, GtkTreePath* path, GtkTreeViewColumn* column, Workspace* workspace); + Control* control = nullptr; GladeGui* gui = nullptr; diff --git a/src/core/gui/dialog/SettingsDialog.cpp b/src/core/gui/dialog/SettingsDialog.cpp index eea592d7cbb8..022f46288b33 100644 --- a/src/core/gui/dialog/SettingsDialog.cpp +++ b/src/core/gui/dialog/SettingsDialog.cpp @@ -538,18 +538,22 @@ void SettingsDialog::load() { bool showFullscreenMenubar = viewMode.showMenubar; bool showFullscreenToolbar = viewMode.showToolbar; bool showFullscreenSidebar = viewMode.showSidebar; + bool showFullscreenWorkspace = viewMode.showWorkspace; viewMode = settings->getViewModes().at(PresetViewModeIds::VIEW_MODE_PRESENTATION); bool showPresentationMenubar = viewMode.showMenubar; bool showPresentationToolbar = viewMode.showToolbar; bool showPresentationSidebar = viewMode.showSidebar; + bool showPresentationWorkspace = viewMode.showWorkspace; bool goPresentationFullscreen = viewMode.goFullscreen; loadCheckbox("cbShowFullscreenMenubar", showFullscreenMenubar); loadCheckbox("cbShowFullscreenToolbar", showFullscreenToolbar); loadCheckbox("cbShowFullscreenSidebar", showFullscreenSidebar); + loadCheckbox("cbShowFullscreenWorkspace", showFullscreenWorkspace); loadCheckbox("cbShowPresentationMenubar", showPresentationMenubar); loadCheckbox("cbShowPresentationToolbar", showPresentationToolbar); loadCheckbox("cbShowPresentationSidebar", showPresentationSidebar); + loadCheckbox("cbShowPresentationWorkspace", showPresentationWorkspace); loadCheckbox("cbPresentationGoFullscreen", goPresentationFullscreen); loadCheckbox("cbHideMenubarStartup", settings->isMenubarVisible()); loadCheckbox("cbShowFilepathInTitlebar", settings->isFilepathInTitlebarShown()); @@ -789,12 +793,14 @@ void SettingsDialog::save() { viewModeFullscreen.showMenubar = getCheckbox("cbShowFullscreenMenubar"); viewModeFullscreen.showToolbar = getCheckbox("cbShowFullscreenToolbar"); viewModeFullscreen.showSidebar = getCheckbox("cbShowFullscreenSidebar"); + viewModeFullscreen.showWorkspace = getCheckbox("cbShowFullscreenWorkspace"); settings->setViewMode(PresetViewModeIds::VIEW_MODE_FULLSCREEN, viewModeFullscreen); ViewMode viewModePresentation; viewModePresentation.showMenubar = getCheckbox("cbShowPresentationMenubar"); viewModePresentation.showToolbar = getCheckbox("cbShowPresentationToolbar"); viewModePresentation.showSidebar = getCheckbox("cbShowPresentationSidebar"); + viewModePresentation.showWorkspace = getCheckbox("cbShowPresentationWorkspace"); viewModePresentation.goFullscreen = getCheckbox("cbPresentationGoFullscreen"); settings->setViewMode(PresetViewModeIds::VIEW_MODE_PRESENTATION, viewModePresentation); diff --git a/src/core/gui/sidebar/Sidebar.cpp b/src/core/gui/sidebar/Sidebar.cpp index cbe5cc8dfb06..3772d258e558 100644 --- a/src/core/gui/sidebar/Sidebar.cpp +++ b/src/core/gui/sidebar/Sidebar.cpp @@ -184,10 +184,12 @@ void Sidebar::setTmpDisabled(bool disabled) { } void Sidebar::saveSize() { - GtkAllocation alloc; - gtk_widget_get_allocation(this->sidebarContents, &alloc); + if (this->control->getSettings()->isSidebarVisible()) { + GtkAllocation alloc; + gtk_widget_get_allocation(this->sidebarContents, &alloc); - this->control->getSettings()->setSidebarWidth(alloc.width); + this->control->getSettings()->setSidebarWidth(alloc.width); + } } auto Sidebar::getToolbar() -> SidebarToolbar* { return &this->toolbar; } diff --git a/src/core/gui/toolbarMenubar/ToolMenuHandler.cpp b/src/core/gui/toolbarMenubar/ToolMenuHandler.cpp index d91a3510f81d..0b243b247775 100644 --- a/src/core/gui/toolbarMenubar/ToolMenuHandler.cpp +++ b/src/core/gui/toolbarMenubar/ToolMenuHandler.cpp @@ -429,6 +429,8 @@ void ToolMenuHandler::initToolItems() { addCustomItem("NEW", ACTION_NEW, "document-new", _("New Xournal")); addCustomItem("OPEN", ACTION_OPEN, "document-open", _("Open file")); + addCustomItem("OPENFOLDER", ACTION_OPEN_FOLDER, "document-open-folder", _("Add folder to workspace")); + addCustomItem("CLOSEALLFOLDERS", ACTION_OPEN_FOLDER, "document-close-all-folders", _("Clear and close workspace")); addCustomItem("SAVE", ACTION_SAVE, "document-save", _("Save")); addCustomItem("SAVEPDF", ACTION_EXPORT_AS_PDF, "document-export-pdf", _("Export as PDF")); addCustomItem("PRINT", ACTION_PRINT, "document-print", _("Print")); diff --git a/ui/main.glade b/ui/main.glade index 9c4e257b8bd6..0c0774440879 100644 --- a/ui/main.glade +++ b/ui/main.glade @@ -179,6 +179,27 @@ + + + menuAddFolderToWorkspace + True + False + True + Add folder to workspace + + + + + + menuCloseAllFoldersWorkspace + True + False + True + False + Clear and close workspace + + + menuFileRecent @@ -556,7 +577,7 @@ False _Pair Pages True - + @@ -566,8 +587,9 @@ False _Presentation Mode True - - + + @@ -577,8 +599,8 @@ False Fullscreen True - - + + @@ -588,7 +610,17 @@ False Show Sidebar True - + + + + + + menuViewWorkspaceVisible + True + False + Show Workspace + True + @@ -2189,561 +2221,675 @@ - - tbTop1 - True - False - icons - - - False - True - 1 - - - - - tbTop2 - True - False - - - False - True - 2 - - - - - mainContainerBox + True False + horizontal - - tbLeft1 - True - False - vertical - icons - - - False - True - 0 - - - - - tbLeft2 - True - False - vertical - icons - - - False - True - 1 - - - - + True False vertical - - panelMainContents + + workspaceTopBox True - True + False + horizontal - - sidebar + + workspaceSidebarTitle True False - vertical + Workspace + + + 10 + + + + + buttonAddFolderWorkspace + True + True + False + none - + True False - - - tbSelectSidebarPage - True - False - - - True - True - 0 - - - - - buttonCloseSidebar - True - True - False - none - - - True - False - window-close - - - - - - False - True - end - 1 - - - + folder-add - - False - True - 1 - + + + + False + True + end + 1 + + + + + buttonCloseWorkspace + True + True + False + none - - sidebarContents + True False - vertical - - - + delete - - True - True - 2 - + + + + False + True + end + 1 + + + + + 5 + False + True + False + + + + + workspaceSidebar + False + GTK_POLICY_AUTOMATIC + + + True + True + + + + + False + + + + + True + False + vertical + + + tbTop1 + True + False + icons + + + False + True + 1 + + + + + tbTop2 + True + False + + + False + True + 2 + + + + + mainContainerBox + True + False + + + tbLeft1 + True + False + vertical + icons + + + False + True + 0 + + + + + tbLeft2 + True + False + vertical + icons + + + False + True + 1 + + + + + True + False + vertical - + + panelMainContents True - False + True - - btUp + + sidebar True - True - True + False + vertical - + True False - go-up + + + tbSelectSidebarPage + True + False + + + True + True + 0 + + + + + buttonCloseSidebar + True + True + False + none + + + True + False + window-close + + + + + + False + True + end + 1 + + + + + False + True + 1 + - - - False - True - 1 - - - - - btDown - True - True - True - + + sidebarContents True False - go-down + vertical + + + + + True + True + 2 + - - - False - True - 2 - - - - - btCopy - True - True - True - + True False - edit-copy + + + btUp + True + True + True + + + True + False + go-up + + + + + False + True + 1 + + + + + btDown + True + True + True + + + True + False + go-down + + + + + False + True + 2 + + + + + btCopy + True + True + True + + + True + False + edit-copy + + + + + False + True + 3 + + + + + btDelete + True + True + True + + + True + False + edit-delete + + + + + False + True + 4 + + + + + False + True + 2 + 3 + - False - True - 3 + False + False - - btDelete + + boxContents True - True - True + False + vertical - - True - False - edit-delete - + - False - True - 4 + True + True - - False + True True - 2 - 3 + 0 - False - False + True + True + 3 - - boxContents + + tbRight1 True False vertical - - - + icons - True - True + False + True + 3 + + + + + tbRight2 + True + False + vertical + icons + + + False + True + 4 True True - 0 + 3 - - - True - True - 3 - - - - - tbRight1 - True - False - vertical - icons - - - False - True - 3 - - - - - tbRight2 - True - False - vertical - icons - - - False - True - 4 - - - - - True - True - 3 - - - - - searchBar - True - False - vertical - - - separator1 - True - False - - - False - True - 0 - - - - - searchToolbar - False - icons - - toolbutton1 + + searchBar True False - 12 + vertical - + + separator1 True False + + + False + True + 0 + + + + + searchToolbar + False + icons - - searchTextField + + toolbutton1 True - True - edit-find-symbolic - False - False + False + 12 + + + True + False + + + searchTextField + True + True + edit-find-symbolic + False + False + + + True + True + 0 + + + + + btSearchBack + True + False + True + Find previous occurrence of the search string + True + + + True + False + go-up + + + + + False + True + 1 + + + + + btSearchForward + True + False + True + Find next occurrence of the search string + True + + + True + False + go-down + + + + + False + True + 2 + + + + + - True - True - 0 + False + True - - btSearchBack + + toolbutton3 True False - True - Find previous occurrence of the search string - True - + + lbSearchState True False - go-up + end + 0 - False - True - 1 + True + True - - btSearchForward + + toolbutton2 True False - True - Find next occurrence of the search string - True - + + buttonCloseSearch True False - go-down + False + none + + + True + False + window-close + + + False - True - 2 + True - + + True + True + 1 + 1 + False - True + True + 4 - - toolbutton3 + + tbBottom1 True False - - - lbSearchState - True - False - end - 0 - - - True - True + False + True + 5 - - toolbutton2 + + tbBottom2 True False + + + False + True + 6 + + + + + statusbar + False - - buttonCloseSearch + + lbState True False - False - none - - - True - False - window-close - - - + State PLACEHOLDER + + False + True + 5 + 0 + + + + + pgState + True + False + + + False + True + 1 + + + + + statusbar1 + True + False + 10 + 10 + 6 + 6 + vertical + 2 + + + True + True + end + 2 + False - True + True + 7 - True - True - 1 - 1 + True + True - - False - True - 4 - - - - - tbBottom1 - True - False - - - False - True - 5 - - - - - tbBottom2 - True - False - - - False - True - 6 - - - - - statusbar - False - - - lbState - True - False - State PLACEHOLDER - - - False - True - 5 - 0 - - - - - pgState - True - False - - - False - True - 1 - - - - - statusbar1 - True - False - 10 - 10 - 6 - 6 - vertical - 2 - - - True - True - end - 2 - - - - - False - True - 7 - diff --git a/ui/settings.glade b/ui/settings.glade index 2ee38417acfd..f3437dbc922c 100644 --- a/ui/settings.glade +++ b/ui/settings.glade @@ -3718,6 +3718,21 @@ This setting can make it easier to draw with touch. 1 + + + Show Workspace + cbShowFullscreenWorkspace + True + True + False + True + + + False + True + 1 + + @@ -3807,6 +3822,21 @@ This setting can make it easier to draw with touch. 1 + + + Show Workspace + cbShowPresentationWorkspace + True + True + False + True + + + False + True + 1 + + False