diff options
Diffstat (limited to 'examples/demos/documentviewer')
-rw-r--r-- | examples/demos/documentviewer/CMakeLists.txt | 92 | ||||
-rw-r--r-- | examples/demos/documentviewer/app/CMakeLists.txt | 96 | ||||
-rw-r--r-- | examples/demos/documentviewer/app/abstractviewer.cpp (renamed from examples/demos/documentviewer/abstractviewer.cpp) | 108 | ||||
-rw-r--r-- | examples/demos/documentviewer/app/abstractviewer.h (renamed from examples/demos/documentviewer/abstractviewer.h) | 53 | ||||
-rw-r--r-- | examples/demos/documentviewer/app/images/copy.png (renamed from examples/demos/documentviewer/images/copy.png) | bin | 1338 -> 1338 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/copy@2x.png (renamed from examples/demos/documentviewer/images/copy@2x.png) | bin | 2219 -> 2219 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/cut.png (renamed from examples/demos/documentviewer/images/cut.png) | bin | 1323 -> 1323 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/cut@2x.png (renamed from examples/demos/documentviewer/images/cut@2x.png) | bin | 2888 -> 2888 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/go-next-view-page.png (renamed from examples/demos/documentviewer/images/go-next-view-page.png) | bin | 1125 -> 1125 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/go-next-view-page@2x.png (renamed from examples/demos/documentviewer/images/go-next-view-page@2x.png) | bin | 2312 -> 2312 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/go-next-view.png (renamed from examples/demos/documentviewer/images/go-next-view.png) | bin | 990 -> 990 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/go-next-view@2x.png (renamed from examples/demos/documentviewer/images/go-next-view@2x.png) | bin | 1830 -> 1830 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/go-previous-view-page.png (renamed from examples/demos/documentviewer/images/go-previous-view-page.png) | bin | 1119 -> 1119 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/go-previous-view-page@2x.png (renamed from examples/demos/documentviewer/images/go-previous-view-page@2x.png) | bin | 2067 -> 2067 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/go-previous-view.png (renamed from examples/demos/documentviewer/images/go-previous-view.png) | bin | 1010 -> 1010 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/go-previous-view@2x.png (renamed from examples/demos/documentviewer/images/go-previous-view@2x.png) | bin | 1875 -> 1875 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/magnifier.png (renamed from examples/demos/documentviewer/images/magnifier.png) | bin | 1006 -> 1006 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/magnifier@2x.png (renamed from examples/demos/documentviewer/images/magnifier@2x.png) | bin | 2249 -> 2249 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/open.png (renamed from examples/demos/documentviewer/images/open.png) | bin | 2073 -> 2073 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/open@2x.png (renamed from examples/demos/documentviewer/images/open@2x.png) | bin | 1017 -> 1017 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/paste.png (renamed from examples/demos/documentviewer/images/paste.png) | bin | 1645 -> 1645 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/paste@2x.png (renamed from examples/demos/documentviewer/images/paste@2x.png) | bin | 2782 -> 2782 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/print.png (renamed from examples/demos/documentviewer/images/print.png) | bin | 678 -> 678 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/print2x.png (renamed from examples/demos/documentviewer/images/print2x.png) | bin | 931 -> 931 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/qt-logo.png (renamed from examples/demos/documentviewer/images/qt-logo.png) | bin | 1483 -> 1483 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/qt-logo@2x.png (renamed from examples/demos/documentviewer/images/qt-logo@2x.png) | bin | 1933 -> 1933 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/zoom-fit-best.png (renamed from examples/demos/documentviewer/images/zoom-fit-best.png) | bin | 1067 -> 1067 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/zoom-fit-best@2x.png (renamed from examples/demos/documentviewer/images/zoom-fit-best@2x.png) | bin | 1692 -> 1692 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/zoom-fit-width.png (renamed from examples/demos/documentviewer/images/zoom-fit-width.png) | bin | 905 -> 905 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/zoom-fit-width@2x.png (renamed from examples/demos/documentviewer/images/zoom-fit-width@2x.png) | bin | 1724 -> 1724 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/zoom-in.png (renamed from examples/demos/documentviewer/images/zoom-in.png) | bin | 952 -> 952 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/zoom-in@2x.png (renamed from examples/demos/documentviewer/images/zoom-in@2x.png) | bin | 2100 -> 2100 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/zoom-original.png (renamed from examples/demos/documentviewer/images/zoom-original.png) | bin | 946 -> 946 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/zoom-original@2x.png (renamed from examples/demos/documentviewer/images/zoom-original@2x.png) | bin | 2005 -> 2005 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/zoom-out.png (renamed from examples/demos/documentviewer/images/zoom-out.png) | bin | 940 -> 940 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/zoom-out@2x.png (renamed from examples/demos/documentviewer/images/zoom-out@2x.png) | bin | 1971 -> 1971 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/zoom-previous.png (renamed from examples/demos/documentviewer/images/zoom-previous.png) | bin | 946 -> 946 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/images/zoom-previous@2x.png (renamed from examples/demos/documentviewer/images/zoom-previous@2x.png) | bin | 2049 -> 2049 bytes | |||
-rw-r--r-- | examples/demos/documentviewer/app/main.cpp (renamed from examples/demos/documentviewer/main.cpp) | 0 | ||||
-rw-r--r-- | examples/demos/documentviewer/app/mainwindow.cpp (renamed from examples/demos/documentviewer/mainwindow.cpp) | 65 | ||||
-rw-r--r-- | examples/demos/documentviewer/app/mainwindow.h (renamed from examples/demos/documentviewer/mainwindow.h) | 7 | ||||
-rw-r--r-- | examples/demos/documentviewer/app/mainwindow.ui (renamed from examples/demos/documentviewer/mainwindow.ui) | 26 | ||||
-rw-r--r-- | examples/demos/documentviewer/app/recentfilemenu.cpp | 38 | ||||
-rw-r--r-- | examples/demos/documentviewer/app/recentfilemenu.h | 28 | ||||
-rw-r--r-- | examples/demos/documentviewer/app/recentfiles.cpp | 169 | ||||
-rw-r--r-- | examples/demos/documentviewer/app/recentfiles.h | 81 | ||||
-rw-r--r-- | examples/demos/documentviewer/app/viewerfactory.cpp | 173 | ||||
-rw-r--r-- | examples/demos/documentviewer/app/viewerfactory.h | 57 | ||||
-rw-r--r-- | examples/demos/documentviewer/app/viewerinterfaces.h | 39 | ||||
-rw-r--r-- | examples/demos/documentviewer/doc/src/documentviewer.qdoc | 94 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/CMakeLists.txt | 6 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/jsonviewer/CMakeLists.txt | 35 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/jsonviewer/jsonviewer.cpp (renamed from examples/demos/documentviewer/jsonviewer.cpp) | 15 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/jsonviewer/jsonviewer.h (renamed from examples/demos/documentviewer/jsonviewer.h) | 14 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/jsonviewer/jsonviewer.json | 1 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/pdfviewer/CMakeLists.txt | 39 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/pdfviewer/hoverwatcher.cpp (renamed from examples/demos/documentviewer/hoverwatcher.cpp) | 0 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/pdfviewer/hoverwatcher.h (renamed from examples/demos/documentviewer/hoverwatcher.h) | 0 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/pdfviewer/pdfviewer.cpp (renamed from examples/demos/documentviewer/pdfviewer.cpp) | 18 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/pdfviewer/pdfviewer.h (renamed from examples/demos/documentviewer/pdfviewer.h) | 23 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/pdfviewer/pdfviewer.json | 1 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/pdfviewer/zoomselector.cpp (renamed from examples/demos/documentviewer/zoomselector.cpp) | 0 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/pdfviewer/zoomselector.h (renamed from examples/demos/documentviewer/zoomselector.h) | 0 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/txtviewer/CMakeLists.txt | 35 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/txtviewer/txtviewer.cpp (renamed from examples/demos/documentviewer/txtviewer.cpp) | 16 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/txtviewer/txtviewer.h (renamed from examples/demos/documentviewer/txtviewer.h) | 14 | ||||
-rw-r--r-- | examples/demos/documentviewer/plugins/txtviewer/txtviewer.json | 1 | ||||
-rw-r--r-- | examples/demos/documentviewer/viewerfactory.cpp | 32 | ||||
-rw-r--r-- | examples/demos/documentviewer/viewerfactory.h | 19 |
69 files changed, 1160 insertions, 235 deletions
diff --git a/examples/demos/documentviewer/CMakeLists.txt b/examples/demos/documentviewer/CMakeLists.txt index 338f65cd..28f91fc1 100644 --- a/examples/demos/documentviewer/CMakeLists.txt +++ b/examples/demos/documentviewer/CMakeLists.txt @@ -1,93 +1,21 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + cmake_minimum_required(VERSION 3.16) project(documentviewer LANGUAGES CXX) -set(CMAKE_AUTOMOC ON) +find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets + OPTIONAL_COMPONENTS PrintSupport PdfWidgets) if(NOT DEFINED INSTALL_EXAMPLESDIR) set(INSTALL_EXAMPLESDIR "examples") endif() -set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}") - -find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets PdfWidgets - OPTIONAL_COMPONENTS PrintSupport) - -qt_standard_project_setup() - -qt_add_executable(documentviewer - main.cpp - mainwindow.cpp mainwindow.h mainwindow.ui - abstractviewer.cpp abstractviewer.h - viewerfactory.cpp viewerfactory.h - jsonviewer.cpp jsonviewer.h - txtviewer.cpp txtviewer.h - pdfviewer.cpp pdfviewer.h - zoomselector.cpp zoomselector.h - hoverwatcher.cpp hoverwatcher.cpp -) - -set_target_properties(documentviewer PROPERTIES - WIN32_EXECUTABLE TRUE - MACOSX_BUNDLE TRUE -) -# Resources: -set(documentviewer_resource_files - "images/copy@2x.png" - "images/copy.png" - "images/cut@2x.png" - "images/cut.png" - "images/go-next-view@2x.png" - "images/go-next-view-page@2x.png" - "images/go-next-view-page.png" - "images/go-next-view.png" - "images/go-previous-view@2x.png" - "images/go-previous-view-page@2x.png" - "images/go-previous-view-page.png" - "images/go-previous-view.png" - "images/magnifier@2x.png" - "images/magnifier.png" - "images/open@2x.png" - "images/open.png" - "images/paste@2x.png" - "images/paste.png" - "images/print2x.png" - "images/print.png" - "images/qt-logo@2x.png" - "images/qt-logo.png" - "images/zoom-fit-best@2x.png" - "images/zoom-fit-best.png" - "images/zoom-fit-width@2x.png" - "images/zoom-fit-width.png" - "images/zoom-in@2x.png" - "images/zoom-in.png" - "images/zoom-original@2x.png" - "images/zoom-original.png" - "images/zoom-out@2x.png" - "images/zoom-out.png" - "images/zoom-previous@2x.png" - "images/zoom-previous.png" -) - -qt6_add_resources(documentviewer "documentviewer" - PREFIX - "/demos/documentviewer" - FILES - ${documentviewer_resource_files} -) - -target_link_libraries(documentviewer PUBLIC - Qt::Core - Qt::Gui - Qt::Widgets - Qt::PdfWidgets -) - if(TARGET Qt6::PrintSupport) - target_link_libraries(documentviewer PRIVATE Qt6::PrintSupport) + add_compile_definitions(QT_DOCUMENTVIEWER_PRINTSUPPORT) endif() -install(TARGETS documentviewer - RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" - BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" - LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" -) +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/demos/documentviewer") + +add_subdirectory(app) +add_subdirectory(plugins) diff --git a/examples/demos/documentviewer/app/CMakeLists.txt b/examples/demos/documentviewer/app/CMakeLists.txt new file mode 100644 index 00000000..f23998b8 --- /dev/null +++ b/examples/demos/documentviewer/app/CMakeLists.txt @@ -0,0 +1,96 @@ +cmake_minimum_required(VERSION 3.16) +project(documentviewer LANGUAGES CXX) + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets + OPTIONAL_COMPONENTS PrintSupport PdfWidgets) + +qt_standard_project_setup() + +set(CMAKE_AUTOMOC ON) + +qt_add_executable(documentviewer + main.cpp + mainwindow.cpp mainwindow.h mainwindow.ui + viewerfactory.cpp viewerfactory.h + abstractviewer.cpp abstractviewer.h + recentfiles.cpp recentfiles.h + recentfilemenu.cpp recentfilemenu.h + viewerinterfaces.h +) + +set_target_properties(documentviewer PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +qt_add_resources(documentviewer "documentviewer" + PREFIX + "/demos/documentviewer" + FILES + "images/copy@2x.png" + "images/copy.png" + "images/cut@2x.png" + "images/cut.png" + "images/go-next-view@2x.png" + "images/go-next-view-page@2x.png" + "images/go-next-view-page.png" + "images/go-next-view.png" + "images/go-previous-view@2x.png" + "images/go-previous-view-page@2x.png" + "images/go-previous-view-page.png" + "images/go-previous-view.png" + "images/magnifier@2x.png" + "images/magnifier.png" + "images/open@2x.png" + "images/open.png" + "images/paste@2x.png" + "images/paste.png" + "images/print2x.png" + "images/print.png" + "images/qt-logo@2x.png" + "images/qt-logo.png" + "images/zoom-fit-best@2x.png" + "images/zoom-fit-best.png" + "images/zoom-fit-width@2x.png" + "images/zoom-fit-width.png" + "images/zoom-in@2x.png" + "images/zoom-in.png" + "images/zoom-original@2x.png" + "images/zoom-original.png" + "images/zoom-out@2x.png" + "images/zoom-out.png" + "images/zoom-previous@2x.png" + "images/zoom-previous.png" +) + +target_link_libraries(documentviewer PRIVATE + Qt::Core + Qt::Gui + Qt::Widgets +) + +if(QT6_IS_SHARED_LIBS_BUILD) + add_dependencies(documentviewer + jsonviewer + pdfviewer + txtviewer + ) +else() + target_link_libraries(documentviewer PRIVATE + jsonviewer + pdfviewer + txtviewer + ) +endif() + +if(TARGET Qt6::PrintSupport) + target_link_libraries(documentviewer PRIVATE Qt6::PrintSupport) + add_compile_definitions(QT_DOCUMENTVIEWER_PRINTSUPPORT) +endif() + +install(TARGETS documentviewer + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) + diff --git a/examples/demos/documentviewer/abstractviewer.cpp b/examples/demos/documentviewer/app/abstractviewer.cpp index 0dbc3b26..4d6191ab 100644 --- a/examples/demos/documentviewer/abstractviewer.cpp +++ b/examples/demos/documentviewer/app/abstractviewer.cpp @@ -13,14 +13,18 @@ #include <QSettings> #include <QApplication> -#if defined(QT_ABSTRACTVIEWER_PRINTSUPPORT) +#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT #include <QPrintDialog> -#endif // QT_ABSTRACTVIEWER_PRINTSUPPORT +#endif // QT_DOCUMENTVIEWER_PRINTSUPPORT -AbstractViewer::AbstractViewer(QFile *file, QWidget *widget, QMainWindow *mainWindow) : - m_file(file), - m_widget(widget) +AbstractViewer::AbstractViewer() : m_file(nullptr), m_widget(nullptr) { +} + +void AbstractViewer::init(QFile *file, QWidget *widget, QMainWindow *mainWindow) +{ + m_file.reset(file); + m_widget = widget; Q_ASSERT(widget); Q_ASSERT(mainWindow); m_uiAssets.mainWindow = mainWindow; @@ -35,6 +39,96 @@ AbstractViewer::~AbstractViewer() qDeleteAll(m_toolBars); } +bool AbstractViewer::isEmpty() const +{ + return !hasContent(); +} + +bool AbstractViewer::isPrintingEnabled() const +{ + return m_printingEnabled; +} + +bool AbstractViewer::hasContent() const +{ + return false; +} + +bool AbstractViewer::supportsOverview() const +{ + return false; +} + +bool AbstractViewer::isModified() const +{ + return false; +} + +bool AbstractViewer::saveDocument() +{ + return false; +} + +bool AbstractViewer::saveDocumentAs() +{ + return false; +} + +QList<QAction *> AbstractViewer::actions() const +{ + return m_actions; +} + +QWidget *AbstractViewer::widget() const +{ + return m_widget; +} + +QList<QMenu *> AbstractViewer::menus() const +{ + return m_menus; +} + +QMainWindow *AbstractViewer::mainWindow() const +{ + return m_uiAssets.mainWindow; +} + +QStatusBar *AbstractViewer::statusBar() const +{ + return mainWindow()->statusBar(); +} + +QMenuBar *AbstractViewer::menuBar() const +{ + return mainWindow()->menuBar(); +} + +void AbstractViewer::maybeEnablePrinting() +{ + maybeSetPrintingEnabled(true); +} + +void AbstractViewer::disablePrinting() +{ + maybeSetPrintingEnabled(false); +} + +bool AbstractViewer::isDefaultViewer() const +{ + return false; +} + +AbstractViewer *AbstractViewer::viewer() +{ + return this; +} + +const AbstractViewer *AbstractViewer::viewer() const +{ + return this; +} + void AbstractViewer::statusMessage(const QString &message, const QString &type, int timeout) { const QString msg = viewerName() + (type.isEmpty() ? ": " : "/" + type + ": ") + message; @@ -78,7 +172,7 @@ QMenu *AbstractViewer::fileMenu() void AbstractViewer::print() { -#ifdef QT_ABSTRACTVIEWER_PRINTSUPPORT +#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT static const QString type = tr("Printing"); if (!hasContent()) { statusMessage(tr("No content to print."), type); @@ -126,7 +220,7 @@ void AbstractViewer::print() */ void AbstractViewer::maybeSetPrintingEnabled(bool enabled) { -#ifndef QT_ABSTRACTVIEWER_PRINTSUPPORT +#ifndef QT_DOCUMENTVIEWER_PRINTSUPPORT enabled = false; #else if (!hasContent()) diff --git a/examples/demos/documentviewer/abstractviewer.h b/examples/demos/documentviewer/app/abstractviewer.h index 702702ba..fb5dd891 100644 --- a/examples/demos/documentviewer/abstractviewer.h +++ b/examples/demos/documentviewer/app/abstractviewer.h @@ -8,14 +8,9 @@ #include <QMainWindow> #include <QFileInfo> -#if defined(QT_PRINTSUPPORT_LIB) +#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT #include <QtPrintSupport/qtprintsupportglobal.h> -#if QT_CONFIG(printer) -#if QT_CONFIG(printdialog) -#define QT_ABSTRACTVIEWER_PRINTSUPPORT #include <QPrinter> -#endif // QT_CONFIG(printdialog) -#endif // QT_CONFIG(printer) #endif // QT_PRINTSUPPORT_LIB class QToolBar; @@ -27,28 +22,32 @@ class AbstractViewer : public QObject Q_OBJECT protected: - explicit AbstractViewer(QFile *file, QWidget *widget, QMainWindow *mainWindow); + AbstractViewer(); public: virtual ~AbstractViewer(); - + virtual void init(QFile *file, QWidget *widget, QMainWindow *mainWindow); void initViewer(QAction *back, QAction *forward, QAction *help, QTabWidget *tabs); - virtual bool isModified() const { return false; } - virtual bool saveDocument() { return false; } - virtual bool saveDocumentAs() { return false; } + virtual bool isModified() const; + virtual bool saveDocument(); + virtual bool saveDocumentAs(); virtual QString viewerName() const = 0; - virtual bool supportsOverview() const { return false; } + virtual bool supportsOverview() const; virtual QByteArray saveState() const = 0; virtual bool restoreState(QByteArray &) = 0; - virtual bool hasContent() const { return false; } - bool isEmpty() const { return !hasContent(); } - bool isPrintingEnabled() const { return m_printingEnabled; } - - QList<QAction *> actions() const { return m_actions; } - QWidget *widget() const { return m_widget; } - QList<QMenu *> menus() const { return m_menus; } - -#ifdef QT_ABSTRACTVIEWER_PRINTSUPPORT + virtual bool hasContent() const; + virtual QStringList supportedMimeTypes() const = 0; + virtual bool isDefaultViewer() const; + bool isEmpty() const; + bool isPrintingEnabled() const; + AbstractViewer *viewer(); + const AbstractViewer *viewer() const; + + QList<QAction *> actions() const; + QWidget *widget() const; + QList<QMenu *> menus() const; + +#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT protected: virtual void printDocument(QPrinter *) const {}; #endif @@ -76,18 +75,18 @@ protected: QToolBar *addToolBar(const QString &); QMenu *addMenu(const QString &); QMenu *fileMenu(); - QMainWindow *mainWindow() const { return m_uiAssets.mainWindow; } - QStatusBar *statusBar() const { return mainWindow()->statusBar(); } - QMenuBar *menuBar() const { return mainWindow()->menuBar(); } + QMainWindow *mainWindow() const; + QStatusBar *statusBar() const; + QMenuBar *menuBar() const; std::unique_ptr<QFile> m_file; QList<QAction *> m_actions; - QWidget *m_widget; + QWidget *m_widget = nullptr; protected slots: void maybeSetPrintingEnabled(bool enabled); - inline void maybeEnablePrinting() { return maybeSetPrintingEnabled(true); } - inline void disablePrinting() { return maybeSetPrintingEnabled(false); } + void maybeEnablePrinting(); + void disablePrinting(); private: QList<QMenu *> m_menus; diff --git a/examples/demos/documentviewer/images/copy.png b/examples/demos/documentviewer/app/images/copy.png Binary files differindex 2aeb2828..2aeb2828 100644 --- a/examples/demos/documentviewer/images/copy.png +++ b/examples/demos/documentviewer/app/images/copy.png diff --git a/examples/demos/documentviewer/images/copy@2x.png b/examples/demos/documentviewer/app/images/copy@2x.png Binary files differindex f4ebabba..f4ebabba 100644 --- a/examples/demos/documentviewer/images/copy@2x.png +++ b/examples/demos/documentviewer/app/images/copy@2x.png diff --git a/examples/demos/documentviewer/images/cut.png b/examples/demos/documentviewer/app/images/cut.png Binary files differindex 54638e93..54638e93 100644 --- a/examples/demos/documentviewer/images/cut.png +++ b/examples/demos/documentviewer/app/images/cut.png diff --git a/examples/demos/documentviewer/images/cut@2x.png b/examples/demos/documentviewer/app/images/cut@2x.png Binary files differindex 5a5da4fd..5a5da4fd 100644 --- a/examples/demos/documentviewer/images/cut@2x.png +++ b/examples/demos/documentviewer/app/images/cut@2x.png diff --git a/examples/demos/documentviewer/images/go-next-view-page.png b/examples/demos/documentviewer/app/images/go-next-view-page.png Binary files differindex bd2a3383..bd2a3383 100644 --- a/examples/demos/documentviewer/images/go-next-view-page.png +++ b/examples/demos/documentviewer/app/images/go-next-view-page.png diff --git a/examples/demos/documentviewer/images/go-next-view-page@2x.png b/examples/demos/documentviewer/app/images/go-next-view-page@2x.png Binary files differindex 5ddcbbcc..5ddcbbcc 100644 --- a/examples/demos/documentviewer/images/go-next-view-page@2x.png +++ b/examples/demos/documentviewer/app/images/go-next-view-page@2x.png diff --git a/examples/demos/documentviewer/images/go-next-view.png b/examples/demos/documentviewer/app/images/go-next-view.png Binary files differindex 98b79dea..98b79dea 100644 --- a/examples/demos/documentviewer/images/go-next-view.png +++ b/examples/demos/documentviewer/app/images/go-next-view.png diff --git a/examples/demos/documentviewer/images/go-next-view@2x.png b/examples/demos/documentviewer/app/images/go-next-view@2x.png Binary files differindex 91940643..91940643 100644 --- a/examples/demos/documentviewer/images/go-next-view@2x.png +++ b/examples/demos/documentviewer/app/images/go-next-view@2x.png diff --git a/examples/demos/documentviewer/images/go-previous-view-page.png b/examples/demos/documentviewer/app/images/go-previous-view-page.png Binary files differindex ecd3768e..ecd3768e 100644 --- a/examples/demos/documentviewer/images/go-previous-view-page.png +++ b/examples/demos/documentviewer/app/images/go-previous-view-page.png diff --git a/examples/demos/documentviewer/images/go-previous-view-page@2x.png b/examples/demos/documentviewer/app/images/go-previous-view-page@2x.png Binary files differindex f0d91c9f..f0d91c9f 100644 --- a/examples/demos/documentviewer/images/go-previous-view-page@2x.png +++ b/examples/demos/documentviewer/app/images/go-previous-view-page@2x.png diff --git a/examples/demos/documentviewer/images/go-previous-view.png b/examples/demos/documentviewer/app/images/go-previous-view.png Binary files differindex 086bd9a1..086bd9a1 100644 --- a/examples/demos/documentviewer/images/go-previous-view.png +++ b/examples/demos/documentviewer/app/images/go-previous-view.png diff --git a/examples/demos/documentviewer/images/go-previous-view@2x.png b/examples/demos/documentviewer/app/images/go-previous-view@2x.png Binary files differindex 900860ce..900860ce 100644 --- a/examples/demos/documentviewer/images/go-previous-view@2x.png +++ b/examples/demos/documentviewer/app/images/go-previous-view@2x.png diff --git a/examples/demos/documentviewer/images/magnifier.png b/examples/demos/documentviewer/app/images/magnifier.png Binary files differindex 6eb457d9..6eb457d9 100644 --- a/examples/demos/documentviewer/images/magnifier.png +++ b/examples/demos/documentviewer/app/images/magnifier.png diff --git a/examples/demos/documentviewer/images/magnifier@2x.png b/examples/demos/documentviewer/app/images/magnifier@2x.png Binary files differindex ed84af18..ed84af18 100644 --- a/examples/demos/documentviewer/images/magnifier@2x.png +++ b/examples/demos/documentviewer/app/images/magnifier@2x.png diff --git a/examples/demos/documentviewer/images/open.png b/examples/demos/documentviewer/app/images/open.png Binary files differindex 45fa2883..45fa2883 100644 --- a/examples/demos/documentviewer/images/open.png +++ b/examples/demos/documentviewer/app/images/open.png diff --git a/examples/demos/documentviewer/images/open@2x.png b/examples/demos/documentviewer/app/images/open@2x.png Binary files differindex 12c2c3c1..12c2c3c1 100644 --- a/examples/demos/documentviewer/images/open@2x.png +++ b/examples/demos/documentviewer/app/images/open@2x.png diff --git a/examples/demos/documentviewer/images/paste.png b/examples/demos/documentviewer/app/images/paste.png Binary files differindex c14425ca..c14425ca 100644 --- a/examples/demos/documentviewer/images/paste.png +++ b/examples/demos/documentviewer/app/images/paste.png diff --git a/examples/demos/documentviewer/images/paste@2x.png b/examples/demos/documentviewer/app/images/paste@2x.png Binary files differindex 360b0f6c..360b0f6c 100644 --- a/examples/demos/documentviewer/images/paste@2x.png +++ b/examples/demos/documentviewer/app/images/paste@2x.png diff --git a/examples/demos/documentviewer/images/print.png b/examples/demos/documentviewer/app/images/print.png Binary files differindex 4ace2614..4ace2614 100644 --- a/examples/demos/documentviewer/images/print.png +++ b/examples/demos/documentviewer/app/images/print.png diff --git a/examples/demos/documentviewer/images/print2x.png b/examples/demos/documentviewer/app/images/print2x.png Binary files differindex 1c3655be..1c3655be 100644 --- a/examples/demos/documentviewer/images/print2x.png +++ b/examples/demos/documentviewer/app/images/print2x.png diff --git a/examples/demos/documentviewer/images/qt-logo.png b/examples/demos/documentviewer/app/images/qt-logo.png Binary files differindex c9171422..c9171422 100644 --- a/examples/demos/documentviewer/images/qt-logo.png +++ b/examples/demos/documentviewer/app/images/qt-logo.png diff --git a/examples/demos/documentviewer/images/qt-logo@2x.png b/examples/demos/documentviewer/app/images/qt-logo@2x.png Binary files differindex 95d1d09b..95d1d09b 100644 --- a/examples/demos/documentviewer/images/qt-logo@2x.png +++ b/examples/demos/documentviewer/app/images/qt-logo@2x.png diff --git a/examples/demos/documentviewer/images/zoom-fit-best.png b/examples/demos/documentviewer/app/images/zoom-fit-best.png Binary files differindex 6a13de4c..6a13de4c 100644 --- a/examples/demos/documentviewer/images/zoom-fit-best.png +++ b/examples/demos/documentviewer/app/images/zoom-fit-best.png diff --git a/examples/demos/documentviewer/images/zoom-fit-best@2x.png b/examples/demos/documentviewer/app/images/zoom-fit-best@2x.png Binary files differindex 904b41c8..904b41c8 100644 --- a/examples/demos/documentviewer/images/zoom-fit-best@2x.png +++ b/examples/demos/documentviewer/app/images/zoom-fit-best@2x.png diff --git a/examples/demos/documentviewer/images/zoom-fit-width.png b/examples/demos/documentviewer/app/images/zoom-fit-width.png Binary files differindex d51fbac6..d51fbac6 100644 --- a/examples/demos/documentviewer/images/zoom-fit-width.png +++ b/examples/demos/documentviewer/app/images/zoom-fit-width.png diff --git a/examples/demos/documentviewer/images/zoom-fit-width@2x.png b/examples/demos/documentviewer/app/images/zoom-fit-width@2x.png Binary files differindex 4d1fd0b4..4d1fd0b4 100644 --- a/examples/demos/documentviewer/images/zoom-fit-width@2x.png +++ b/examples/demos/documentviewer/app/images/zoom-fit-width@2x.png diff --git a/examples/demos/documentviewer/images/zoom-in.png b/examples/demos/documentviewer/app/images/zoom-in.png Binary files differindex 5ae1046c..5ae1046c 100644 --- a/examples/demos/documentviewer/images/zoom-in.png +++ b/examples/demos/documentviewer/app/images/zoom-in.png diff --git a/examples/demos/documentviewer/images/zoom-in@2x.png b/examples/demos/documentviewer/app/images/zoom-in@2x.png Binary files differindex 863ef4ac..863ef4ac 100644 --- a/examples/demos/documentviewer/images/zoom-in@2x.png +++ b/examples/demos/documentviewer/app/images/zoom-in@2x.png diff --git a/examples/demos/documentviewer/images/zoom-original.png b/examples/demos/documentviewer/app/images/zoom-original.png Binary files differindex 8aa9bb49..8aa9bb49 100644 --- a/examples/demos/documentviewer/images/zoom-original.png +++ b/examples/demos/documentviewer/app/images/zoom-original.png diff --git a/examples/demos/documentviewer/images/zoom-original@2x.png b/examples/demos/documentviewer/app/images/zoom-original@2x.png Binary files differindex d5473007..d5473007 100644 --- a/examples/demos/documentviewer/images/zoom-original@2x.png +++ b/examples/demos/documentviewer/app/images/zoom-original@2x.png diff --git a/examples/demos/documentviewer/images/zoom-out.png b/examples/demos/documentviewer/app/images/zoom-out.png Binary files differindex 081b6d98..081b6d98 100644 --- a/examples/demos/documentviewer/images/zoom-out.png +++ b/examples/demos/documentviewer/app/images/zoom-out.png diff --git a/examples/demos/documentviewer/images/zoom-out@2x.png b/examples/demos/documentviewer/app/images/zoom-out@2x.png Binary files differindex 34c8e174..34c8e174 100644 --- a/examples/demos/documentviewer/images/zoom-out@2x.png +++ b/examples/demos/documentviewer/app/images/zoom-out@2x.png diff --git a/examples/demos/documentviewer/images/zoom-previous.png b/examples/demos/documentviewer/app/images/zoom-previous.png Binary files differindex 0ff5c041..0ff5c041 100644 --- a/examples/demos/documentviewer/images/zoom-previous.png +++ b/examples/demos/documentviewer/app/images/zoom-previous.png diff --git a/examples/demos/documentviewer/images/zoom-previous@2x.png b/examples/demos/documentviewer/app/images/zoom-previous@2x.png Binary files differindex e9909abc..e9909abc 100644 --- a/examples/demos/documentviewer/images/zoom-previous@2x.png +++ b/examples/demos/documentviewer/app/images/zoom-previous@2x.png diff --git a/examples/demos/documentviewer/main.cpp b/examples/demos/documentviewer/app/main.cpp index 1540bc5a..1540bc5a 100644 --- a/examples/demos/documentviewer/main.cpp +++ b/examples/demos/documentviewer/app/main.cpp diff --git a/examples/demos/documentviewer/mainwindow.cpp b/examples/demos/documentviewer/app/mainwindow.cpp index ac134101..94ff73e8 100644 --- a/examples/demos/documentviewer/mainwindow.cpp +++ b/examples/demos/documentviewer/app/mainwindow.cpp @@ -1,9 +1,12 @@ // Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + #include "mainwindow.h" #include "ui_mainwindow.h" -#include "abstractviewer.h" #include "viewerfactory.h" +#include "abstractviewer.h" +#include "recentfiles.h" +#include "recentfilemenu.h" #include <QFileDialog> #include <QSettings> #include <QToolButton> @@ -15,7 +18,25 @@ MainWindow::MainWindow(QWidget *parent) : ui(new Ui::MainWindow) { ui->setupUi(this); + + m_recentFiles.reset(new RecentFiles(ui->actionRecent)); + connect(m_recentFiles.get(), &RecentFiles::countChanged, this, [&](int count){ + ui->actionRecent->setText(QString("%1 recent files").arg(count)); + }); + readSettings(); + m_factory.reset(new ViewerFactory(ui->viewArea, this)); + const QStringList &viewers = m_factory->viewerNames(); + const QString msg = tr("Available viewers: ") + viewers.join(", "); + statusBar()->showMessage(msg); + + auto *menu = new RecentFileMenu(this, m_recentFiles.get()); + ui->actionRecent->setMenu(menu); + connect(menu, &RecentFileMenu::fileOpened, this, &MainWindow::openFile); + QWidget *w = ui->mainToolBar->widgetForAction(ui->actionRecent); + auto *button = qobject_cast<QToolButton *>(w); + if (button) + connect(ui->actionRecent, &QAction::triggered, button, &QToolButton::showMenu); } MainWindow::~MainWindow() @@ -46,24 +67,48 @@ void MainWindow::openFile(const QString &fileName) QFileInfo fileInfo(*file); m_currentDir = fileInfo.dir(); + m_recentFiles->addFile(fileInfo.absoluteFilePath()); // If a viewer is already open, save its state first saveViewerSettings(); - m_viewer.reset(ViewerFactory::makeViewer(file, ui->viewArea, this)); - restoreViewerSettings(); + m_viewer = m_factory->viewer(file); + if (!m_viewer) { + statusBar()->showMessage(tr("File %1 can't be opened.").arg(fileName)); + return; + } ui->actionPrint->setEnabled(m_viewer->hasContent()); - connect(m_viewer.get(), &AbstractViewer::printingEnabledChanged, ui->actionPrint, &QAction::setEnabled); - connect(ui->actionPrint, &QAction::triggered, m_viewer.get(), &AbstractViewer::print); - connect(m_viewer.get(), &AbstractViewer::showMessage, statusBar(), &QStatusBar::showMessage); + connect(m_viewer, &AbstractViewer::printingEnabledChanged, ui->actionPrint, &QAction::setEnabled); + connect(ui->actionPrint, &QAction::triggered, m_viewer, &AbstractViewer::print); + connect(m_viewer, &AbstractViewer::showMessage, statusBar(), &QStatusBar::showMessage); m_viewer->initViewer(ui->actionBack, ui->actionForward, ui->menuHelp->menuAction(), ui->tabWidget); + restoreViewerSettings(); ui->scrollArea->setWidget(m_viewer->widget()); } void MainWindow::on_actionAbout_triggered() { - QMessageBox::aboutQt(this); + static const QString &text = [&]{ + QString text = tr("A Widgets application to display and print JSON, " + "text and PDF files. Demonstrates various features to use " + "in widget applications: Using QSettings, query and save " + "user preferences, manage file histories and control cursor " + "behavior when hovering over widgets.\n\n" + "This version has loaded the following plugins:\n") + + m_factory->viewerNames().join(", ") + + tr("\n\nIt supports thow following mime types:\n") + + m_factory->supportedMimeTypes().join("\n"); + + AbstractViewer *def = m_factory->defaultViewer(); + if (def) { + text += tr("\n\nOther mime types will be displayed with ") + def->viewerName() + "."; + } + + return text; + }(); + + QMessageBox::about(this, tr("About Document Viewer Demo"), text); } void MainWindow::on_actionAboutQt_triggered() @@ -86,6 +131,9 @@ void MainWindow::readSettings() QByteArray mainWindowState = settings.value(settingsMainWindow).toByteArray(); restoreState(mainWindowState); } + + // Restore recent files + m_recentFiles->restoreFromSettings(settings, settingsFiles); } void MainWindow::saveSettings() const @@ -98,6 +146,9 @@ void MainWindow::saveSettings() const // Save QMainWindow state settings.setValue(settingsMainWindow, saveState()); + // Save recent files + m_recentFiles->saveSettings(settings, settingsFiles); + settings.sync(); } diff --git a/examples/demos/documentviewer/mainwindow.h b/examples/demos/documentviewer/app/mainwindow.h index 64d95718..52bea422 100644 --- a/examples/demos/documentviewer/mainwindow.h +++ b/examples/demos/documentviewer/app/mainwindow.h @@ -10,6 +10,8 @@ #include <QStringLiteral> class AbstractViewer; +class RecentFiles; +class ViewerFactory; namespace Ui { class MainWindow; } @@ -37,14 +39,17 @@ private: void saveViewerSettings() const; QDir m_currentDir; + AbstractViewer *m_viewer = nullptr; std::unique_ptr<Ui::MainWindow> ui; - std::unique_ptr<AbstractViewer> m_viewer; + std::unique_ptr<RecentFiles> m_recentFiles; int m_classId = -1; + std::unique_ptr<ViewerFactory> m_factory; static constexpr QLatin1StringView settingsName = QLatin1StringView("DocumentViewerExample"); static constexpr QLatin1StringView settingsDir = QLatin1StringView("WorkingDir"); static constexpr QLatin1StringView settingsMainWindow = QLatin1StringView("MainWindow"); static constexpr QLatin1StringView settingsViewers = QLatin1StringView("Viewers"); + static constexpr QLatin1StringView settingsFiles = QLatin1StringView("RecentFiles"); }; #endif // MAINWINDOW_H diff --git a/examples/demos/documentviewer/mainwindow.ui b/examples/demos/documentviewer/app/mainwindow.ui index 815384eb..c77fcb9e 100644 --- a/examples/demos/documentviewer/mainwindow.ui +++ b/examples/demos/documentviewer/app/mainwindow.ui @@ -14,7 +14,7 @@ <string>Document Viewer Demo</string> </property> <property name="windowIcon"> - <iconset resource="../../../../../build/dev/qtdoc/examples/demos/documentviewer/.rcc/documentviewer.qrc"> + <iconset resource="../../../../../../build/dev/qtdoc/examples/demos/documentviewer/app/.rcc/documentviewer.qrc"> <normaloff>:/demos/documentviewer/images/qt-logo.png</normaloff>:/demos/documentviewer/images/qt-logo.png</iconset> </property> <widget class="QWidget" name="centralwidget"> @@ -96,6 +96,7 @@ <string>File</string> </property> <addaction name="actionOpen"/> + <addaction name="actionRecent"/> <addaction name="actionPrint"/> <addaction name="actionQuit"/> </widget> @@ -121,6 +122,7 @@ <bool>false</bool> </attribute> <addaction name="actionOpen"/> + <addaction name="actionRecent"/> <addaction name="actionPrint"/> <addaction name="separator"/> <addaction name="actionBack"/> @@ -141,8 +143,8 @@ </action> <action name="actionAbout"> <property name="icon"> - <iconset theme="help-about"> - <normaloff>.</normaloff>.</iconset> + <iconset theme="help-about" resource="../../../../../../build/dev/qtdoc/examples/demos/documentviewer/app/.rcc/documentviewer.qrc"> + <normaloff>:/demos/documentviewer/images/qt-logo.png</normaloff>:/demos/documentviewer/images/qt-logo.png</iconset> </property> <property name="text"> <string>about documentviewer</string> @@ -189,8 +191,8 @@ <bool>false</bool> </property> <property name="icon"> - <iconset theme="document-print"> - <normaloff>:/demos/documentviewer/images/print.png</normaloff>:/demos/documentviewer/images/print.png</iconset> + <iconset theme="document-print" resource="../../../../../../build/dev/qtdoc/examples/demos/documentviewer/app/.rcc/documentviewer.qrc"> + <normaloff>:/demos/documentviewer/images/print.png</normaloff>:/demos/documentviewer/images/print.png</iconset> </property> <property name="text"> <string>Print</string> @@ -204,9 +206,9 @@ </action> <action name="actionAboutQt"> <property name="icon"> - <iconset resource="../../../../../build/dev/qthttpserver/examples/httpserver/simple/.rcc/assets.qrc"> - <normaloff>:/demos/documentviewer/images/qt-logo.png</normaloff> - <normalon>:/demos/documentviewer/images/qt-logo.png</normalon>:/demos/documentviewer/images/qt-logo.png</iconset> + <iconset resource="../../../../../../build/dev/qtdoc/examples/demos/documentviewer/app/.rcc/documentviewer.qrc"> + <normaloff>:/demos/documentviewer/images/qt-logo.png</normaloff> + <normalon>:/demos/documentviewer/images/qt-logo.png</normalon>:/demos/documentviewer/images/qt-logo.png</iconset> </property> <property name="text"> <string>About Qt</string> @@ -224,7 +226,7 @@ <normaloff>.</normaloff>.</iconset> </property> <property name="text"> - <string>Open</string> + <string>Recently opened...</string> </property> <property name="shortcut"> <string>Meta+R</string> @@ -232,7 +234,8 @@ </action> <action name="actionQuit"> <property name="icon"> - <iconset theme="application-exit"/> + <iconset theme="application-exit"> + <normaloff>.</normaloff>.</iconset> </property> <property name="text"> <string>Quit</string> @@ -246,8 +249,7 @@ </action> </widget> <resources> - <include location="../../../../../build/dev/qtdoc/examples/demos/documentviewer/.rcc/documentviewer.qrc"/> - <include location="../../../../../build/dev/qthttpserver/examples/httpserver/simple/.rcc/assets.qrc"/> + <include location="../../../../../../build/dev/qtdoc/examples/demos/documentviewer/app/.rcc/documentviewer.qrc"/> </resources> <connections> <connection> diff --git a/examples/demos/documentviewer/app/recentfilemenu.cpp b/examples/demos/documentviewer/app/recentfilemenu.cpp new file mode 100644 index 00000000..26713860 --- /dev/null +++ b/examples/demos/documentviewer/app/recentfilemenu.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "recentfilemenu.h" +#include "recentfiles.h" + +#include <QAction> +#include <QObject> +#include <QWidget> + +RecentFileMenu::RecentFileMenu(QWidget *parent, RecentFiles *recent) : + QMenu(parent), m_recentFiles(recent) +{ + Q_ASSERT(recent); + connect(m_recentFiles, &RecentFiles::changed, this, &RecentFileMenu::updateList); + connect(m_recentFiles, &QObject::destroyed, this, &QObject::deleteLater); + updateList(); +} + +void RecentFileMenu::updateList() +{ + QList<QAction *> acts = actions(); + qDeleteAll(acts); + + if (m_recentFiles->isEmpty()) { + addAction(tr("<no recent files>")); + return; + } + + for (const QString &fileName : m_recentFiles->recentFiles()) { + QAction *action = addAction(fileName); + connect(action, &QAction::triggered, this, [&](){ + QAction *action = qobject_cast<QAction *>(sender()); + Q_ASSERT(action); + emit fileOpened(action->text()); + }); + } +} diff --git a/examples/demos/documentviewer/app/recentfilemenu.h b/examples/demos/documentviewer/app/recentfilemenu.h new file mode 100644 index 00000000..2c90dbe9 --- /dev/null +++ b/examples/demos/documentviewer/app/recentfilemenu.h @@ -0,0 +1,28 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef RECENTFILEMENU_H +#define RECENTFILEMENU_H + +#include <QMenu> + +class RecentFiles; +class QAction; +class RecentFileMenu : public QMenu +{ + Q_OBJECT + +public: + explicit RecentFileMenu(QWidget *parent, RecentFiles *recent); + +signals: + void fileOpened(const QString &fileName); + +private slots: + void updateList(); + +private: + RecentFiles *m_recentFiles; +}; + +#endif // RECENTFILEMENU_H diff --git a/examples/demos/documentviewer/app/recentfiles.cpp b/examples/demos/documentviewer/app/recentfiles.cpp new file mode 100644 index 00000000..2a26c131 --- /dev/null +++ b/examples/demos/documentviewer/app/recentfiles.cpp @@ -0,0 +1,169 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "recentfiles.h" +#include <QFileInfo> +#include <QSettings> + +RecentFiles::RecentFiles(QObject *parent) : QObject(parent) +{ +} + +void RecentFiles::clear() +{ + if (isEmpty()) + return; + + QStringList::clear(); + emit countChanged(0); + emit listCleared(); +} + +void RecentFiles::addFile(const QString &fileName, EmitPolicy policy) +{ + if (!testFileAccess(fileName)) + return; + + // Remember size, as cleanup can result in a change without size change + const qsizetype c = count(); + + // Clean dangling and duplicate files + bool duplicateFound = false; + for (const QString &file : *this) { + if (!testFileAccess(file)) { + removeFile(file, RemoveReason::Dangling); + } else if (file == fileName) { + removeFile(file, RemoveReason::Duplicate); + duplicateFound = true; + } + } + + // Cut tail + while (count() > m_maxFiles) + removeFile((count() - 1), RemoveReason::TailCut); + + prepend(fileName); + + switch (policy) { + case EmitPolicy::NeverEmit: + return; + + case EmitPolicy::AllwaysEmit: + emit changed(); + emit fileAdded(fileName); + emit countChanged(count()); + return; + + case EmitPolicy::EmitWhenChanged: + emit changed(); + if (!duplicateFound) + emit fileAdded(fileName); + + if (c != count()) + emit countChanged(count()); + + return; + } +} + +void RecentFiles::addFiles(const QStringList &files) +{ + if (files.isEmpty()) + return; + + if (files.count() == 1) { + addFile(files.at(0)); + return; + } + + const auto &c = count(); + + for (const auto &file : files) + addFile(file, EmitPolicy::NeverEmit); + + emit filesAdded(files); + emit changed(); + if (count() != c) + emit countChanged(count()); +} + +// Test if file exists and can be opened +bool RecentFiles::testFileAccess(const QString &fileName) const +{ + QFileInfo info(fileName); + if (!info.isFile()) + return false; + + switch (m_openMode) { + case QIODevice::ReadOnly: + if (!info.isReadable()) + return false; + break; + case QIODevice::ReadWrite: + if (!(info.isReadable() && info.isWritable())) + return false; + break; + case QIODevice::WriteOnly: + if (!info.isWritable()) + return false; + break; + } + return true; +} + +void RecentFiles::removeFile(qsizetype index, RemoveReason reason) +{ + if (index < 0 || index >= count()) + return; + + const QString &fileName = at(index); + remove(index); + + // No emit for duplicate removal, add emits changed later. + if (reason == RemoveReason::Duplicate) + return; + + emit fileRemoved(fileName, reason); + emit changed(); +} + +void RecentFiles::saveSettings(QSettings &settings, const QString &key) const +{ + settings.beginGroup(key); + settings.setValue(s_maxFiles, maxFiles()); + settings.setValue(s_openMode, static_cast<int>(openMode())); + if (!isEmpty()) { + settings.beginWriteArray(s_fileNames, count()); + for (int index = 0; index < count(); ++index) { + settings.setArrayIndex(index); + settings.setValue(s_file, at(index)); + } + settings.endArray(); + } + settings.endGroup(); +} + +bool RecentFiles::restoreFromSettings(QSettings &settings, const QString &key) +{ + settings.beginGroup(key); + const qsizetype mxFiles = settings.value(s_maxFiles, maxFiles()).toLongLong(); + const auto mode = qvariant_cast<QIODevice::OpenMode>(settings.value(s_openMode, + static_cast<int>(openMode())).toInt()); + setMaxFiles(mxFiles); + setOpenMode(mode); + QStringList::clear(); // clear list without emitting + const int numberFiles = settings.beginReadArray(s_fileNames); + for (int index = 0; index < numberFiles; ++index) { + settings.setArrayIndex(index); + const QString absoluteFilePath = settings.value(s_file).toString(); + addFile(absoluteFilePath, EmitPolicy::NeverEmit); + } + settings.endArray(); + settings.endGroup(); + if (count() > 0) { + emit settingsRestored(count()); + emit changed(); + } + + return true; +} diff --git a/examples/demos/documentviewer/app/recentfiles.h b/examples/demos/documentviewer/app/recentfiles.h new file mode 100644 index 00000000..d9bb2eb8 --- /dev/null +++ b/examples/demos/documentviewer/app/recentfiles.h @@ -0,0 +1,81 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef RECENTFILES_H +#define RECENTFILES_H + +#include <QMenu> +#include <QFile> + +class QSettings; +class RecentFiles : public QObject, private QStringList +{ + Q_OBJECT +public: + enum class RemoveReason { + Reset, + Dangling, + TailCut, + RemovedManually, + Duplicate + }; + Q_ENUM(RemoveReason) + + explicit RecentFiles(QObject *parent); + + // Access to QStringList member functions + qsizetype count() const {return QStringList::count(); }; + const QStringList recentFiles() const {return *this; } + bool isEmpty() const { return QStringList::isEmpty(); } + + // Properties + qsizetype maxFiles() const { return m_maxFiles; } + void setMaxFiles(qsizetype maxFiles) { m_maxFiles = maxFiles; } + QIODevice::OpenMode openMode() const { return m_openMode; } + void setOpenMode(QIODevice::OpenMode mode) { m_openMode = mode; } + +public slots: + void addFile(const QString &fileName) {addFile(fileName, EmitPolicy::EmitWhenChanged); } + void addFiles(const QStringList &fileNames); + void removeFile(const QString &fileName) {removeFile(indexOf(fileName)); } + void removeFile(qsizetype index) {removeFile(index, RemoveReason::RemovedManually); } + void saveSettings(QSettings &settings, const QString &key) const; + bool restoreFromSettings(QSettings &settings, const QString &key); + void clear(); + +signals: + void fileAdded(const QString &fileName); + void filesAdded(const QStringList &files); + void fileRemoved(const QString &fileName, RecentFiles::RemoveReason reason); + void countChanged(int count); + void listCleared(); + void settingsRestored(qsizetype count); + void changed(); + +private: + bool testFileAccess(const QString &fileName) const; + + // Private removers with reason + void removeFile(qsizetype index, RemoveReason reason); + void removeFile(const QString &fileName, RemoveReason reason) {removeFile(indexOf(fileName), reason); } + + // Private adder with emit policy + enum class EmitPolicy { + AllwaysEmit, + EmitWhenChanged, + NeverEmit + }; + + void addFile(const QString &fileName, EmitPolicy policy); + + qsizetype m_maxFiles = 10; + QIODevice::OpenMode m_openMode = QIODevice::ReadOnly; + + // Constexprs for settings + static constexpr QLatin1StringView s_maxFiles = QLatin1StringView("maxFiles"); + static constexpr QLatin1StringView s_openMode = QLatin1StringView("openMode"); + static constexpr QLatin1StringView s_fileNames = QLatin1StringView("fileNames"); + static constexpr QLatin1StringView s_file = QLatin1StringView("file"); +}; + +#endif // RECENTFILES_H diff --git a/examples/demos/documentviewer/app/viewerfactory.cpp b/examples/demos/documentviewer/app/viewerfactory.cpp new file mode 100644 index 00000000..cb5023bd --- /dev/null +++ b/examples/demos/documentviewer/app/viewerfactory.cpp @@ -0,0 +1,173 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include <QWidget> +#include <QMimeDatabase> +#include <QMimeType> +#include <QApplication> +#include <QPluginLoader> +#include <QDir> +#include "abstractviewer.h" +#include "viewerfactory.h" +#include "viewerinterfaces.h" +#include <concepts> + +ViewerFactory::ViewerFactory(QWidget *displayWidget, QMainWindow *mainWindow, DefaultPolicy policy) + : m_defaultPolicy(policy), + m_displayWidget(displayWidget), + m_mainWindow(mainWindow) +{ + Q_ASSERT(m_displayWidget); + Q_ASSERT(m_mainWindow); + loadViewerPlugins(); +} + +ViewerFactory::~ViewerFactory() +{ + unload(); +} + +AbstractViewer *ViewerFactory::viewer(QFile *file) const +{ + Q_ASSERT(file); + + const QFileInfo info(*file); + QMimeDatabase db; + const auto mimeType = db.mimeTypeForFile(info); + + AbstractViewer *viewer = ViewerFactory::viewer(mimeType); + if (!viewer) { + qWarning() << "Mime type" << mimeType.name() << "not supported."; + return nullptr; + } + + viewer->init(file, m_displayWidget, m_mainWindow); + return viewer; +} + +void ViewerFactory::loadViewerPlugins() +{ + if (!m_viewers.isEmpty()) + return; + + // Load static plugins + const QObjectList &staticPlugins = QPluginLoader::staticInstances(); + for (auto *plugin : staticPlugins) + addViewer(plugin); + + // Load shared plugins + QDir pluginsDir = QDir(QApplication::applicationDirPath()); + +#if defined(Q_OS_WIN) + if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release") + pluginsDir.cdUp(); +#elif defined(Q_OS_DARWIN) + if (pluginsDir.dirName() == "macOS") { + pluginsDir.cdUp(); + pluginsDir.cdUp(); + pluginsDir.cdUp(); + } +#endif + const auto entryList = pluginsDir.entryList(QDir::Files); + for (const QString &fileName : entryList) { + QPluginLoader loader(pluginsDir.absoluteFilePath(fileName)); + QObject *plugin = loader.instance(); + if (plugin) + addViewer(plugin); +#if 0 + else + qDebug() << loader.errorString(); +#endif + } +} + +void ViewerFactory::unload() +{ + qDeleteAll(viewers()); + m_viewers.clear(); +} + +void ViewerFactory::addViewer(QObject *viewerObject) +{ + auto *interface = qobject_cast<ViewerInterface *>(viewerObject); + if (!interface) + return; + + // Set custom default viewer + if (interface->viewer()->isDefaultViewer()) + m_defaultViewer = interface->viewer(); + + m_viewers.insert(interface->viewerName(), interface->viewer()); +} + +QStringList ViewerFactory::viewerNames(bool showDefault) const +{ + if (!showDefault) + return m_viewers.keys(); + + QStringList list; + for (auto it = m_viewers.constBegin(); it != m_viewers.constEnd(); ++it) { + QString name = it.key(); + if ((m_defaultViewer && it.value()->isDefaultViewer()) + || (!m_defaultViewer && it.key() == "TxtViewer")) { + name += "(default)"; + } + list.append(name); + } + return list; +} + +ViewerFactory::ViewerList ViewerFactory::viewers() const +{ + return m_viewers.values(); +} + +AbstractViewer *ViewerFactory::findViewer(const QString &viewerName) const +{ + const ViewerList &viewerList = viewers(); + for (auto *viewer : viewerList) { + if (viewer->viewerName() == viewerName) + return viewer; + } + qWarning() << "Plugin" << viewerName << "not loaded."; + return nullptr; +} + +AbstractViewer *ViewerFactory::viewer(const QMimeType &mimeType) const +{ + const ViewerList &viewerList = viewers(); + + for (AbstractViewer *viewer : viewerList) { + for (const QString &type : viewer->supportedMimeTypes()) { + if (mimeType.inherits(type)) + return viewer; + } + } + + return defaultViewer(); +} + +AbstractViewer *ViewerFactory::defaultViewer() const +{ + switch (m_defaultPolicy) { + case DefaultPolicy::NeverDefault: + return nullptr; + case DefaultPolicy::DefaultToCustomViewer: + return m_defaultViewer ? m_defaultViewer : findViewer("TxtViewer"); + case DefaultPolicy::DefaultToTxtViewer: + return findViewer("TxtViewer"); + } + Q_UNREACHABLE(); +} + +QStringList ViewerFactory::supportedMimeTypes() const +{ + static QStringList mimeTypes; + if (!mimeTypes.isEmpty()) + return mimeTypes; + + const ViewerList &viewerList = viewers(); + for (auto viewer : viewerList) + mimeTypes.append(viewer->supportedMimeTypes()); + return mimeTypes; +} diff --git a/examples/demos/documentviewer/app/viewerfactory.h b/examples/demos/documentviewer/app/viewerfactory.h new file mode 100644 index 00000000..4022ea58 --- /dev/null +++ b/examples/demos/documentviewer/app/viewerfactory.h @@ -0,0 +1,57 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef VIEWERFACTORY_H +#define VIEWERFACTORY_H + +#include <QString> +#include <QMimeType> +#include <QObject> +#include <QMap> + +class AbstractViewer; +class QWidget; +class QMainWindow; +class Questions; +class QFile; +class ViewerFactory +{ +public: + enum class DefaultPolicy { + NeverDefault, + DefaultToTxtViewer, + DefaultToCustomViewer + }; + + explicit ViewerFactory(QWidget *displayWidget, QMainWindow *mainWindow, + DefaultPolicy policy = DefaultPolicy::DefaultToTxtViewer); + ~ViewerFactory(); + + DefaultPolicy defaultPolicy() const { return m_defaultPolicy; } + void setDefaultPolicy(DefaultPolicy policy) { m_defaultPolicy = policy; } + + AbstractViewer *viewer(QFile *file) const; + + + typedef QMap<QString, AbstractViewer *> ViewerMap; + typedef QList<AbstractViewer *> ViewerList; + QStringList viewerNames(bool showDefault = false) const; + ViewerList viewers() const; + AbstractViewer *findViewer(const QString &viewerName) const; + AbstractViewer *defaultViewer() const; + QStringList supportedMimeTypes() const; + +private: + DefaultPolicy m_defaultPolicy; + QWidget *m_displayWidget; + QMainWindow *m_mainWindow; + ViewerMap m_viewers; + AbstractViewer *m_defaultViewer = nullptr; + + void loadViewerPlugins(); + void addViewer(QObject *viewerObject); + AbstractViewer *viewer(const QMimeType &type) const; + void unload(); +}; + +#endif // VIEWERFACTORY_H diff --git a/examples/demos/documentviewer/app/viewerinterfaces.h b/examples/demos/documentviewer/app/viewerinterfaces.h new file mode 100644 index 00000000..bdeaac97 --- /dev/null +++ b/examples/demos/documentviewer/app/viewerinterfaces.h @@ -0,0 +1,39 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef VIEWERINTERFACES_H +#define VIEWERINTERFACES_H + +#include "abstractviewer.h" +#include <QtPlugin> +#include <QWidget> + +QT_BEGIN_NAMESPACE +class QFile; +class QMainWindow; +class QWidget; +class QTabWidget; +class QPrinter; +QT_END_NAMESPACE + +class ViewerInterface : public AbstractViewer +{ +public: + virtual ~ViewerInterface() = default; + virtual QString viewerName() const override = 0; + virtual QByteArray saveState() const override = 0; + virtual bool restoreState(QByteArray &) override = 0; + virtual bool supportsOverview() const override = 0; + virtual bool hasContent() const override = 0; +#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT + virtual void printDocument(QPrinter *) const override = 0; + virtual QStringList supportedMimeTypes() const override = 0; +#endif +}; + +QT_BEGIN_NAMESPACE +#define ViewerInterface_iid "org.qt-project.Qt.Examples.DocumentViewer.ViewerInterface/1.0" +Q_DECLARE_INTERFACE(ViewerInterface, ViewerInterface_iid) +QT_END_NAMESPACE + +#endif //VIEWERINTERFACES_H diff --git a/examples/demos/documentviewer/doc/src/documentviewer.qdoc b/examples/demos/documentviewer/doc/src/documentviewer.qdoc index e9607a6f..8462e5a4 100644 --- a/examples/demos/documentviewer/doc/src/documentviewer.qdoc +++ b/examples/demos/documentviewer/doc/src/documentviewer.qdoc @@ -27,14 +27,14 @@ To create an executable, we use a standard main.cpp file. First, we set the application's organization name: - \quotefromfile demos/documentviewer/main.cpp + \quotefromfile demos/documentviewer/app/main.cpp \skipto int main \printuntil QApplication::set \endsection1 \section1 Creating an application and showing the main window - \quotefromfile demos/documentviewer/main.cpp + \quotefromfile demos/documentviewer/app/main.cpp \skipto QApplication app \printuntil } \endsection1 @@ -44,13 +44,17 @@ The class constructor initializes the user interface created in Qt Designer. It links the actions for opening a file and the about dialog to their implementation. - \quotefromfile demos/documentviewer/mainwindow.cpp + \quotefromfile demos/documentviewer/app/mainwindow.cpp \skipto ui->setupUi \printuntil triggered The \c mainwindow.ui file provides a QTabWidget on the left, where bookmarks and thumbnails can be displayed. It provides a QScrollArea on the right, where the viewed file contents are - displayed. + \printuntil showMenu); + + If a file is opened, the {File} class (inheriting from {QFile}) automatically determines + the FileType used in this application. If no valid file type could be established, the user + is asked, if it should be opened as plain text. The ViewerFactory class provides a static method to create a file type specific viewer. @@ -62,7 +66,7 @@ virtual restoreState method. Afterwards, the standard UI assets are passed to the viewer and it's display widget is displayed in the main scroll area. - \quotefromfile demos/documentviewer/mainwindow.cpp + \quotefromfile demos/documentviewer/app/mainwindow.cpp \skipuntil void MainWindow::openFile \skipto m_viewer->initViewer \printuntil } @@ -74,7 +78,7 @@ displayed, the main window and the user questions. Depending on the file's mime type, it creates an appropriate document viewer. - \quotefromfile demos/documentviewer/mainwindow.cpp + \quotefromfile demos/documentviewer/app/mainwindow.cpp \skipto AbstractViewer \printuntil } \endsection1 @@ -159,40 +163,40 @@ HoverWatcher inherits from QObject and the QWidget watched becomes the instance's parent. An event filter is used to intercept the hover events without consuming them. - \quotefromfile demos/documentviewer/hoverwatcher.cpp + \quotefromfile demos/documentviewer/plugins/pdfviewer/hoverwatcher.cpp \skipto HoverWatcher::HoverWatcher \printuntil } The actions watched are represented in an enum. - \quotefromfile demos/documentviewer/hoverwatcher.h + \quotefromfile demos/documentviewer/plugins/pdfviewer/hoverwatcher.h \skipto enum HoverAction \printuntil }; Static methods create watchers, check their existence for a specific QWidget or dismiss a watcher. - \quotefromfile demos/documentviewer/hoverwatcher.h + \quotefromfile demos/documentviewer/plugins/pdfviewer/hoverwatcher.h \skipto static HoverWatcher \printuntil static void dismiss A cursor shape can be specified or unset for each HoverAction. If no cursor shape is specified for an action, the application's override cursor will be restored when it occurs. - \quotefromfile demos/documentviewer/hoverwatcher.h + \quotefromfile demos/documentviewer/plugins/pdfviewer/hoverwatcher.h \skipto public slots \printuntil void unSetCursorShape The mouseButtons property specifies, which mouse buttons to consider for the MousePress action. - \quotefromfile demos/documentviewer/hoverwatcher.h + \quotefromfile demos/documentviewer/plugins/pdfviewer/hoverwatcher.h \skipuntil public slots \skipto setMouseButtons \printuntil setMouseButton( Action specific signals are emitted when an action has been processed. - \quotefromfile demos/documentviewer/hoverwatcher.h + \quotefromfile demos/documentviewer/plugins/pdfviewer/hoverwatcher.h \skipto signals \printuntil left(); @@ -202,6 +206,72 @@ void hoverAction(HoverAction action); \endcode \endsection2 + + \section2 The {RecentFiles} class + + The class is a QStringList, specialized to manage a list of recently opened files. + + \quotefromfile demos/documentviewer/recentfiles.cpp + \skipto RecentFiles::RecentFiles + \printuntil } + + It provides slots to add a single or multiple files, by passing their path or a list + of paths as an argument. A file is added, if the path leads to a valid file. + If a file already exists in the list of recent files, it is removed from its original position + and added on the top. + + \quotefromfile demos/documentviewer/recentfiles.h + \skipto public slots + \printuntil addFiles + + Files can be removed by name or by index. + + \quotefromfile demos/documentviewer/recentfiles.h + \skipuntil public slots + \skipto removeFile + \printuntil addFiles + + Slots are available to save and restore from {QSettings}. + Files restored from settings are ignored, if they no longer exist. + + \quotefromfile demos/documentviewer/recentfiles.h + \skipuntil public slots + \skipto saveSettings + \printuntil restoreFromSettings + + The maxFiles property manages the maximum amount of recent files to be remebered (default: 10). + + \code + qsizetype maxFiles(); + void setMaxFiles(qsizetype maxFiles); + \endcode + + {RecentFiles} verifies a file can be opened in {openMode}, before adding it. + + \code + void setOpenMode(QIODevice::OpenMode mode); + QIODevice::OpenMode openMode() const; + \endcode + \endsection2 + + \section2 The {RecentFileMenu} class + + The {RecentFileMenu} class is a QMenu, specialized as a submenu to display a \l{RecentFiles} + object as a submenu. + + Its constructor takes a parent widget, usually and QAction or a QMenu. + Its fileOpened signal passes a QString argument with the absolute file name, when the + application user has selected a recent file from the list. + + \note + A {RecentFileMenu} is deleted either with its parent widget, or with the RecentFiles object + passed to its constructor. + + \quotefromfile demos/documentviewer/recentfilemenu.h + \skipuntil class RecentFileMenu + \printuntil void fileOpened + + \endsection2 \endsection1 */ diff --git a/examples/demos/documentviewer/plugins/CMakeLists.txt b/examples/demos/documentviewer/plugins/CMakeLists.txt new file mode 100644 index 00000000..60d8b190 --- /dev/null +++ b/examples/demos/documentviewer/plugins/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +add_subdirectory(jsonviewer) +add_subdirectory(pdfviewer) +add_subdirectory(txtviewer) diff --git a/examples/demos/documentviewer/plugins/jsonviewer/CMakeLists.txt b/examples/demos/documentviewer/plugins/jsonviewer/CMakeLists.txt new file mode 100644 index 00000000..ca61e574 --- /dev/null +++ b/examples/demos/documentviewer/plugins/jsonviewer/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_add_plugin(jsonviewer + CLASS_NAME JsonViewer + jsonviewer.cpp jsonviewer.h + ../../app/abstractviewer.h ../../app/abstractviewer.cpp +) + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets + OPTIONAL_COMPONENTS PrintSupport) + +set_target_properties(jsonviewer PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/app" +) + +target_include_directories(jsonviewer PRIVATE + ../../app +) + +target_link_libraries(jsonviewer PRIVATE + Qt6::Core + Qt6::Gui + Qt6::Widgets +) + +if(TARGET Qt6::PrintSupport) + target_link_libraries(jsonviewer PRIVATE Qt6::PrintSupport) +endif() + +install(TARGETS jsonviewer + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}/plugins" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}/plugins" +) + diff --git a/examples/demos/documentviewer/jsonviewer.cpp b/examples/demos/documentviewer/plugins/jsonviewer/jsonviewer.cpp index 3b7b4a91..55160a56 100644 --- a/examples/demos/documentviewer/jsonviewer.cpp +++ b/examples/demos/documentviewer/plugins/jsonviewer/jsonviewer.cpp @@ -18,14 +18,14 @@ #include <QLineEdit> #include <QLabel> #include <QApplication> -#ifdef QT_ABSTRACTVIEWER_PRINTSUPPORT +#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT #include <QPrinter> #include <QPainter> #endif -JsonViewer::JsonViewer(QFile *file, QWidget *parent, QMainWindow *mainWindow) : - AbstractViewer(file, new QTreeView(parent), mainWindow) +void JsonViewer::init(QFile *file, QWidget *parent, QMainWindow *mainWindow) { + AbstractViewer::init(file, new QTreeView(parent), mainWindow); m_tree = qobject_cast<QTreeView *>(widget()); connect(this, &AbstractViewer::uiInitialized, this, &JsonViewer::setupJsonUi); } @@ -35,6 +35,11 @@ JsonViewer::~JsonViewer() delete m_toplevel; } +QStringList JsonViewer::supportedMimeTypes() const +{ + return {"application/json"}; +} + void JsonViewer::setupJsonUi() { // Build Menus and toolbars @@ -268,7 +273,7 @@ bool JsonViewer::hasContent() const return !m_root.isEmpty(); } -#if defined(QT_ABSTRACTVIEWER_PRINTSUPPORT) +#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT void JsonViewer::printDocument(QPrinter *printer) const { if (!hasContent()) @@ -278,7 +283,7 @@ void JsonViewer::printDocument(QPrinter *printer) const doc.print(printer); } -#endif // QT_ABSTRACTVIEWER_PRINTSUPPORT +#endif // QT_DOCUMENTVIEWER_PRINTSUPPORT QByteArray JsonViewer::saveState() const { diff --git a/examples/demos/documentviewer/jsonviewer.h b/examples/demos/documentviewer/plugins/jsonviewer/jsonviewer.h index c9291cd2..ae706020 100644 --- a/examples/demos/documentviewer/jsonviewer.h +++ b/examples/demos/documentviewer/plugins/jsonviewer/jsonviewer.h @@ -4,7 +4,7 @@ #ifndef JSONVIEWER_H #define JSONVIEWER_H -#include "abstractviewer.h" +#include "viewerinterfaces.h" #include <QJsonValue> #include <QJsonDocument> #include <QAbstractItemModel> @@ -15,21 +15,25 @@ class QTreeView; class QListWidget; class QListWidgetItem; class QLineEdit; +class QPrinter; -class JsonViewer : public AbstractViewer +class JsonViewer : public ViewerInterface { - Q_GADGET + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.DocumentViewer.ViewerInterface/1.0" FILE "jsonviewer.json") + Q_INTERFACES(ViewerInterface) public: - JsonViewer(QFile *file, QWidget *parent, QMainWindow *mainWindow); ~JsonViewer() override; + void init(QFile *file, QWidget *parent, QMainWindow *mainWindow) override; QString viewerName() const override { return staticMetaObject.className(); }; + QStringList supportedMimeTypes() const override; QByteArray saveState() const override; bool restoreState(QByteArray &) override; bool supportsOverview() const override { return true; } bool hasContent() const override; -#if defined(QT_ABSTRACTVIEWER_PRINTSUPPORT) +#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT protected: void printDocument(QPrinter *printer) const override; #endif // QT_ABSTRACTVIEWER_PRINTSUPPORT diff --git a/examples/demos/documentviewer/plugins/jsonviewer/jsonviewer.json b/examples/demos/documentviewer/plugins/jsonviewer/jsonviewer.json new file mode 100644 index 00000000..224a438c --- /dev/null +++ b/examples/demos/documentviewer/plugins/jsonviewer/jsonviewer.json @@ -0,0 +1 @@ +{ "Keys": [ "jsonviewer" ] } diff --git a/examples/demos/documentviewer/plugins/pdfviewer/CMakeLists.txt b/examples/demos/documentviewer/plugins/pdfviewer/CMakeLists.txt new file mode 100644 index 00000000..0c8241f8 --- /dev/null +++ b/examples/demos/documentviewer/plugins/pdfviewer/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets PdfWidgets + OPTIONAL_COMPONENTS PrintSupport) + +qt_add_plugin(pdfviewer + CLASS_NAME PdfViewer + pdfviewer.cpp pdfviewer.h + zoomselector.cpp zoomselector.h + hoverwatcher.cpp hoverwatcher.h + ../../app/abstractviewer.h ../../app/abstractviewer.cpp +) + +set_target_properties(pdfviewer PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/app" +) + +target_include_directories(pdfviewer PRIVATE + ../../app + .. +) + +target_link_libraries(pdfviewer PRIVATE + Qt6::Core + Qt6::Gui + Qt6::Widgets + Qt6::PdfWidgets +) + +if(TARGET Qt6::PrintSupport) + target_link_libraries(pdfviewer PRIVATE Qt6::PrintSupport) +endif() + +install(TARGETS pdfviewer + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}/plugins" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}/plugins" +) + diff --git a/examples/demos/documentviewer/hoverwatcher.cpp b/examples/demos/documentviewer/plugins/pdfviewer/hoverwatcher.cpp index 3c0ffe1e..3c0ffe1e 100644 --- a/examples/demos/documentviewer/hoverwatcher.cpp +++ b/examples/demos/documentviewer/plugins/pdfviewer/hoverwatcher.cpp diff --git a/examples/demos/documentviewer/hoverwatcher.h b/examples/demos/documentviewer/plugins/pdfviewer/hoverwatcher.h index 8ddfcd1f..8ddfcd1f 100644 --- a/examples/demos/documentviewer/hoverwatcher.h +++ b/examples/demos/documentviewer/plugins/pdfviewer/hoverwatcher.h diff --git a/examples/demos/documentviewer/pdfviewer.cpp b/examples/demos/documentviewer/plugins/pdfviewer/pdfviewer.cpp index 669b9371..0d21c0ea 100644 --- a/examples/demos/documentviewer/pdfviewer.cpp +++ b/examples/demos/documentviewer/plugins/pdfviewer/pdfviewer.cpp @@ -25,20 +25,21 @@ #include <QEvent> #include <QMouseEvent> #include <QScroller> -#ifdef QT_ABSTRACTVIEWER_PRINTSUPPORT +#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT #include <QPrinter> #include <QPainter> #endif Q_LOGGING_CATEGORY(lcExample, "qt.examples.pdfviewer") -PdfViewer::PdfViewer(QFile *file, QWidget *parent, QMainWindow *mainWindow) : - AbstractViewer(file, new QPdfView(parent), mainWindow), m_document(new QPdfDocument(this)) - +void PdfViewer::init(QFile *file, QWidget *parent, QMainWindow *mainWindow) { + AbstractViewer::init(file, new QPdfView(parent), mainWindow); + m_document = new QPdfDocument(this); m_pdfView = qobject_cast<QPdfView *>(widget()); connect(this, &AbstractViewer::uiInitialized, this, &PdfViewer::initPdfViewer); } + PdfViewer::~PdfViewer() { delete m_pages; @@ -46,6 +47,11 @@ PdfViewer::~PdfViewer() delete m_document; } +QStringList PdfViewer::supportedMimeTypes() const +{ + return {"application/pdf"}; +} + void PdfViewer::initPdfViewer() { m_toolBar = addToolBar("PDF"); @@ -154,7 +160,7 @@ bool PdfViewer::hasContent() const return m_document ? m_document->pageCount() > 0 : false; } -#if defined(QT_ABSTRACTVIEWER_PRINTSUPPORT) +#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT void PdfViewer::printDocument(QPrinter *printer) const { if (!hasContent()) @@ -172,7 +178,7 @@ void PdfViewer::printDocument(QPrinter *printer) const } painter.end(); } -#endif // QT_ABSTRACTVIEWER_PRINTSUPPORT +#endif // QT_DOCUMENTVIEWER_PRINTSUPPORT void PdfViewer::bookmarkSelected(const QModelIndex &index) { diff --git a/examples/demos/documentviewer/pdfviewer.h b/examples/demos/documentviewer/plugins/pdfviewer/pdfviewer.h index d70ca81c..e4fe1a67 100644 --- a/examples/demos/documentviewer/pdfviewer.h +++ b/examples/demos/documentviewer/plugins/pdfviewer/pdfviewer.h @@ -4,7 +4,7 @@ #ifndef PDFVIEWER_H #define PDFVIEWER_H -#include "abstractviewer.h" +#include "viewerinterfaces.h" #include <QLoggingCategory> Q_DECLARE_LOGGING_CATEGORY(lcExample) @@ -17,22 +17,25 @@ class QListView; class QTabWidget; class QTreeView; class ZoomSelector; -class PdfViewer : public AbstractViewer +class PdfViewer : public ViewerInterface { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.DocumentViewer.ViewerInterface" FILE "pdfviewer.json") + Q_INTERFACES(ViewerInterface) public: - PdfViewer(QFile *file, QWidget *parent, QMainWindow *mainWindow); - ~PdfViewer() override; + void init(QFile *file, QWidget *parent, QMainWindow *mainWindow) override; QString viewerName() const override { return staticMetaObject.className(); }; + QStringList supportedMimeTypes() const override; bool supportsOverview() const override { return true; } bool hasContent() const override; QByteArray saveState() const override { return QByteArray(); } bool restoreState(QByteArray &) override { return true; } -#if defined(QT_ABSTRACTVIEWER_PRINTSUPPORT) +#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT protected: void printDocument(QPrinter *printer) const override; -#endif // QT_ABSTRACTVIEWER_PRINTSUPPORT +#endif // QT_DOCUMENTVIEWER_PRINTSUPPORT public slots: void openPdfFile(); @@ -58,10 +61,10 @@ private: const qreal zoomMultiplier = qSqrt(2.0); static constexpr int maxIconWidth = 200; QToolBar *m_toolBar = nullptr; - ZoomSelector *m_zoomSelector; - QPdfPageSelector *m_pageSelector; - QPdfDocument *m_document; - QPdfView *m_pdfView; + ZoomSelector *m_zoomSelector = nullptr; + QPdfPageSelector *m_pageSelector = nullptr; + QPdfDocument *m_document = nullptr; + QPdfView *m_pdfView = nullptr; QAction *m_actionForward = nullptr; QAction *m_actionBack = nullptr; QTreeView *m_bookmarks = nullptr; diff --git a/examples/demos/documentviewer/plugins/pdfviewer/pdfviewer.json b/examples/demos/documentviewer/plugins/pdfviewer/pdfviewer.json new file mode 100644 index 00000000..19b3bdcb --- /dev/null +++ b/examples/demos/documentviewer/plugins/pdfviewer/pdfviewer.json @@ -0,0 +1 @@ +{ "Keys": [ "pdfviewer" ] } diff --git a/examples/demos/documentviewer/zoomselector.cpp b/examples/demos/documentviewer/plugins/pdfviewer/zoomselector.cpp index 2994b567..2994b567 100644 --- a/examples/demos/documentviewer/zoomselector.cpp +++ b/examples/demos/documentviewer/plugins/pdfviewer/zoomselector.cpp diff --git a/examples/demos/documentviewer/zoomselector.h b/examples/demos/documentviewer/plugins/pdfviewer/zoomselector.h index 7c35bdab..7c35bdab 100644 --- a/examples/demos/documentviewer/zoomselector.h +++ b/examples/demos/documentviewer/plugins/pdfviewer/zoomselector.h diff --git a/examples/demos/documentviewer/plugins/txtviewer/CMakeLists.txt b/examples/demos/documentviewer/plugins/txtviewer/CMakeLists.txt new file mode 100644 index 00000000..7e0730a1 --- /dev/null +++ b/examples/demos/documentviewer/plugins/txtviewer/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets + OPTIONAL_COMPONENTS PrintSupport) + +qt_add_plugin(txtviewer + CLASS_NAME TxtViewer + txtviewer.cpp txtviewer.h + ../../app/abstractviewer.h ../../app/abstractviewer.cpp +) + +set_target_properties(txtviewer PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/app" +) + +target_include_directories(txtviewer PRIVATE + ../../app +) + +target_link_libraries(txtviewer PRIVATE + Qt6::Core + Qt6::Gui + Qt6::Widgets +) + +if(TARGET Qt6::PrintSupport) + target_link_libraries(txtviewer PRIVATE Qt6::PrintSupport) +endif() + +install(TARGETS jsonviewer + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}/plugins" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}/plugins" +) + diff --git a/examples/demos/documentviewer/txtviewer.cpp b/examples/demos/documentviewer/plugins/txtviewer/txtviewer.cpp index b392c985..cfe8d809 100644 --- a/examples/demos/documentviewer/txtviewer.cpp +++ b/examples/demos/documentviewer/plugins/txtviewer/txtviewer.cpp @@ -13,14 +13,14 @@ #include <QMetaObject> #include <QScrollBar> #include <QPainter> -#ifdef QT_ABSTRACTVIEWER_PRINTSUPPORT +#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT #include <QPrinter> #include <QPrintDialog> #endif -TxtViewer::TxtViewer(QFile *file, QWidget *parent, QMainWindow *mainWindow) : - AbstractViewer(file, new QPlainTextEdit(parent), mainWindow) +void TxtViewer::init(QFile *file, QWidget *parent, QMainWindow *mainWindow) { + AbstractViewer::init(file, new QPlainTextEdit(parent), mainWindow); m_textEdit = qobject_cast<QPlainTextEdit *>(widget()); connect(this, &AbstractViewer::uiInitialized, this, &TxtViewer::setupTxtUi); } @@ -29,6 +29,11 @@ TxtViewer::~TxtViewer() { } +QStringList TxtViewer::supportedMimeTypes() const +{ + return {"text/plain"}; +} + void TxtViewer::setupTxtUi() { QMenu *editMenu = addMenu(tr("&Edit")); @@ -119,7 +124,7 @@ bool TxtViewer::hasContent() const return (!m_textEdit->toPlainText().isEmpty()); } -#if defined(QT_ABSTRACTVIEWER_PRINTSUPPORT) +#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT void TxtViewer::printDocument(QPrinter *printer) const { if (!hasContent()) @@ -127,8 +132,7 @@ void TxtViewer::printDocument(QPrinter *printer) const m_textEdit->print(printer); } - -#endif // QT_ABSTRACTVIEWER_PRINTSUPPORT +#endif // QT_DOCUMENTVIEWER_PRINTSUPPORT bool TxtViewer::saveFile(QFile *file) { diff --git a/examples/demos/documentviewer/txtviewer.h b/examples/demos/documentviewer/plugins/txtviewer/txtviewer.h index 2b3ba953..7206d451 100644 --- a/examples/demos/documentviewer/txtviewer.h +++ b/examples/demos/documentviewer/plugins/txtviewer/txtviewer.h @@ -4,28 +4,34 @@ #ifndef TXTVIEWER_H #define TXTVIEWER_H +#include "viewerinterfaces.h" #include "abstractviewer.h" #include <QPointer> class QMainWindow; class QPlainTextEdit; class QLabel; -class TxtViewer : public AbstractViewer +class TxtViewer : public ViewerInterface { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.DocumentViewer.ViewerInterface" FILE "txtviewer.json") + Q_INTERFACES(ViewerInterface) public: - TxtViewer(QFile *file, QWidget *parent, QMainWindow *mainWindow); ~TxtViewer() override; + void init(QFile *file, QWidget *parent, QMainWindow *mainWindow) override; QString viewerName() const override { return staticMetaObject.className(); }; + QStringList supportedMimeTypes() const override; bool saveDocument() override { return saveFile(m_file.get()); }; bool saveDocumentAs() override; bool hasContent() const override; QByteArray saveState() const override { return QByteArray(); } bool restoreState(QByteArray &) override { return true; } + bool supportsOverview() const override { return false; } -#if defined(QT_ABSTRACTVIEWER_PRINTSUPPORT) +#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT protected: void printDocument(QPrinter *printer) const override; -#endif // QT_ABSTRACTVIEWER_PRINTSUPPORT +#endif // QT_DOCUMENTVIEWER_PRINTSUPPORT private slots: void setupTxtUi(); diff --git a/examples/demos/documentviewer/plugins/txtviewer/txtviewer.json b/examples/demos/documentviewer/plugins/txtviewer/txtviewer.json new file mode 100644 index 00000000..ac7b3674 --- /dev/null +++ b/examples/demos/documentviewer/plugins/txtviewer/txtviewer.json @@ -0,0 +1 @@ +{ "Keys": [ "txtviewer" ] } diff --git a/examples/demos/documentviewer/viewerfactory.cpp b/examples/demos/documentviewer/viewerfactory.cpp deleted file mode 100644 index aaceaf54..00000000 --- a/examples/demos/documentviewer/viewerfactory.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#include <QWidget> -#include <QMimeDatabase> -#include <QMimeType> -#include "viewerfactory.h" - -#include "abstractviewer.h" -#include "pdfviewer.h" -#include "txtviewer.h" -#include "jsonviewer.h" - -AbstractViewer *ViewerFactory::makeViewer(QFile *file, QWidget *displayWidget, - QMainWindow *mainWindow) -{ - Q_ASSERT(file); - - const QFileInfo info(*file); - QMimeDatabase db; - const auto mimeType = db.mimeTypeForFile(info); - - if (mimeType.inherits("application/json")) - return new JsonViewer(file, displayWidget, mainWindow); - if (mimeType.inherits("text/plain")) - return new TxtViewer(file, displayWidget, mainWindow); - if (mimeType.inherits("application/pdf")) - return new PdfViewer(file, displayWidget, mainWindow); - - // Default to text viewer - return new TxtViewer(file, displayWidget, mainWindow); -} diff --git a/examples/demos/documentviewer/viewerfactory.h b/examples/demos/documentviewer/viewerfactory.h deleted file mode 100644 index 1a180068..00000000 --- a/examples/demos/documentviewer/viewerfactory.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#ifndef VIEWERFACTORY_H -#define VIEWERFACTORY_H - -class AbstractViewer; -class QWidget; -class QMainWindow; -class Questions; -class QFile; -class ViewerFactory -{ -public: - ViewerFactory() = delete; - static AbstractViewer *makeViewer(QFile *file, QWidget *displayWidget, QMainWindow *mainWindow); -}; - -#endif // VIEWERFACTORY_H |