Migrate documentviewer example into plugin based architecture
This patch changes the document viewer example to a plugin based architecture. It adapts the documentation accordingly. Change-Id: Ia24028aa27e21fb8ab36f5ef3a9953be60858b19 Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
|
@ -23,6 +23,6 @@ endif()
|
||||||
if(TARGET Qt::Quick AND TARGET Qt::qsb AND TARGET Qt::Pdf)
|
if(TARGET Qt::Quick AND TARGET Qt::qsb AND TARGET Qt::Pdf)
|
||||||
qt_internal_add_example(photosurface)
|
qt_internal_add_example(photosurface)
|
||||||
endif()
|
endif()
|
||||||
if(TARGET Qt::Widgets AND TARGET Qt::PdfWidgets)
|
if(TARGET Qt::Widgets)
|
||||||
qt_internal_add_example(documentviewer)
|
qt_internal_add_example(documentviewer)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -11,7 +11,7 @@ endif()
|
||||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/demos/${PROJECT_NAME}")
|
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/demos/${PROJECT_NAME}")
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick)
|
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick)
|
||||||
qt_standard_project_setup(REQUIRES 6.5)
|
qt_standard_project_setup()
|
||||||
|
|
||||||
qt_add_executable(colorpaletteclient
|
qt_add_executable(colorpaletteclient
|
||||||
main.cpp
|
main.cpp
|
||||||
|
|
|
@ -1,93 +1,21 @@
|
||||||
|
# Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
project(documentviewer LANGUAGES CXX)
|
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)
|
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||||
set(INSTALL_EXAMPLESDIR "examples")
|
set(INSTALL_EXAMPLESDIR "examples")
|
||||||
endif()
|
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)
|
if(TARGET Qt6::PrintSupport)
|
||||||
target_link_libraries(documentviewer PRIVATE Qt6::PrintSupport)
|
add_compile_definitions(QT_DOCUMENTVIEWER_PRINTSUPPORT)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
install(TARGETS documentviewer
|
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/demos/documentviewer")
|
||||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
|
||||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
add_subdirectory(app)
|
||||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
add_subdirectory(plugins)
|
||||||
)
|
|
||||||
|
|
|
@ -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}"
|
||||||
|
)
|
||||||
|
|
|
@ -13,14 +13,18 @@
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
||||||
#if defined(QT_ABSTRACTVIEWER_PRINTSUPPORT)
|
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
#include <QPrintDialog>
|
#include <QPrintDialog>
|
||||||
#endif // QT_ABSTRACTVIEWER_PRINTSUPPORT
|
#endif // QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
|
|
||||||
AbstractViewer::AbstractViewer(QFile *file, QWidget *widget, QMainWindow *mainWindow) :
|
AbstractViewer::AbstractViewer() : m_file(nullptr), m_widget(nullptr)
|
||||||
m_file(file),
|
|
||||||
m_widget(widget)
|
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractViewer::init(QFile *file, QWidget *widget, QMainWindow *mainWindow)
|
||||||
|
{
|
||||||
|
m_file.reset(file);
|
||||||
|
m_widget = widget;
|
||||||
Q_ASSERT(widget);
|
Q_ASSERT(widget);
|
||||||
Q_ASSERT(mainWindow);
|
Q_ASSERT(mainWindow);
|
||||||
m_uiAssets.mainWindow = mainWindow;
|
m_uiAssets.mainWindow = mainWindow;
|
||||||
|
@ -35,6 +39,96 @@ AbstractViewer::~AbstractViewer()
|
||||||
qDeleteAll(m_toolBars);
|
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)
|
void AbstractViewer::statusMessage(const QString &message, const QString &type, int timeout)
|
||||||
{
|
{
|
||||||
const QString msg = viewerName() + (type.isEmpty() ? ": " : "/" + type + ": ") + message;
|
const QString msg = viewerName() + (type.isEmpty() ? ": " : "/" + type + ": ") + message;
|
||||||
|
@ -78,7 +172,7 @@ QMenu *AbstractViewer::fileMenu()
|
||||||
|
|
||||||
void AbstractViewer::print()
|
void AbstractViewer::print()
|
||||||
{
|
{
|
||||||
#ifdef QT_ABSTRACTVIEWER_PRINTSUPPORT
|
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
static const QString type = tr("Printing");
|
static const QString type = tr("Printing");
|
||||||
if (!hasContent()) {
|
if (!hasContent()) {
|
||||||
statusMessage(tr("No content to print."), type);
|
statusMessage(tr("No content to print."), type);
|
||||||
|
@ -126,7 +220,7 @@ void AbstractViewer::print()
|
||||||
*/
|
*/
|
||||||
void AbstractViewer::maybeSetPrintingEnabled(bool enabled)
|
void AbstractViewer::maybeSetPrintingEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
#ifndef QT_ABSTRACTVIEWER_PRINTSUPPORT
|
#ifndef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
enabled = false;
|
enabled = false;
|
||||||
#else
|
#else
|
||||||
if (!hasContent())
|
if (!hasContent())
|
|
@ -8,14 +8,9 @@
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|
||||||
#if defined(QT_PRINTSUPPORT_LIB)
|
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
#include <QtPrintSupport/qtprintsupportglobal.h>
|
#include <QtPrintSupport/qtprintsupportglobal.h>
|
||||||
#if QT_CONFIG(printer)
|
|
||||||
#if QT_CONFIG(printdialog)
|
|
||||||
#define QT_ABSTRACTVIEWER_PRINTSUPPORT
|
|
||||||
#include <QPrinter>
|
#include <QPrinter>
|
||||||
#endif // QT_CONFIG(printdialog)
|
|
||||||
#endif // QT_CONFIG(printer)
|
|
||||||
#endif // QT_PRINTSUPPORT_LIB
|
#endif // QT_PRINTSUPPORT_LIB
|
||||||
|
|
||||||
class QToolBar;
|
class QToolBar;
|
||||||
|
@ -27,28 +22,32 @@ class AbstractViewer : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit AbstractViewer(QFile *file, QWidget *widget, QMainWindow *mainWindow);
|
AbstractViewer();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~AbstractViewer();
|
virtual ~AbstractViewer();
|
||||||
|
virtual void init(QFile *file, QWidget *widget, QMainWindow *mainWindow);
|
||||||
void initViewer(QAction *back, QAction *forward, QAction *help, QTabWidget *tabs);
|
void initViewer(QAction *back, QAction *forward, QAction *help, QTabWidget *tabs);
|
||||||
virtual bool isModified() const { return false; }
|
virtual bool isModified() const;
|
||||||
virtual bool saveDocument() { return false; }
|
virtual bool saveDocument();
|
||||||
virtual bool saveDocumentAs() { return false; }
|
virtual bool saveDocumentAs();
|
||||||
virtual QString viewerName() const = 0;
|
virtual QString viewerName() const = 0;
|
||||||
virtual bool supportsOverview() const { return false; }
|
virtual bool supportsOverview() const;
|
||||||
virtual QByteArray saveState() const = 0;
|
virtual QByteArray saveState() const = 0;
|
||||||
virtual bool restoreState(QByteArray &) = 0;
|
virtual bool restoreState(QByteArray &) = 0;
|
||||||
virtual bool hasContent() const { return false; }
|
virtual bool hasContent() const;
|
||||||
bool isEmpty() const { return !hasContent(); }
|
virtual QStringList supportedMimeTypes() const = 0;
|
||||||
bool isPrintingEnabled() const { return m_printingEnabled; }
|
virtual bool isDefaultViewer() const;
|
||||||
|
bool isEmpty() const;
|
||||||
|
bool isPrintingEnabled() const;
|
||||||
|
AbstractViewer *viewer();
|
||||||
|
const AbstractViewer *viewer() const;
|
||||||
|
|
||||||
QList<QAction *> actions() const { return m_actions; }
|
QList<QAction *> actions() const;
|
||||||
QWidget *widget() const { return m_widget; }
|
QWidget *widget() const;
|
||||||
QList<QMenu *> menus() const { return m_menus; }
|
QList<QMenu *> menus() const;
|
||||||
|
|
||||||
#ifdef QT_ABSTRACTVIEWER_PRINTSUPPORT
|
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
protected:
|
protected:
|
||||||
virtual void printDocument(QPrinter *) const {};
|
virtual void printDocument(QPrinter *) const {};
|
||||||
#endif
|
#endif
|
||||||
|
@ -76,18 +75,18 @@ protected:
|
||||||
QToolBar *addToolBar(const QString &);
|
QToolBar *addToolBar(const QString &);
|
||||||
QMenu *addMenu(const QString &);
|
QMenu *addMenu(const QString &);
|
||||||
QMenu *fileMenu();
|
QMenu *fileMenu();
|
||||||
QMainWindow *mainWindow() const { return m_uiAssets.mainWindow; }
|
QMainWindow *mainWindow() const;
|
||||||
QStatusBar *statusBar() const { return mainWindow()->statusBar(); }
|
QStatusBar *statusBar() const;
|
||||||
QMenuBar *menuBar() const { return mainWindow()->menuBar(); }
|
QMenuBar *menuBar() const;
|
||||||
|
|
||||||
std::unique_ptr<QFile> m_file;
|
std::unique_ptr<QFile> m_file;
|
||||||
QList<QAction *> m_actions;
|
QList<QAction *> m_actions;
|
||||||
QWidget *m_widget;
|
QWidget *m_widget = nullptr;
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void maybeSetPrintingEnabled(bool enabled);
|
void maybeSetPrintingEnabled(bool enabled);
|
||||||
inline void maybeEnablePrinting() { return maybeSetPrintingEnabled(true); }
|
void maybeEnablePrinting();
|
||||||
inline void disablePrinting() { return maybeSetPrintingEnabled(false); }
|
void disablePrinting();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<QMenu *> m_menus;
|
QList<QMenu *> m_menus;
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 990 B After Width: | Height: | Size: 990 B |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 1010 B After Width: | Height: | Size: 1010 B |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1006 B After Width: | Height: | Size: 1006 B |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 1017 B After Width: | Height: | Size: 1017 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 678 B After Width: | Height: | Size: 678 B |
Before Width: | Height: | Size: 931 B After Width: | Height: | Size: 931 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 905 B After Width: | Height: | Size: 905 B |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 952 B After Width: | Height: | Size: 952 B |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 946 B After Width: | Height: | Size: 946 B |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 940 B After Width: | Height: | Size: 940 B |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 946 B After Width: | Height: | Size: 946 B |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
@ -1,9 +1,12 @@
|
||||||
// Copyright (C) 2023 The Qt Company Ltd.
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
#include "abstractviewer.h"
|
|
||||||
#include "viewerfactory.h"
|
#include "viewerfactory.h"
|
||||||
|
#include "abstractviewer.h"
|
||||||
|
#include "recentfiles.h"
|
||||||
|
#include "recentfilemenu.h"
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
|
@ -15,7 +18,25 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
ui(new Ui::MainWindow)
|
ui(new Ui::MainWindow)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
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();
|
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()
|
MainWindow::~MainWindow()
|
||||||
|
@ -46,24 +67,48 @@ void MainWindow::openFile(const QString &fileName)
|
||||||
|
|
||||||
QFileInfo fileInfo(*file);
|
QFileInfo fileInfo(*file);
|
||||||
m_currentDir = fileInfo.dir();
|
m_currentDir = fileInfo.dir();
|
||||||
|
m_recentFiles->addFile(fileInfo.absoluteFilePath());
|
||||||
|
|
||||||
// If a viewer is already open, save its state first
|
// If a viewer is already open, save its state first
|
||||||
saveViewerSettings();
|
saveViewerSettings();
|
||||||
m_viewer.reset(ViewerFactory::makeViewer(file, ui->viewArea, this));
|
m_viewer = m_factory->viewer(file);
|
||||||
restoreViewerSettings();
|
if (!m_viewer) {
|
||||||
|
statusBar()->showMessage(tr("File %1 can't be opened.").arg(fileName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ui->actionPrint->setEnabled(m_viewer->hasContent());
|
ui->actionPrint->setEnabled(m_viewer->hasContent());
|
||||||
connect(m_viewer.get(), &AbstractViewer::printingEnabledChanged, ui->actionPrint, &QAction::setEnabled);
|
connect(m_viewer, &AbstractViewer::printingEnabledChanged, ui->actionPrint, &QAction::setEnabled);
|
||||||
connect(ui->actionPrint, &QAction::triggered, m_viewer.get(), &AbstractViewer::print);
|
connect(ui->actionPrint, &QAction::triggered, m_viewer, &AbstractViewer::print);
|
||||||
connect(m_viewer.get(), &AbstractViewer::showMessage, statusBar(), &QStatusBar::showMessage);
|
connect(m_viewer, &AbstractViewer::showMessage, statusBar(), &QStatusBar::showMessage);
|
||||||
|
|
||||||
m_viewer->initViewer(ui->actionBack, ui->actionForward, ui->menuHelp->menuAction(), ui->tabWidget);
|
m_viewer->initViewer(ui->actionBack, ui->actionForward, ui->menuHelp->menuAction(), ui->tabWidget);
|
||||||
|
restoreViewerSettings();
|
||||||
ui->scrollArea->setWidget(m_viewer->widget());
|
ui->scrollArea->setWidget(m_viewer->widget());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionAbout_triggered()
|
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()
|
void MainWindow::on_actionAboutQt_triggered()
|
||||||
|
@ -86,6 +131,9 @@ void MainWindow::readSettings()
|
||||||
QByteArray mainWindowState = settings.value(settingsMainWindow).toByteArray();
|
QByteArray mainWindowState = settings.value(settingsMainWindow).toByteArray();
|
||||||
restoreState(mainWindowState);
|
restoreState(mainWindowState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore recent files
|
||||||
|
m_recentFiles->restoreFromSettings(settings, settingsFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::saveSettings() const
|
void MainWindow::saveSettings() const
|
||||||
|
@ -98,6 +146,9 @@ void MainWindow::saveSettings() const
|
||||||
// Save QMainWindow state
|
// Save QMainWindow state
|
||||||
settings.setValue(settingsMainWindow, saveState());
|
settings.setValue(settingsMainWindow, saveState());
|
||||||
|
|
||||||
|
// Save recent files
|
||||||
|
m_recentFiles->saveSettings(settings, settingsFiles);
|
||||||
|
|
||||||
settings.sync();
|
settings.sync();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <QStringLiteral>
|
#include <QStringLiteral>
|
||||||
|
|
||||||
class AbstractViewer;
|
class AbstractViewer;
|
||||||
|
class RecentFiles;
|
||||||
|
class ViewerFactory;
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
}
|
}
|
||||||
|
@ -37,14 +39,17 @@ private:
|
||||||
void saveViewerSettings() const;
|
void saveViewerSettings() const;
|
||||||
|
|
||||||
QDir m_currentDir;
|
QDir m_currentDir;
|
||||||
|
AbstractViewer *m_viewer = nullptr;
|
||||||
std::unique_ptr<Ui::MainWindow> ui;
|
std::unique_ptr<Ui::MainWindow> ui;
|
||||||
std::unique_ptr<AbstractViewer> m_viewer;
|
std::unique_ptr<RecentFiles> m_recentFiles;
|
||||||
int m_classId = -1;
|
int m_classId = -1;
|
||||||
|
std::unique_ptr<ViewerFactory> m_factory;
|
||||||
|
|
||||||
static constexpr QLatin1StringView settingsName = QLatin1StringView("DocumentViewerExample");
|
static constexpr QLatin1StringView settingsName = QLatin1StringView("DocumentViewerExample");
|
||||||
static constexpr QLatin1StringView settingsDir = QLatin1StringView("WorkingDir");
|
static constexpr QLatin1StringView settingsDir = QLatin1StringView("WorkingDir");
|
||||||
static constexpr QLatin1StringView settingsMainWindow = QLatin1StringView("MainWindow");
|
static constexpr QLatin1StringView settingsMainWindow = QLatin1StringView("MainWindow");
|
||||||
static constexpr QLatin1StringView settingsViewers = QLatin1StringView("Viewers");
|
static constexpr QLatin1StringView settingsViewers = QLatin1StringView("Viewers");
|
||||||
|
static constexpr QLatin1StringView settingsFiles = QLatin1StringView("RecentFiles");
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
|
@ -14,7 +14,7 @@
|
||||||
<string>Document Viewer Demo</string>
|
<string>Document Viewer Demo</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowIcon">
|
<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>
|
<normaloff>:/demos/documentviewer/images/qt-logo.png</normaloff>:/demos/documentviewer/images/qt-logo.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="centralwidget">
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
@ -96,6 +96,7 @@
|
||||||
<string>File</string>
|
<string>File</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionOpen"/>
|
<addaction name="actionOpen"/>
|
||||||
|
<addaction name="actionRecent"/>
|
||||||
<addaction name="actionPrint"/>
|
<addaction name="actionPrint"/>
|
||||||
<addaction name="actionQuit"/>
|
<addaction name="actionQuit"/>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -121,6 +122,7 @@
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</attribute>
|
</attribute>
|
||||||
<addaction name="actionOpen"/>
|
<addaction name="actionOpen"/>
|
||||||
|
<addaction name="actionRecent"/>
|
||||||
<addaction name="actionPrint"/>
|
<addaction name="actionPrint"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionBack"/>
|
<addaction name="actionBack"/>
|
||||||
|
@ -141,8 +143,8 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="actionAbout">
|
<action name="actionAbout">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset theme="help-about">
|
<iconset theme="help-about" resource="../../../../../../build/dev/qtdoc/examples/demos/documentviewer/app/.rcc/documentviewer.qrc">
|
||||||
<normaloff>.</normaloff>.</iconset>
|
<normaloff>:/demos/documentviewer/images/qt-logo.png</normaloff>:/demos/documentviewer/images/qt-logo.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>about documentviewer</string>
|
<string>about documentviewer</string>
|
||||||
|
@ -189,8 +191,8 @@
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset theme="document-print">
|
<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>
|
<normaloff>:/demos/documentviewer/images/print.png</normaloff>:/demos/documentviewer/images/print.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Print</string>
|
<string>Print</string>
|
||||||
|
@ -204,9 +206,9 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="actionAboutQt">
|
<action name="actionAboutQt">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../../../../../build/dev/qthttpserver/examples/httpserver/simple/.rcc/assets.qrc">
|
<iconset resource="../../../../../../build/dev/qtdoc/examples/demos/documentviewer/app/.rcc/documentviewer.qrc">
|
||||||
<normaloff>:/demos/documentviewer/images/qt-logo.png</normaloff>
|
<normaloff>:/demos/documentviewer/images/qt-logo.png</normaloff>
|
||||||
<normalon>:/demos/documentviewer/images/qt-logo.png</normalon>:/demos/documentviewer/images/qt-logo.png</iconset>
|
<normalon>:/demos/documentviewer/images/qt-logo.png</normalon>:/demos/documentviewer/images/qt-logo.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>About Qt</string>
|
<string>About Qt</string>
|
||||||
|
@ -224,7 +226,7 @@
|
||||||
<normaloff>.</normaloff>.</iconset>
|
<normaloff>.</normaloff>.</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Open</string>
|
<string>Recently opened...</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Meta+R</string>
|
<string>Meta+R</string>
|
||||||
|
@ -232,7 +234,8 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="actionQuit">
|
<action name="actionQuit">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset theme="application-exit"/>
|
<iconset theme="application-exit">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Quit</string>
|
<string>Quit</string>
|
||||||
|
@ -246,8 +249,7 @@
|
||||||
</action>
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../../../../build/dev/qtdoc/examples/demos/documentviewer/.rcc/documentviewer.qrc"/>
|
<include location="../../../../../../build/dev/qtdoc/examples/demos/documentviewer/app/.rcc/documentviewer.qrc"/>
|
||||||
<include location="../../../../../build/dev/qthttpserver/examples/httpserver/simple/.rcc/assets.qrc"/>
|
|
||||||
</resources>
|
</resources>
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
<connection>
|
|
@ -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());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -27,14 +27,14 @@
|
||||||
To create an executable, we use a standard main.cpp file.
|
To create an executable, we use a standard main.cpp file.
|
||||||
First, we set the application's organization name:
|
First, we set the application's organization name:
|
||||||
|
|
||||||
\quotefromfile demos/documentviewer/main.cpp
|
\quotefromfile demos/documentviewer/app/main.cpp
|
||||||
\skipto int main
|
\skipto int main
|
||||||
\printuntil QApplication::set
|
\printuntil QApplication::set
|
||||||
\endsection1
|
\endsection1
|
||||||
|
|
||||||
\section1 Creating an application and showing the main window
|
\section1 Creating an application and showing the main window
|
||||||
|
|
||||||
\quotefromfile demos/documentviewer/main.cpp
|
\quotefromfile demos/documentviewer/app/main.cpp
|
||||||
\skipto QApplication app
|
\skipto QApplication app
|
||||||
\printuntil }
|
\printuntil }
|
||||||
\endsection1
|
\endsection1
|
||||||
|
@ -44,13 +44,17 @@
|
||||||
The class constructor initializes the user interface created in Qt Designer.
|
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.
|
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
|
\skipto ui->setupUi
|
||||||
\printuntil triggered
|
\printuntil triggered
|
||||||
|
|
||||||
The \c mainwindow.ui file provides a QTabWidget on the left, where bookmarks and thumbnails
|
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
|
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.
|
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
|
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.
|
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
|
\skipuntil void MainWindow::openFile
|
||||||
\skipto m_viewer->initViewer
|
\skipto m_viewer->initViewer
|
||||||
\printuntil }
|
\printuntil }
|
||||||
|
@ -74,7 +78,7 @@
|
||||||
displayed, the main window and the user questions.
|
displayed, the main window and the user questions.
|
||||||
Depending on the file's mime type, it creates an appropriate document viewer.
|
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
|
\skipto AbstractViewer
|
||||||
\printuntil }
|
\printuntil }
|
||||||
\endsection1
|
\endsection1
|
||||||
|
@ -159,40 +163,40 @@
|
||||||
HoverWatcher inherits from QObject and the QWidget watched becomes the instance's parent.
|
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.
|
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
|
\skipto HoverWatcher::HoverWatcher
|
||||||
\printuntil }
|
\printuntil }
|
||||||
|
|
||||||
The actions watched are represented in an enum.
|
The actions watched are represented in an enum.
|
||||||
|
|
||||||
\quotefromfile demos/documentviewer/hoverwatcher.h
|
\quotefromfile demos/documentviewer/plugins/pdfviewer/hoverwatcher.h
|
||||||
\skipto enum HoverAction
|
\skipto enum HoverAction
|
||||||
\printuntil };
|
\printuntil };
|
||||||
|
|
||||||
Static methods create watchers, check their existence for a specific QWidget or dismiss
|
Static methods create watchers, check their existence for a specific QWidget or dismiss
|
||||||
a watcher.
|
a watcher.
|
||||||
|
|
||||||
\quotefromfile demos/documentviewer/hoverwatcher.h
|
\quotefromfile demos/documentviewer/plugins/pdfviewer/hoverwatcher.h
|
||||||
\skipto static HoverWatcher
|
\skipto static HoverWatcher
|
||||||
\printuntil static void dismiss
|
\printuntil static void dismiss
|
||||||
|
|
||||||
A cursor shape can be specified or unset for each HoverAction. If no cursor shape is
|
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.
|
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
|
\skipto public slots
|
||||||
\printuntil void unSetCursorShape
|
\printuntil void unSetCursorShape
|
||||||
|
|
||||||
The mouseButtons property specifies, which mouse buttons to consider for the MousePress action.
|
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
|
\skipuntil public slots
|
||||||
\skipto setMouseButtons
|
\skipto setMouseButtons
|
||||||
\printuntil setMouseButton(
|
\printuntil setMouseButton(
|
||||||
|
|
||||||
Action specific signals are emitted when an action has been processed.
|
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
|
\skipto signals
|
||||||
\printuntil left();
|
\printuntil left();
|
||||||
|
|
||||||
|
@ -201,6 +205,72 @@
|
||||||
\code
|
\code
|
||||||
void hoverAction(HoverAction action);
|
void hoverAction(HoverAction action);
|
||||||
\endcode
|
\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
|
\endsection2
|
||||||
\endsection1
|
\endsection1
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
@ -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"
|
||||||
|
)
|
||||||
|
|
|
@ -18,14 +18,14 @@
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#ifdef QT_ABSTRACTVIEWER_PRINTSUPPORT
|
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
#include <QPrinter>
|
#include <QPrinter>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JsonViewer::JsonViewer(QFile *file, QWidget *parent, QMainWindow *mainWindow) :
|
void JsonViewer::init(QFile *file, QWidget *parent, QMainWindow *mainWindow)
|
||||||
AbstractViewer(file, new QTreeView(parent), mainWindow)
|
|
||||||
{
|
{
|
||||||
|
AbstractViewer::init(file, new QTreeView(parent), mainWindow);
|
||||||
m_tree = qobject_cast<QTreeView *>(widget());
|
m_tree = qobject_cast<QTreeView *>(widget());
|
||||||
connect(this, &AbstractViewer::uiInitialized, this, &JsonViewer::setupJsonUi);
|
connect(this, &AbstractViewer::uiInitialized, this, &JsonViewer::setupJsonUi);
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,11 @@ JsonViewer::~JsonViewer()
|
||||||
delete m_toplevel;
|
delete m_toplevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList JsonViewer::supportedMimeTypes() const
|
||||||
|
{
|
||||||
|
return {"application/json"};
|
||||||
|
}
|
||||||
|
|
||||||
void JsonViewer::setupJsonUi()
|
void JsonViewer::setupJsonUi()
|
||||||
{
|
{
|
||||||
// Build Menus and toolbars
|
// Build Menus and toolbars
|
||||||
|
@ -268,7 +273,7 @@ bool JsonViewer::hasContent() const
|
||||||
return !m_root.isEmpty();
|
return !m_root.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(QT_ABSTRACTVIEWER_PRINTSUPPORT)
|
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
void JsonViewer::printDocument(QPrinter *printer) const
|
void JsonViewer::printDocument(QPrinter *printer) const
|
||||||
{
|
{
|
||||||
if (!hasContent())
|
if (!hasContent())
|
||||||
|
@ -278,7 +283,7 @@ void JsonViewer::printDocument(QPrinter *printer) const
|
||||||
doc.print(printer);
|
doc.print(printer);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // QT_ABSTRACTVIEWER_PRINTSUPPORT
|
#endif // QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
|
|
||||||
QByteArray JsonViewer::saveState() const
|
QByteArray JsonViewer::saveState() const
|
||||||
{
|
{
|
|
@ -4,7 +4,7 @@
|
||||||
#ifndef JSONVIEWER_H
|
#ifndef JSONVIEWER_H
|
||||||
#define JSONVIEWER_H
|
#define JSONVIEWER_H
|
||||||
|
|
||||||
#include "abstractviewer.h"
|
#include "viewerinterfaces.h"
|
||||||
#include <QJsonValue>
|
#include <QJsonValue>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
|
@ -15,21 +15,25 @@ class QTreeView;
|
||||||
class QListWidget;
|
class QListWidget;
|
||||||
class QListWidgetItem;
|
class QListWidgetItem;
|
||||||
class QLineEdit;
|
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:
|
public:
|
||||||
JsonViewer(QFile *file, QWidget *parent, QMainWindow *mainWindow);
|
|
||||||
~JsonViewer() override;
|
~JsonViewer() override;
|
||||||
|
|
||||||
|
void init(QFile *file, QWidget *parent, QMainWindow *mainWindow) override;
|
||||||
QString viewerName() const override { return staticMetaObject.className(); };
|
QString viewerName() const override { return staticMetaObject.className(); };
|
||||||
|
QStringList supportedMimeTypes() const override;
|
||||||
QByteArray saveState() const override;
|
QByteArray saveState() const override;
|
||||||
bool restoreState(QByteArray &) override;
|
bool restoreState(QByteArray &) override;
|
||||||
bool supportsOverview() const override { return true; }
|
bool supportsOverview() const override { return true; }
|
||||||
bool hasContent() const override;
|
bool hasContent() const override;
|
||||||
|
|
||||||
#if defined(QT_ABSTRACTVIEWER_PRINTSUPPORT)
|
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
protected:
|
protected:
|
||||||
void printDocument(QPrinter *printer) const override;
|
void printDocument(QPrinter *printer) const override;
|
||||||
#endif // QT_ABSTRACTVIEWER_PRINTSUPPORT
|
#endif // QT_ABSTRACTVIEWER_PRINTSUPPORT
|
|
@ -0,0 +1 @@
|
||||||
|
{ "Keys": [ "jsonviewer" ] }
|
|
@ -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"
|
||||||
|
)
|
||||||
|
|
|
@ -25,20 +25,21 @@
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QScroller>
|
#include <QScroller>
|
||||||
#ifdef QT_ABSTRACTVIEWER_PRINTSUPPORT
|
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
#include <QPrinter>
|
#include <QPrinter>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcExample, "qt.examples.pdfviewer")
|
Q_LOGGING_CATEGORY(lcExample, "qt.examples.pdfviewer")
|
||||||
|
|
||||||
PdfViewer::PdfViewer(QFile *file, QWidget *parent, QMainWindow *mainWindow) :
|
void PdfViewer::init(QFile *file, QWidget *parent, QMainWindow *mainWindow)
|
||||||
AbstractViewer(file, new QPdfView(parent), mainWindow), m_document(new QPdfDocument(this))
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
AbstractViewer::init(file, new QPdfView(parent), mainWindow);
|
||||||
|
m_document = new QPdfDocument(this);
|
||||||
m_pdfView = qobject_cast<QPdfView *>(widget());
|
m_pdfView = qobject_cast<QPdfView *>(widget());
|
||||||
connect(this, &AbstractViewer::uiInitialized, this, &PdfViewer::initPdfViewer);
|
connect(this, &AbstractViewer::uiInitialized, this, &PdfViewer::initPdfViewer);
|
||||||
}
|
}
|
||||||
|
|
||||||
PdfViewer::~PdfViewer()
|
PdfViewer::~PdfViewer()
|
||||||
{
|
{
|
||||||
delete m_pages;
|
delete m_pages;
|
||||||
|
@ -46,6 +47,11 @@ PdfViewer::~PdfViewer()
|
||||||
delete m_document;
|
delete m_document;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList PdfViewer::supportedMimeTypes() const
|
||||||
|
{
|
||||||
|
return {"application/pdf"};
|
||||||
|
}
|
||||||
|
|
||||||
void PdfViewer::initPdfViewer()
|
void PdfViewer::initPdfViewer()
|
||||||
{
|
{
|
||||||
m_toolBar = addToolBar("PDF");
|
m_toolBar = addToolBar("PDF");
|
||||||
|
@ -154,7 +160,7 @@ bool PdfViewer::hasContent() const
|
||||||
return m_document ? m_document->pageCount() > 0 : false;
|
return m_document ? m_document->pageCount() > 0 : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(QT_ABSTRACTVIEWER_PRINTSUPPORT)
|
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
void PdfViewer::printDocument(QPrinter *printer) const
|
void PdfViewer::printDocument(QPrinter *printer) const
|
||||||
{
|
{
|
||||||
if (!hasContent())
|
if (!hasContent())
|
||||||
|
@ -172,7 +178,7 @@ void PdfViewer::printDocument(QPrinter *printer) const
|
||||||
}
|
}
|
||||||
painter.end();
|
painter.end();
|
||||||
}
|
}
|
||||||
#endif // QT_ABSTRACTVIEWER_PRINTSUPPORT
|
#endif // QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
|
|
||||||
void PdfViewer::bookmarkSelected(const QModelIndex &index)
|
void PdfViewer::bookmarkSelected(const QModelIndex &index)
|
||||||
{
|
{
|
|
@ -4,7 +4,7 @@
|
||||||
#ifndef PDFVIEWER_H
|
#ifndef PDFVIEWER_H
|
||||||
#define PDFVIEWER_H
|
#define PDFVIEWER_H
|
||||||
|
|
||||||
#include "abstractviewer.h"
|
#include "viewerinterfaces.h"
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
Q_DECLARE_LOGGING_CATEGORY(lcExample)
|
Q_DECLARE_LOGGING_CATEGORY(lcExample)
|
||||||
|
@ -17,22 +17,25 @@ class QListView;
|
||||||
class QTabWidget;
|
class QTabWidget;
|
||||||
class QTreeView;
|
class QTreeView;
|
||||||
class ZoomSelector;
|
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:
|
public:
|
||||||
PdfViewer(QFile *file, QWidget *parent, QMainWindow *mainWindow);
|
|
||||||
|
|
||||||
~PdfViewer() override;
|
~PdfViewer() override;
|
||||||
|
void init(QFile *file, QWidget *parent, QMainWindow *mainWindow) override;
|
||||||
QString viewerName() const override { return staticMetaObject.className(); };
|
QString viewerName() const override { return staticMetaObject.className(); };
|
||||||
|
QStringList supportedMimeTypes() const override;
|
||||||
bool supportsOverview() const override { return true; }
|
bool supportsOverview() const override { return true; }
|
||||||
bool hasContent() const override;
|
bool hasContent() const override;
|
||||||
QByteArray saveState() const override { return QByteArray(); }
|
QByteArray saveState() const override { return QByteArray(); }
|
||||||
bool restoreState(QByteArray &) override { return true; }
|
bool restoreState(QByteArray &) override { return true; }
|
||||||
|
|
||||||
#if defined(QT_ABSTRACTVIEWER_PRINTSUPPORT)
|
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
protected:
|
protected:
|
||||||
void printDocument(QPrinter *printer) const override;
|
void printDocument(QPrinter *printer) const override;
|
||||||
#endif // QT_ABSTRACTVIEWER_PRINTSUPPORT
|
#endif // QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void openPdfFile();
|
void openPdfFile();
|
||||||
|
@ -58,10 +61,10 @@ private:
|
||||||
const qreal zoomMultiplier = qSqrt(2.0);
|
const qreal zoomMultiplier = qSqrt(2.0);
|
||||||
static constexpr int maxIconWidth = 200;
|
static constexpr int maxIconWidth = 200;
|
||||||
QToolBar *m_toolBar = nullptr;
|
QToolBar *m_toolBar = nullptr;
|
||||||
ZoomSelector *m_zoomSelector;
|
ZoomSelector *m_zoomSelector = nullptr;
|
||||||
QPdfPageSelector *m_pageSelector;
|
QPdfPageSelector *m_pageSelector = nullptr;
|
||||||
QPdfDocument *m_document;
|
QPdfDocument *m_document = nullptr;
|
||||||
QPdfView *m_pdfView;
|
QPdfView *m_pdfView = nullptr;
|
||||||
QAction *m_actionForward = nullptr;
|
QAction *m_actionForward = nullptr;
|
||||||
QAction *m_actionBack = nullptr;
|
QAction *m_actionBack = nullptr;
|
||||||
QTreeView *m_bookmarks = nullptr;
|
QTreeView *m_bookmarks = nullptr;
|
|
@ -0,0 +1 @@
|
||||||
|
{ "Keys": [ "pdfviewer" ] }
|
|
@ -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"
|
||||||
|
)
|
||||||
|
|
|
@ -13,14 +13,14 @@
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#ifdef QT_ABSTRACTVIEWER_PRINTSUPPORT
|
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
#include <QPrinter>
|
#include <QPrinter>
|
||||||
#include <QPrintDialog>
|
#include <QPrintDialog>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TxtViewer::TxtViewer(QFile *file, QWidget *parent, QMainWindow *mainWindow) :
|
void TxtViewer::init(QFile *file, QWidget *parent, QMainWindow *mainWindow)
|
||||||
AbstractViewer(file, new QPlainTextEdit(parent), mainWindow)
|
|
||||||
{
|
{
|
||||||
|
AbstractViewer::init(file, new QPlainTextEdit(parent), mainWindow);
|
||||||
m_textEdit = qobject_cast<QPlainTextEdit *>(widget());
|
m_textEdit = qobject_cast<QPlainTextEdit *>(widget());
|
||||||
connect(this, &AbstractViewer::uiInitialized, this, &TxtViewer::setupTxtUi);
|
connect(this, &AbstractViewer::uiInitialized, this, &TxtViewer::setupTxtUi);
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,11 @@ TxtViewer::~TxtViewer()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList TxtViewer::supportedMimeTypes() const
|
||||||
|
{
|
||||||
|
return {"text/plain"};
|
||||||
|
}
|
||||||
|
|
||||||
void TxtViewer::setupTxtUi()
|
void TxtViewer::setupTxtUi()
|
||||||
{
|
{
|
||||||
QMenu *editMenu = addMenu(tr("&Edit"));
|
QMenu *editMenu = addMenu(tr("&Edit"));
|
||||||
|
@ -119,7 +124,7 @@ bool TxtViewer::hasContent() const
|
||||||
return (!m_textEdit->toPlainText().isEmpty());
|
return (!m_textEdit->toPlainText().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(QT_ABSTRACTVIEWER_PRINTSUPPORT)
|
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
void TxtViewer::printDocument(QPrinter *printer) const
|
void TxtViewer::printDocument(QPrinter *printer) const
|
||||||
{
|
{
|
||||||
if (!hasContent())
|
if (!hasContent())
|
||||||
|
@ -127,8 +132,7 @@ void TxtViewer::printDocument(QPrinter *printer) const
|
||||||
|
|
||||||
m_textEdit->print(printer);
|
m_textEdit->print(printer);
|
||||||
}
|
}
|
||||||
|
#endif // QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
#endif // QT_ABSTRACTVIEWER_PRINTSUPPORT
|
|
||||||
|
|
||||||
bool TxtViewer::saveFile(QFile *file)
|
bool TxtViewer::saveFile(QFile *file)
|
||||||
{
|
{
|
|
@ -4,28 +4,34 @@
|
||||||
#ifndef TXTVIEWER_H
|
#ifndef TXTVIEWER_H
|
||||||
#define TXTVIEWER_H
|
#define TXTVIEWER_H
|
||||||
|
|
||||||
|
#include "viewerinterfaces.h"
|
||||||
#include "abstractviewer.h"
|
#include "abstractviewer.h"
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
|
||||||
class QMainWindow;
|
class QMainWindow;
|
||||||
class QPlainTextEdit;
|
class QPlainTextEdit;
|
||||||
class QLabel;
|
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:
|
public:
|
||||||
TxtViewer(QFile *file, QWidget *parent, QMainWindow *mainWindow);
|
|
||||||
~TxtViewer() override;
|
~TxtViewer() override;
|
||||||
|
void init(QFile *file, QWidget *parent, QMainWindow *mainWindow) override;
|
||||||
QString viewerName() const override { return staticMetaObject.className(); };
|
QString viewerName() const override { return staticMetaObject.className(); };
|
||||||
|
QStringList supportedMimeTypes() const override;
|
||||||
bool saveDocument() override { return saveFile(m_file.get()); };
|
bool saveDocument() override { return saveFile(m_file.get()); };
|
||||||
bool saveDocumentAs() override;
|
bool saveDocumentAs() override;
|
||||||
bool hasContent() const override;
|
bool hasContent() const override;
|
||||||
QByteArray saveState() const override { return QByteArray(); }
|
QByteArray saveState() const override { return QByteArray(); }
|
||||||
bool restoreState(QByteArray &) override { return true; }
|
bool restoreState(QByteArray &) override { return true; }
|
||||||
|
bool supportsOverview() const override { return false; }
|
||||||
|
|
||||||
#if defined(QT_ABSTRACTVIEWER_PRINTSUPPORT)
|
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
protected:
|
protected:
|
||||||
void printDocument(QPrinter *printer) const override;
|
void printDocument(QPrinter *printer) const override;
|
||||||
#endif // QT_ABSTRACTVIEWER_PRINTSUPPORT
|
#endif // QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void setupTxtUi();
|
void setupTxtUi();
|
|
@ -0,0 +1 @@
|
||||||
|
{ "Keys": [ "txtviewer" ] }
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -14,7 +14,7 @@ set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/demos/photosurface")
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick ShaderTools)
|
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick ShaderTools)
|
||||||
|
|
||||||
qt_standard_project_setup(REQUIRES 6.5)
|
qt_standard_project_setup()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
#! [appicon_windows]
|
#! [appicon_windows]
|
||||||
|
@ -48,6 +48,7 @@ target_link_libraries(photosurfaceexample PRIVATE
|
||||||
|
|
||||||
qt_add_qml_module(photosurfaceexample
|
qt_add_qml_module(photosurfaceexample
|
||||||
URI photosurface
|
URI photosurface
|
||||||
|
VERSION 1.0
|
||||||
QML_FILES
|
QML_FILES
|
||||||
"photosurface.qml"
|
"photosurface.qml"
|
||||||
"resources/MomentumAnimation.qml"
|
"resources/MomentumAnimation.qml"
|
||||||
|
|