From 9d7a4d2aca1556f88f9d2b7ff75a2a58e6559f4f Mon Sep 17 00:00:00 2001 From: "Victor \"multun\" Collod" Date: Sun, 3 May 2020 22:13:17 -0700 Subject: [PATCH 001/133] remove bogus isAbsurdPoint check This check fails to work with multiple screens having different geometries. It really shouldn't be necessary anyway. --- src/board/UBBoardView.cpp | 27 --------------------------- src/board/UBBoardView.h | 2 -- 2 files changed, 29 deletions(-) diff --git a/src/board/UBBoardView.cpp b/src/board/UBBoardView.cpp index 70fd73686..7ecd14071 100644 --- a/src/board/UBBoardView.cpp +++ b/src/board/UBBoardView.cpp @@ -986,11 +986,6 @@ void UBBoardView::mousePressEvent (QMouseEvent *event) mIsDragInProgress = false; - if (isAbsurdPoint (event->pos ())) { - event->accept (); - return; - } - mMouseDownPos = event->pos (); movingItem = scene()->itemAt(this->mapToScene(event->localPos().toPoint()), QTransform()); @@ -1111,11 +1106,6 @@ void UBBoardView::mouseMoveEvent (QMouseEvent *event) mWidgetMoved = true; mLongPressTimer.stop(); - if (isAbsurdPoint (event->pos ())) { - event->accept (); - return; - } - if ((UBDrawingController::drawingController()->isDrawingTool()) && !mMouseButtonIsPressed) QGraphicsView::mouseMoveEvent(event); @@ -1695,23 +1685,6 @@ void UBBoardView::virtualKeyboardActivated(bool b) setInteractive(!b); } - -// Apple remote desktop sends funny events when the transmission is bad - -bool UBBoardView::isAbsurdPoint(QPoint point) -{ - QDesktopWidget *desktop = qApp->desktop (); - bool isValidPoint = false; - - for (int i = 0; i < desktop->numScreens (); i++) - { - QRect screenRect = desktop->screenGeometry (i); - isValidPoint = isValidPoint || screenRect.contains (mapToGlobal(point)); - } - - return !isValidPoint; -} - void UBBoardView::focusOutEvent (QFocusEvent * event) { Q_UNUSED (event); diff --git a/src/board/UBBoardView.h b/src/board/UBBoardView.h index 076947016..625d60c34 100644 --- a/src/board/UBBoardView.h +++ b/src/board/UBBoardView.h @@ -149,8 +149,6 @@ class UBBoardView : public QGraphicsView bool mIsCreatingTextZone; bool mIsCreatingSceneGrabZone; - bool isAbsurdPoint(QPoint point); - bool mVirtualKeyboardActive; bool mOkOnWidget; From c0f8e628529d3d10ea736bdd4b8f5993379c8289 Mon Sep 17 00:00:00 2001 From: Torsten Maehne Date: Fri, 10 Jun 2022 18:28:47 +0200 Subject: [PATCH 002/133] Fix syntax error message when executing qmake On Debian 11 when executing `qmake OpenBoard.org`, one gets the following error message: ``` qmake OpenBoard.pro sh: 1: Syntax error: "&" unexpected sh: 1: Syntax error: "&" unexpected sh: 1: Syntax error: "&" unexpected ``` The cause is the use of bash-specific `|&` pipe operator in `podcast.pri` line 70 to determine the `FFMPEG_VERSION`. --- src/podcast/podcast.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/podcast/podcast.pri b/src/podcast/podcast.pri index 873658c9f..a3599a5f2 100644 --- a/src/podcast/podcast.pri +++ b/src/podcast/podcast.pri @@ -67,7 +67,7 @@ linux-g++* { -lxcb-xfixes \ -lxcb-render -lxcb-shape -lxcb -lX11 -lasound -lSDL -lx264 -lpthread -lvpx -lvorbisenc -lvorbis -ltheoraenc -ltheoradec -logg -lopus -lmp3lame -lfreetype -lfdk-aac -lass -llzma -lbz2 -lz -ldl -lswresample -lswscale -lavutil -lm - FFMPEG_VERSION = $$system(ffmpeg --version|& grep -oP "version.*?\K[0-9]\.[0-9]") + FFMPEG_VERSION = $$system(ffmpeg --version 2>&1 | grep -oP "version.*?\K[0-9]\.[0-9]") equals(FFMPEG_VERSION, 2.8) { LIBS -= -lswresample LIBS += -lavresample From e915daff9353795b18350168699e7c2fcd08ce73 Mon Sep 17 00:00:00 2001 From: Vekhir Date: Wed, 14 Aug 2024 21:15:29 +0200 Subject: [PATCH 003/133] refactor(tabwidget): Use different overload of addAction The old ordering is deprecated and a new overload with different ordering of arguments is provided. --- src/web/simplebrowser/tabwidget.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/web/simplebrowser/tabwidget.cpp b/src/web/simplebrowser/tabwidget.cpp index 39b70ac93..1c189eac5 100644 --- a/src/web/simplebrowser/tabwidget.cpp +++ b/src/web/simplebrowser/tabwidget.cpp @@ -120,7 +120,11 @@ void TabWidget::handleCurrentChanged(int index) void TabWidget::handleContextMenuRequested(const QPoint &pos) { QMenu menu; +#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)) + menu.addAction(tr("New &Tab"), QKeySequence::AddTab, this, &TabWidget::createTab); +#else menu.addAction(tr("New &Tab"), this, &TabWidget::createTab, QKeySequence::AddTab); +#endif int index = tabBar()->tabAt(pos); if (index != -1) { QAction *action = menu.addAction(tr("Clone Tab")); From 41ba5bdcb2d6d10106eccec579e0e2db93c5e9e5 Mon Sep 17 00:00:00 2001 From: Vekhir Date: Mon, 3 Feb 2025 01:32:43 +0100 Subject: [PATCH 004/133] refactor(UBFFmpegVideoEncoder): Use avcodec_get_supported_config FFmpeg 7.1 introduces avcodec_get_supported_config to query available sample formats. It basically copies over sample_fmts, but doing so directly is deprecated. --- src/podcast/ffmpeg/UBFFmpegVideoEncoder.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/podcast/ffmpeg/UBFFmpegVideoEncoder.cpp b/src/podcast/ffmpeg/UBFFmpegVideoEncoder.cpp index 24451f27a..b2111d932 100644 --- a/src/podcast/ffmpeg/UBFFmpegVideoEncoder.cpp +++ b/src/podcast/ffmpeg/UBFFmpegVideoEncoder.cpp @@ -448,7 +448,19 @@ bool UBFFmpegVideoEncoder::init() } c->bit_rate = 96000; - c->sample_fmt = audioCodec->sample_fmts ? audioCodec->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;// FLTP by default for AAC + + const AVSampleFormat* sample_fmts; +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(61, 19, 100) + sample_fmts = audioCodec->sample_fmts; +#else + int err = avcodec_get_supported_config(nullptr, audioCodec, AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, (const void**)&sample_fmts, nullptr); + if (err) { + setLastErrorMessage("Could not get supported sample formats"); + return false; + } +#endif + c->sample_fmt = sample_fmts ? sample_fmts[0] : AV_SAMPLE_FMT_FLTP;// FLTP by default for AAC + c->sample_rate = mAudioSampleRate; #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 25, 100) From 0362ff97ed7c92f212f6feb48892693adfbd7528 Mon Sep 17 00:00:00 2001 From: Vekhir Date: Wed, 14 Aug 2024 21:34:07 +0200 Subject: [PATCH 005/133] refactor(UBPreferencesController): narrow lambda capture Using the default capture `=` captures more than it has to and leads to ambiguity whether the object is capture by value or by reference. This produces a warning in C++20. Exactly enumerate the captured variables to resolve the warning. --- src/core/UBPreferencesController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/UBPreferencesController.cpp b/src/core/UBPreferencesController.cpp index ed0e393d8..2e191d580 100644 --- a/src/core/UBPreferencesController.cpp +++ b/src/core/UBPreferencesController.cpp @@ -186,7 +186,7 @@ void UBPreferencesController::wire() connect(mPreferencesUI->emptyTrashDaysValue, SIGNAL(valueChanged(int)), settings->emptyTrashDaysValue, SLOT(setInt(int))); - connect(mPreferencesUI->keyboardPaletteKeyButtonSize, qOverload(&QComboBox::currentIndexChanged), settings->boardKeyboardPaletteKeyBtnSize, [=](int index) { + connect(mPreferencesUI->keyboardPaletteKeyButtonSize, qOverload(&QComboBox::currentIndexChanged), settings->boardKeyboardPaletteKeyBtnSize, [this, settings](int index) { settings->boardKeyboardPaletteKeyBtnSize->setString(mPreferencesUI->keyboardPaletteKeyButtonSize->itemText(index)); }); connect(mPreferencesUI->startModeComboBox, SIGNAL(currentIndexChanged(int)), settings->appStartMode, SLOT(setInt(int))); From 237789e48bad972614dafc7f9750054f52ab3a8a Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 6 Apr 2025 12:11:34 +0200 Subject: [PATCH 006/133] refactor: let items know their media assets - currently the relative dependencies to the media asset files are not known by the graphics items - instead the scene has functions to derive that information depending on the item type - create abstract class UBMediaAssetItem to move the information about the media asset to the item - add UBGraphicsPDFItem to the list of media items to enable handling of the underlaying PDF file as media asset - store name of underlying image file in UBGraphicsPixmapItem - get relative dependencies by just querying the items - also provide a setter to inform the items about the asset path - convert legacy function getRelativeDependencies to return a list of QString - adjust invokers of this function, which previously used a variety of functions to convert the QUrl back to a QString. - remove UBGraphicsItem::clearSource() - items must never delete their media asset files, as they do not know whether they are referenced by some other item - removal of media asset files is handled later with the TOC Signed-off-by: letsfindaway --- src/adaptors/UBSvgSubsetAdaptor.cpp | 4 +- src/board/UBBoardController.cpp | 6 +- src/core/UBPersistenceManager.cpp | 6 +- src/document/UBDocumentController.cpp | 13 ++-- src/domain/CMakeLists.txt | 1 + src/domain/UBGraphicsGroupContainerItem.cpp | 12 ---- src/domain/UBGraphicsGroupContainerItem.h | 2 - src/domain/UBGraphicsMediaItem.cpp | 32 +++++---- src/domain/UBGraphicsMediaItem.h | 64 +++++++++--------- src/domain/UBGraphicsPDFItem.cpp | 11 ++-- src/domain/UBGraphicsPDFItem.h | 32 ++++----- src/domain/UBGraphicsPixmapItem.cpp | 29 ++++---- src/domain/UBGraphicsPixmapItem.h | 32 +++++---- src/domain/UBGraphicsScene.cpp | 73 +++++---------------- src/domain/UBGraphicsScene.h | 5 +- src/domain/UBGraphicsSvgItem.cpp | 21 ++---- src/domain/UBGraphicsSvgItem.h | 30 ++++----- src/domain/UBGraphicsTextItem.h | 1 - src/domain/UBGraphicsWidgetItem.cpp | 28 ++++++-- src/domain/UBGraphicsWidgetItem.h | 28 ++++---- src/domain/UBItem.h | 2 - src/domain/UBMediaAssetItem.h | 40 +++++++++++ src/domain/domain.pri | 1 + src/frameworks/UBCoreGraphicsScene.cpp | 4 -- src/tools/UBGraphicsCurtainItem.h | 1 - 25 files changed, 242 insertions(+), 236 deletions(-) create mode 100644 src/domain/UBMediaAssetItem.h diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index 5f2a30840..910516172 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -2176,11 +2176,13 @@ UBGraphicsPixmapItem* UBSvgSubsetAdaptor::UBSvgSubsetReader::pixmapItemFromSvg() { pixmapItem = new UBGraphicsPixmapItem(); QString href = imageHref.toString(); - QImageReader rdr(mDocumentPath + "/" + UBFileSystemUtils::normalizeFilePath(href)); + const auto asset = UBFileSystemUtils::normalizeFilePath(href); + QImageReader rdr(mDocumentPath + "/" + asset); rdr.setAutoTransform(true); QImage img = rdr.read(); QPixmap pix = QPixmap::fromImage(img); pixmapItem->setPixmap(pix); + pixmapItem->setMediaAsset(mDocumentPath, asset); graphicsItemFromSvg(pixmapItem); } else diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index fca71703d..b0d305e1e 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -666,10 +666,10 @@ void UBBoardController::addScene(std::shared_ptr scene, bool re if (scene->document() && (scene->document() != selectedDocument())) { - foreach(QUrl relativeFile, scene->relativeDependencies()) + foreach(QString relativeFile, scene->relativeDependencies()) { - QString source = scene->document()->persistencePath() + "/" + relativeFile.path(); - QString destination = selectedDocument()->persistencePath() + "/" + relativeFile.path(); + QString source = scene->document()->persistencePath() + "/" + relativeFile; + QString destination = selectedDocument()->persistencePath() + "/" + relativeFile; UBFileSystemUtils::copy(source, destination, true); } diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index c532ae836..2aaf23047 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -792,10 +792,10 @@ void UBPersistenceManager::deleteDocumentScenes(std::shared_ptr if (scene) { //scene is about to move into new document - foreach (QUrl relativeFile, scene->relativeDependencies()) + foreach (QString relativeFile, scene->relativeDependencies()) { - QString source = scene->document()->persistencePath() + "/" + relativeFile.toString(); - QString target = trashDocProxy->persistencePath() + "/" + relativeFile.toString(); + QString source = scene->document()->persistencePath() + "/" + relativeFile; + QString target = trashDocProxy->persistencePath() + "/" + relativeFile; QFileInfo fi(target); QDir d = fi.dir(); diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index e4c92dd5e..3ab9f67eb 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -1661,21 +1661,18 @@ void UBDocumentTreeView::dropEvent(QDropEvent *event) std::shared_ptr targetDocProxy = docModel->proxyForIndex(targetIndex); - foreach (QUrl relativeFile, scene->relativeDependencies()) + foreach (QString relativeFile, scene->relativeDependencies()) { - QString source = scene->document()->persistencePath() + "/" + relativeFile.toString(); - QString target = targetDocProxy->persistencePath() + "/" + relativeFile.toString(); - - QString sourceDecoded = scene->document()->persistencePath() + "/" + relativeFile.toString(QUrl::DecodeReserved); - QString targetDecoded = targetDocProxy->persistencePath() + "/" + relativeFile.toString(QUrl::DecodeReserved); + QString source = scene->document()->persistencePath() + "/" + relativeFile; + QString target = targetDocProxy->persistencePath() + "/" + relativeFile; if(QFileInfo(source).isDir()) UBFileSystemUtils::copyDir(source,target); else{ - QFileInfo fi(targetDecoded); + QFileInfo fi(target); QDir d = fi.dir(); d.mkpath(d.absolutePath()); - QFile::copy(sourceDecoded, targetDecoded); + QFile::copy(source, target); } } diff --git a/src/domain/CMakeLists.txt b/src/domain/CMakeLists.txt index 15bcab6b5..9e8579562 100644 --- a/src/domain/CMakeLists.txt +++ b/src/domain/CMakeLists.txt @@ -45,6 +45,7 @@ target_sources(${PROJECT_NAME} PRIVATE UBGraphicsWidgetItemDelegate.h UBItem.cpp UBItem.h + UBMediaAssetItem.h UBPageSizeUndoCommand.cpp UBPageSizeUndoCommand.h UBResizableGraphicsItem.cpp diff --git a/src/domain/UBGraphicsGroupContainerItem.cpp b/src/domain/UBGraphicsGroupContainerItem.cpp index 974c10101..7daa31b1b 100644 --- a/src/domain/UBGraphicsGroupContainerItem.cpp +++ b/src/domain/UBGraphicsGroupContainerItem.cpp @@ -262,18 +262,6 @@ void UBGraphicsGroupContainerItem::destroy(bool canUndo) { remove(canUndo); } -void UBGraphicsGroupContainerItem::clearSource() -{ - foreach(QGraphicsItem *child, childItems()) - { - UBGraphicsItem *item = dynamic_cast(child); - if (item) - { - item->clearSource(); - } - } -} - void UBGraphicsGroupContainerItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (Delegate()->mousePressEvent(event)) { diff --git a/src/domain/UBGraphicsGroupContainerItem.h b/src/domain/UBGraphicsGroupContainerItem.h index 1c99e4ba4..9ae8d8aba 100644 --- a/src/domain/UBGraphicsGroupContainerItem.h +++ b/src/domain/UBGraphicsGroupContainerItem.h @@ -66,8 +66,6 @@ class UBGraphicsGroupContainerItem : public QGraphicsItem, public UBItem, public virtual void setUuid(const QUuid &pUuid); void destroy(bool canUndo = true); - virtual void clearSource(); - protected: virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); diff --git a/src/domain/UBGraphicsMediaItem.cpp b/src/domain/UBGraphicsMediaItem.cpp index 8b1c7b112..0ab67c05c 100644 --- a/src/domain/UBGraphicsMediaItem.cpp +++ b/src/domain/UBGraphicsMediaItem.cpp @@ -34,8 +34,10 @@ #include "UBGraphicsDelegateFrame.h" #include "document/UBDocumentProxy.h" #include "core/UBApplication.h" +#include "core/UBPersistenceManager.h" #include "board/UBBoardController.h" #include "core/memcheck.h" +#include "frameworks/UBFileSystemUtils.h" #include @@ -137,6 +139,13 @@ UBGraphicsAudioItem::UBGraphicsAudioItem(const QUrl &pMediaFileUrl, QGraphicsIte #endif } +QList UBGraphicsAudioItem::mediaAssets() const +{ + const QString completeFileName = QFileInfo(mediaFileUrl().toLocalFile()).fileName(); + const QString path = UBPersistenceManager::audioDirectory + "/"; + return {path + completeFileName}; +} + UBGraphicsVideoItem::UBGraphicsVideoItem(const QUrl &pMediaFileUrl, QGraphicsItem *parent) :UBGraphicsMediaItem(pMediaFileUrl, parent) { @@ -192,6 +201,13 @@ UBGraphicsVideoItem::UBGraphicsVideoItem(const QUrl &pMediaFileUrl, QGraphicsIte update(); } +QList UBGraphicsVideoItem::mediaAssets() const +{ + const QString completeFileName = QFileInfo(mediaFileUrl().toLocalFile()).fileName(); + const QString path = UBPersistenceManager::videoDirectory + "/"; + return {path + completeFileName}; +} + UBGraphicsMediaItem::~UBGraphicsMediaItem() { } @@ -349,17 +365,6 @@ void UBGraphicsMediaItem::setSourceUrl(const QUrl &pSourceUrl) UBItem::setSourceUrl(pSourceUrl); } -void UBGraphicsMediaItem::clearSource() -{ - QString path = mediaFileUrl().toLocalFile(); - //if path is absolute clean duplicated path string - if (!path.contains(UBApplication::boardController->selectedDocument()->persistencePath())) - path = UBApplication::boardController->selectedDocument()->persistencePath() + "/" + path; - - if (!UBFileSystemUtils::deleteFile(path)) - qDebug() << "cannot delete file: " << path; -} - void UBGraphicsMediaItem::toggleMute() { mMuted = !mMuted; @@ -572,6 +577,11 @@ QRectF UBGraphicsMediaItem::boundingRect() const return rect(); } +void UBGraphicsMediaItem::setMediaAsset(const QString& documentPath, const QString& mediaAsset) +{ + setMediaFileUrl(QUrl::fromLocalFile(documentPath + "/" + mediaAsset)); +} + void UBGraphicsMediaItem::setSize(int width, int height) { QRectF r = rect(); diff --git a/src/domain/UBGraphicsMediaItem.h b/src/domain/UBGraphicsMediaItem.h index 7223728a7..e9bddfc15 100644 --- a/src/domain/UBGraphicsMediaItem.h +++ b/src/domain/UBGraphicsMediaItem.h @@ -32,21 +32,19 @@ #include -#include +// #include #include -#include -#include +// #include +// #include -#include "core/UBApplication.h" #include "board/UBBoardController.h" -#include "domain/UBItem.h" +#include "domain/UBMediaAssetItem.h" #include "domain/UBResizableGraphicsItem.h" -#include "frameworks/UBFileSystemUtils.h" class QGraphicsVideoItem; -class UBGraphicsMediaItem : public QObject, public UBItem, public UBGraphicsItem, public QGraphicsRectItem, public UBResizableGraphicsItem +class UBGraphicsMediaItem : public QObject, public UBMediaAssetItem, public UBGraphicsItem, public QGraphicsRectItem, public UBResizableGraphicsItem { Q_OBJECT @@ -73,7 +71,7 @@ class UBGraphicsMediaItem : public QObject, public UBItem, public UBGraphicsItem virtual mediaType getMediaType() const = 0; - virtual std::shared_ptr scene(); + virtual std::shared_ptr scene() override; bool hasLinkedImage() const { return haveLinkedImage; } virtual QUrl mediaFileUrl() const { return mMediaFileUrl; } bool isMuted() const { return mMuted; } @@ -97,25 +95,26 @@ class UBGraphicsMediaItem : public QObject, public UBItem, public UBGraphicsItem bool firstLoad() const; void setFirstLoad(bool firstLoad); - QRectF boundingRect() const; + QRectF boundingRect() const override; - QSizeF size() const { return rect().size(); } + QSizeF size() const override { return rect().size(); } // Setters + virtual void setMediaAsset(const QString& documentPath, const QString& mediaAsset) override; virtual void setMediaFileUrl(QUrl url); void setInitialPos(qint64 p); void setMediaPos(qint64 p); - virtual void setSourceUrl(const QUrl &pSourceUrl); + virtual void setSourceUrl(const QUrl &pSourceUrl) override; void setSelected(bool selected); void setMinimumSize(const QSize& size); - void setUuid(const QUuid &pUuid); + void setUuid(const QUuid &pUuid) override; - virtual void copyItemParameters(UBItem *copy) const; + virtual void copyItemParameters(UBItem *copy) const override; virtual void setSize(int width, int height); - void resize(qreal w, qreal h) { setSize(w, h); } + void resize(qreal w, qreal h) override { setSize(w, h); } - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; public slots: @@ -135,10 +134,8 @@ protected slots: protected: - virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); - virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); - - virtual void clearSource(); + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override; QMediaPlayer *mMediaObject; @@ -171,15 +168,18 @@ class UBGraphicsAudioItem: public UBGraphicsMediaItem public: enum { Type = UBGraphicsItemType::AudioItemType}; - virtual int type() const + virtual int type() const override { return Type; } UBGraphicsAudioItem(const QUrl& pMediaFileUrl, QGraphicsItem *parent = 0); - mediaType getMediaType() const { return mediaType_Audio; } - virtual UBItem* deepCopy() const; + virtual QList mediaAssets() const override; + + mediaType getMediaType() const override { return mediaType_Audio; } + + virtual UBItem* deepCopy() const override; }; class UBGraphicsVideoItem: public UBGraphicsMediaItem @@ -188,20 +188,22 @@ class UBGraphicsVideoItem: public UBGraphicsMediaItem public: enum { Type = UBGraphicsItemType::VideoItemType}; - virtual int type() const + virtual int type() const override { return Type; } UBGraphicsVideoItem(const QUrl& pMediaFileUrl, QGraphicsItem *parent = 0); - mediaType getMediaType() const { return mediaType_Video; } + virtual QList mediaAssets() const override; + + mediaType getMediaType() const override { return mediaType_Video; } - void setSize(int width, int height); + void setSize(int width, int height) override; - virtual UBItem* deepCopy() const; + virtual UBItem* deepCopy() const override; - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; public slots: void videoSizeChanged(QSizeF newSize); @@ -222,10 +224,10 @@ protected slots: QGraphicsVideoItem *mVideoItem; - virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); - virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event); - virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); - virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; + virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; + virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override; + virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; void setPlaceholderVisible(bool visible); diff --git a/src/domain/UBGraphicsPDFItem.cpp b/src/domain/UBGraphicsPDFItem.cpp index 372317b88..b996ef44c 100644 --- a/src/domain/UBGraphicsPDFItem.cpp +++ b/src/domain/UBGraphicsPDFItem.cpp @@ -35,6 +35,7 @@ #include "UBGraphicsPixmapItem.h" #include "UBGraphicsItemDelegate.h" +#include "core/UBPersistenceManager.h" #include "core/memcheck.h" UBGraphicsPDFItem::UBGraphicsPDFItem(PDFRenderer *renderer, int pageNumber, QGraphicsItem* parent) @@ -51,6 +52,10 @@ UBGraphicsPDFItem::~UBGraphicsPDFItem() { } +QList UBGraphicsPDFItem::mediaAssets() const +{ + return {UBPersistenceManager::objectDirectory + "/" + fileUuid().toString() + ".pdf"}; +} QVariant UBGraphicsPDFItem::itemChange(GraphicsItemChange change, const QVariant &value) { @@ -68,12 +73,6 @@ void UBGraphicsPDFItem::updateChild() setCacheMode(prevCacheMode); } -void UBGraphicsPDFItem::setUuid(const QUuid &pUuid) -{ - UBItem::setUuid(pUuid); - setData(UBGraphicsItemData::ItemUuid, QVariant(pUuid)); -} - void UBGraphicsPDFItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (Delegate()->mousePressEvent(event)) diff --git a/src/domain/UBGraphicsPDFItem.h b/src/domain/UBGraphicsPDFItem.h index 4fe21169f..c9a9ae2db 100644 --- a/src/domain/UBGraphicsPDFItem.h +++ b/src/domain/UBGraphicsPDFItem.h @@ -32,7 +32,7 @@ #include -#include "UBItem.h" +#include "UBMediaAssetItem.h" #include "core/UB.h" #include "pdf/GraphicsPDFItem.h" @@ -40,7 +40,7 @@ class UBGraphicsItemDelegate; class UBGraphicsPixmapItem; -class UBGraphicsPDFItem: public GraphicsPDFItem, public UBItem, public UBGraphicsItem +class UBGraphicsPDFItem: public GraphicsPDFItem, public UBMediaAssetItem, public UBGraphicsItem { public: UBGraphicsPDFItem(PDFRenderer *renderer, int pageNumber, QGraphicsItem* parent = 0); @@ -48,34 +48,34 @@ class UBGraphicsPDFItem: public GraphicsPDFItem, public UBItem, public UBGraphic enum { Type = UBGraphicsItemType::PDFItemType }; - virtual int type() const + virtual int type() const override { return Type; } - virtual UBItem* deepCopy() const; + virtual QList mediaAssets() const override; - virtual void copyItemParameters(UBItem *copy) const; + virtual UBItem* deepCopy() const override; - virtual void setRenderingQuality(RenderingQuality pRenderingQuality); + virtual void copyItemParameters(UBItem *copy) const override; - virtual void setCacheBehavior(CacheBehavior cacheBehavior); + virtual void setRenderingQuality(RenderingQuality pRenderingQuality) override; - virtual std::shared_ptr scene(); + virtual void setCacheBehavior(CacheBehavior cacheBehavior) override; + + virtual std::shared_ptr scene() override; virtual UBGraphicsPixmapItem* toPixmapItem() const; - virtual void clearSource(){;} - virtual void setUuid(const QUuid &pUuid); protected: - virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override; + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); - virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); - virtual void updateChild(); + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; + virtual void updateChild() override; private slots: void OnRequireUpdate(); }; diff --git a/src/domain/UBGraphicsPixmapItem.cpp b/src/domain/UBGraphicsPixmapItem.cpp index ccb7d10a7..265aa52c3 100644 --- a/src/domain/UBGraphicsPixmapItem.cpp +++ b/src/domain/UBGraphicsPixmapItem.cpp @@ -63,13 +63,23 @@ UBGraphicsPixmapItem::UBGraphicsPixmapItem(QGraphicsItem* parent) setData(UBGraphicsItemData::ItemCanBeSetAsBackground, true); - setUuid(QUuid::createUuid()); //more logical solution is in creating uuid for element in element's constructor + UBGraphicsPixmapItem::setUuid(QUuid::createUuid()); //more logical solution is in creating uuid for element in element's constructor } UBGraphicsPixmapItem::~UBGraphicsPixmapItem() { } +QList UBGraphicsPixmapItem::mediaAssets() const +{ + if (!mMediaAsset.isEmpty()) + { + return {mMediaAsset}; + } + + return {}; +} + QVariant UBGraphicsPixmapItem::itemChange(GraphicsItemChange change, const QVariant &value) { QVariant newValue = Delegate()->itemChange(change, value); @@ -82,6 +92,11 @@ void UBGraphicsPixmapItem::setUuid(const QUuid &pUuid) setData(UBGraphicsItemData::ItemUuid, QVariant(pUuid)); } +void UBGraphicsPixmapItem::setMediaAsset(const QString& documentPath, const QString& mediaAsset) +{ + mMediaAsset = mediaAsset; +} + void UBGraphicsPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { QMimeData* pMime = new QMimeData(); @@ -187,15 +202,3 @@ qreal UBGraphicsPixmapItem::opacity() const { return QGraphicsPixmapItem::opacity(); } - - -void UBGraphicsPixmapItem::clearSource() -{ - QDir imageDir = UBApplication::boardController->selectedDocument()->persistencePath() + "/" + UBPersistenceManager::imageDirectory; - const QStringList imageFiles = imageDir.entryList({uuid().toString() + ".*"}); - - for (const auto& imageFile : imageFiles) - { - UBFileSystemUtils::deleteFile(imageFile); - } -} diff --git a/src/domain/UBGraphicsPixmapItem.h b/src/domain/UBGraphicsPixmapItem.h index ddc794172..274d18136 100644 --- a/src/domain/UBGraphicsPixmapItem.h +++ b/src/domain/UBGraphicsPixmapItem.h @@ -34,11 +34,11 @@ #include "core/UB.h" -#include "UBItem.h" +#include "UBMediaAssetItem.h" class UBGraphicsItemDelegate; -class UBGraphicsPixmapItem : public QObject, public QGraphicsPixmapItem, public UBItem, public UBGraphicsItem +class UBGraphicsPixmapItem : public QObject, public QGraphicsPixmapItem, public UBMediaAssetItem, public UBGraphicsItem { Q_OBJECT @@ -48,34 +48,40 @@ class UBGraphicsPixmapItem : public QObject, public QGraphicsPixmapItem, public enum { Type = UBGraphicsItemType::PixmapItemType }; - virtual int type() const + virtual int type() const override { return Type; } - virtual UBItem* deepCopy() const; - virtual void copyItemParameters(UBItem *copy) const; + virtual QList mediaAssets() const override; - virtual std::shared_ptr scene(); + virtual UBItem* deepCopy() const override; + + virtual void copyItemParameters(UBItem *copy) const override; + + virtual std::shared_ptr scene() override; Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity) void setOpacity(qreal op); qreal opacity() const; - virtual void clearSource(); + virtual void setUuid(const QUuid &pUuid) override; - virtual void setUuid(const QUuid &pUuid); + virtual void setMediaAsset(const QString& documentPath, const QString& mediaAsset) override; protected: - virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override; + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; - virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); +private: + QString mMediaAsset; }; #endif /* UBGRAPHICSPIXMAPITEM_H_ */ diff --git a/src/domain/UBGraphicsScene.cpp b/src/domain/UBGraphicsScene.cpp index f8ccacdb6..21b272ab6 100644 --- a/src/domain/UBGraphicsScene.cpp +++ b/src/domain/UBGraphicsScene.cpp @@ -1635,6 +1635,7 @@ UBGraphicsPixmapItem* UBGraphicsScene::addImage(QByteArray pData, QGraphicsItem* } QString fileName = UBPersistenceManager::imageDirectory + "/" + pixmapItem->uuid().toString() + "." + format; + pixmapItem->setMediaAsset(documentPath, fileName); QString path = documentPath + "/" + fileName; @@ -2676,76 +2677,38 @@ void UBGraphicsScene::setRenderingQuality(UBItem::RenderingQuality pRenderingQua } } -QList UBGraphicsScene::relativeDependenciesOfItem(QGraphicsItem* item) const +QList UBGraphicsScene::relativeDependencies() const { - QList relativePaths; + QList relativePaths; - UBGraphicsVideoItem *videoItem = dynamic_cast (item); - if (videoItem){ - QString completeFileName = QFileInfo(videoItem->mediaFileUrl().toLocalFile()).fileName(); - QString path = UBPersistenceManager::videoDirectory + "/"; - relativePaths << QUrl(path + completeFileName); - return relativePaths; - } - - UBGraphicsAudioItem *audioItem = dynamic_cast (item); - if (audioItem){ - QString completeFileName = QFileInfo(audioItem->mediaFileUrl().toLocalFile()).fileName(); - QString path = UBPersistenceManager::audioDirectory + "/"; - relativePaths << QUrl(path + completeFileName); - return relativePaths; - } - - UBGraphicsWidgetItem* widget = dynamic_cast(item); - if(widget){ - QString widgetPath = UBPersistenceManager::widgetDirectory + "/" + widget->uuid().toString() + ".wgt"; - QString screenshotPath = UBPersistenceManager::widgetDirectory + "/" + widget->uuid().toString().remove("{").remove("}") + ".png"; - relativePaths << QUrl(widgetPath); - relativePaths << QUrl(screenshotPath); - return relativePaths; - } - - UBGraphicsPixmapItem* pixmapItem = dynamic_cast(item); - if(pixmapItem){ - QDir imageDir = mDocument->persistencePath() + "/" + UBPersistenceManager::imageDirectory; - QStringList imageFiles = imageDir.entryList({pixmapItem->uuid().toString() + ".*"}); - - if (!imageFiles.isEmpty()) - { - relativePaths << QUrl(UBPersistenceManager::imageDirectory + "/" + imageFiles.last()); - } - - return relativePaths; + for (const auto item : mediaAssetItems()) + { + relativePaths << item->mediaAssets(); } - UBGraphicsSvgItem* svgItem = dynamic_cast(item); - if(svgItem){ - relativePaths << QUrl(UBPersistenceManager::imageDirectory + "/" + svgItem->uuid().toString() + ".svg"); - return relativePaths; - } + // remove duplicates + std::sort(relativePaths.begin(), relativePaths.end()); + relativePaths.erase(std::unique(relativePaths.begin(), relativePaths.end()), relativePaths.end()); return relativePaths; } -QList UBGraphicsScene::relativeDependencies() const +QList UBGraphicsScene::mediaAssetItems() const { - QList relativePaths; + QList mediaAssetItemList; - foreach(auto item, items()) + for (const auto item : items()) { - UBGraphicsGroupContainerItem* groupItem = dynamic_cast(item); - if(groupItem) + // items() returns a list of all items, including child items + const auto mediaAssetItem = dynamic_cast(item); + + if (mediaAssetItem) { - foreach (QGraphicsItem* child, groupItem->childItems()) - { - relativePaths << relativeDependenciesOfItem(child); - } + mediaAssetItemList << mediaAssetItem; } - else - relativePaths << relativeDependenciesOfItem(item); } - return relativePaths; + return mediaAssetItemList; } QSize UBGraphicsScene::nominalSize() diff --git a/src/domain/UBGraphicsScene.h b/src/domain/UBGraphicsScene.h index e0113d3d2..1552a3ea4 100644 --- a/src/domain/UBGraphicsScene.h +++ b/src/domain/UBGraphicsScene.h @@ -57,6 +57,7 @@ class UBMagnifierParams; class UBMagnifier; class UBGraphicsCache; class UBGraphicsGroupContainerItem; +class UBMediaAssetItem; class UBSelectionFrame; class UBBoardView; @@ -285,8 +286,8 @@ class UBGraphicsScene: public UBCoreGraphicsScene, public UBItem, public std::en virtual void setRenderingQuality(UBItem::RenderingQuality pRenderingQuality, UBItem::CacheBehavior cacheBehavior); - QList relativeDependenciesOfItem(QGraphicsItem* item) const; - QList relativeDependencies() const; + QList relativeDependencies() const; + QList mediaAssetItems() const; QSize nominalSize(); diff --git a/src/domain/UBGraphicsSvgItem.cpp b/src/domain/UBGraphicsSvgItem.cpp index cdef67048..b5965573c 100644 --- a/src/domain/UBGraphicsSvgItem.cpp +++ b/src/domain/UBGraphicsSvgItem.cpp @@ -89,13 +89,18 @@ void UBGraphicsSvgItem::init() setData(UBGraphicsItemData::ItemCanBeSetAsBackground, true); - setUuid(QUuid::createUuid()); + UBGraphicsSvgItem::setUuid(QUuid::createUuid()); } UBGraphicsSvgItem::~UBGraphicsSvgItem() { } +QList UBGraphicsSvgItem::mediaAssets() const +{ + return {UBPersistenceManager::imageDirectory + "/" + uuid().toString() + ".svg"}; +} + QByteArray UBGraphicsSvgItem::fileData() const { @@ -229,17 +234,3 @@ UBGraphicsPixmapItem* UBGraphicsSvgItem::toPixmapItem() const return pixmapItem; } - -void UBGraphicsSvgItem::setUuid(const QUuid &pUuid) -{ - UBItem::setUuid(pUuid); - setData(UBGraphicsItemData::ItemUuid, QVariant(pUuid)); //store item uuid inside the QGraphicsItem to fast operations with Items on the scene -} - - -void UBGraphicsSvgItem::clearSource() -{ - QString fileName = UBPersistenceManager::imageDirectory + "/" + uuid().toString() + ".svg"; - QString diskPath = UBApplication::boardController->selectedDocument()->persistencePath() + "/" + fileName; - UBFileSystemUtils::deleteFile(diskPath); -} diff --git a/src/domain/UBGraphicsSvgItem.h b/src/domain/UBGraphicsSvgItem.h index f831c99a2..799941be5 100644 --- a/src/domain/UBGraphicsSvgItem.h +++ b/src/domain/UBGraphicsSvgItem.h @@ -33,14 +33,14 @@ #include #include -#include "UBItem.h" +#include "UBMediaAssetItem.h" #include "core/UB.h" class UBGraphicsItemDelegate; class UBGraphicsPixmapItem; -class UBGraphicsSvgItem: public QGraphicsSvgItem, public UBItem, public UBGraphicsItem +class UBGraphicsSvgItem: public QGraphicsSvgItem, public UBMediaAssetItem, public UBGraphicsItem { public: UBGraphicsSvgItem(const QString& pFile, QGraphicsItem* parent = 0); @@ -50,6 +50,8 @@ class UBGraphicsSvgItem: public QGraphicsSvgItem, public UBItem, public UBGraphi virtual ~UBGraphicsSvgItem(); + virtual QList mediaAssets() const override; + QByteArray fileData() const; void setFileData(const QByteArray& pFileData) @@ -59,34 +61,30 @@ class UBGraphicsSvgItem: public QGraphicsSvgItem, public UBItem, public UBGraphi enum { Type = UBGraphicsItemType::SvgItemType }; - virtual int type() const + virtual int type() const override { return Type; } - virtual UBItem* deepCopy() const; + virtual UBItem* deepCopy() const override; - virtual void copyItemParameters(UBItem *copy) const; + virtual void copyItemParameters(UBItem *copy) const override; - virtual void setRenderingQuality(RenderingQuality pRenderingQuality); + virtual void setRenderingQuality(RenderingQuality pRenderingQuality) override; - virtual std::shared_ptr scene(); + virtual std::shared_ptr scene() override; virtual UBGraphicsPixmapItem* toPixmapItem() const; - virtual void setUuid(const QUuid &pUuid); - - virtual void clearSource(); - protected: - virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override; + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; - virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; QByteArray mFileData; }; diff --git a/src/domain/UBGraphicsTextItem.h b/src/domain/UBGraphicsTextItem.h index a06470e2c..62217029d 100644 --- a/src/domain/UBGraphicsTextItem.h +++ b/src/domain/UBGraphicsTextItem.h @@ -95,7 +95,6 @@ class UBGraphicsTextItem : public QGraphicsTextItem, public UBItem, public UBRes mColorOnLightBackground = pColorOnLightBackground; } - virtual void clearSource(){;} virtual void setUuid(const QUuid &pUuid); void activateTextEditor(bool activate); void setSelected(bool selected); diff --git a/src/domain/UBGraphicsWidgetItem.cpp b/src/domain/UBGraphicsWidgetItem.cpp index ce285bb6a..81420550e 100644 --- a/src/domain/UBGraphicsWidgetItem.cpp +++ b/src/domain/UBGraphicsWidgetItem.cpp @@ -48,6 +48,7 @@ #include "core/memcheck.h" #include "core/UBApplicationController.h" #include "core/UBApplication.h" +#include "core/UBPersistenceManager.h" #include "core/UBSettings.h" #include "frameworks/UBFileSystemUtils.h" @@ -198,6 +199,13 @@ UBGraphicsWidgetItem::~UBGraphicsWidgetItem() delete mWebEngineView; } +QList UBGraphicsWidgetItem::mediaAssets() const +{ + const QString widgetPath = UBPersistenceManager::widgetDirectory + "/" + uuid().toString() + ".wgt"; + const QString screenshotPath = UBPersistenceManager::widgetDirectory + "/" + uuid().toString(QUuid::WithoutBraces) + ".png"; + return {widgetPath, screenshotPath}; +} + void UBGraphicsWidgetItem::initialize() { setMinimumSize(nominalSize()); @@ -390,12 +398,6 @@ QUrl UBGraphicsWidgetItem::getSnapshotPath() const return mSnapshotFile; } -void UBGraphicsWidgetItem::clearSource() -{ - UBFileSystemUtils::deleteDir(getOwnFolder().toLocalFile()); - UBFileSystemUtils::deleteFile(getSnapshotPath().toLocalFile()); -} - void UBGraphicsWidgetItem::setUuid(const QUuid &pUuid) { UBItem::setUuid(pUuid); @@ -1016,6 +1018,10 @@ UBItem* UBGraphicsAppleWidgetItem::deepCopy() const } +void UBGraphicsAppleWidgetItem::setMediaAsset(const QString& documentPath, const QString& mediaAsset) +{ +} + void UBGraphicsAppleWidgetItem::copyItemParameters(UBItem *copy) const { UBGraphicsAppleWidgetItem *cp = dynamic_cast(copy); @@ -1527,3 +1533,13 @@ void UBGraphicsW3CWidgetItem::copyItemParameters(UBItem *copy) const } } +void UBGraphicsW3CWidgetItem::setMediaAsset(const QString& documentPath, const QString& mediaAsset) +{ + if (mediaAsset.endsWith(".wgt")) + { + widgetUrl(QUrl::fromLocalFile(documentPath + "/" + mediaAsset)); + setOwnFolder(widgetUrl()); + mMainHtmlUrl.setPath(widgetUrl().path() + "/" + mMainHtmlFileName); + } +} + diff --git a/src/domain/UBGraphicsWidgetItem.h b/src/domain/UBGraphicsWidgetItem.h index 0919651ae..25f150f64 100644 --- a/src/domain/UBGraphicsWidgetItem.h +++ b/src/domain/UBGraphicsWidgetItem.h @@ -36,7 +36,7 @@ #include "core/UB.h" -#include "UBItem.h" +#include "UBMediaAssetItem.h" #include "UBResizableGraphicsItem.h" class QWebChannel; @@ -57,7 +57,7 @@ struct UBWidgetType }; }; -class UBGraphicsWidgetItem : public QGraphicsProxyWidget, public UBItem, public UBResizableGraphicsItem, public UBGraphicsItem +class UBGraphicsWidgetItem : public QGraphicsProxyWidget, public UBMediaAssetItem, public UBResizableGraphicsItem, public UBGraphicsItem { Q_OBJECT @@ -68,7 +68,7 @@ class UBGraphicsWidgetItem : public QGraphicsProxyWidget, public UBItem, public enum { Type = UBGraphicsItemType::GraphicsWidgetItemType }; virtual int type() const override { return Type; } - + virtual QList mediaAssets() const override; virtual void initialize(); virtual void resize(qreal w, qreal h) override; @@ -109,8 +109,6 @@ class UBGraphicsWidgetItem : public QGraphicsProxyWidget, public UBItem, public virtual void setSnapshotPath(const QUrl &newFilePath); virtual QUrl getSnapshotPath() const; - virtual void clearSource() override; - virtual void setUuid(const QUuid &pUuid) override; QSize nominalSize() const; @@ -226,9 +224,9 @@ class UBGraphicsAppleWidgetItem : public UBGraphicsWidgetItem UBGraphicsAppleWidgetItem(const QUrl& pWidgetUrl, QGraphicsItem *parent = 0); ~UBGraphicsAppleWidgetItem(); - virtual void copyItemParameters(UBItem *copy) const; - virtual void setUuid(const QUuid &pUuid); - virtual UBItem* deepCopy() const; + virtual void copyItemParameters(UBItem *copy) const override; + virtual UBItem* deepCopy() const override; + virtual void setMediaAsset(const QString& documentPath, const QString& mediaAsset) override; }; class UBGraphicsW3CWidgetItem : public UBGraphicsWidgetItem @@ -271,15 +269,15 @@ class UBGraphicsW3CWidgetItem : public UBGraphicsWidgetItem UBGraphicsW3CWidgetItem(const QUrl& pWidgetUrl, QGraphicsItem *parent = 0); ~UBGraphicsW3CWidgetItem(); - virtual void setUuid(const QUuid &pUuid); - virtual UBItem* deepCopy() const; - virtual void copyItemParameters(UBItem *copy) const; + virtual UBItem* deepCopy() const override; + virtual void copyItemParameters(UBItem *copy) const override; + virtual void setMediaAsset(const QString& documentPath, const QString& mediaAsset) override; QMap preferences() const; Metadata metadatas() const; - virtual void removeScript(); - virtual void sendJSEnterEvent(); - virtual void sendJSLeaveEvent(); + virtual void removeScript() override; + virtual void sendJSEnterEvent() override; + virtual void sendJSLeaveEvent() override; static QString createNPAPIWrapper(const QString& url, const QString& pMimeType = QString(), const QSize& sizeHint = QSize(300, 150), const QString& pName = QString()); static QString createNPAPIWrapperInDir(const QString& url, const QDir& pDir, const QString& pMimeType = QString(), const QSize& sizeHint = QSize(300, 150), const QString& pName = QString()); @@ -289,7 +287,7 @@ class UBGraphicsW3CWidgetItem : public UBGraphicsWidgetItem Metadata mMetadatas; private slots: - virtual void registerAPI(); + virtual void registerAPI() override; private: static void loadNPAPIWrappersTemplates(); diff --git a/src/domain/UBItem.h b/src/domain/UBItem.h index 5d6b1679c..eef10ba3b 100644 --- a/src/domain/UBItem.h +++ b/src/domain/UBItem.h @@ -139,8 +139,6 @@ class UBGraphicsItem void remove(bool canUndo = true); - virtual void clearSource(){} - private: UBGraphicsItemDelegate* mDelegate; }; diff --git a/src/domain/UBMediaAssetItem.h b/src/domain/UBMediaAssetItem.h new file mode 100644 index 000000000..ac9f8a50b --- /dev/null +++ b/src/domain/UBMediaAssetItem.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + +#pragma once + +#include +#include + +#include "domain/UBItem.h" + +class UBMediaAssetItem : public UBItem +{ +protected: + UBMediaAssetItem() = default; + +public: + virtual ~UBMediaAssetItem() = default; + + virtual QList mediaAssets() const = 0; + virtual void setMediaAsset(const QString& documentPath, const QString& mediaAsset) {} +}; diff --git a/src/domain/domain.pri b/src/domain/domain.pri index 94603caab..3db8010df 100644 --- a/src/domain/domain.pri +++ b/src/domain/domain.pri @@ -8,6 +8,7 @@ HEADERS += src/domain/UBGraphicsScene.h \ src/domain/UBGraphicsSvgItem.h \ src/domain/UBGraphicsPolygonItem.h \ src/domain/UBItem.h \ + src/domain/UBMediaAssetItem.h \ src/domain/UBGraphicsWidgetItem.h \ src/domain/UBGraphicsPDFItem.h \ src/domain/UBGraphicsTextItem.h \ diff --git a/src/frameworks/UBCoreGraphicsScene.cpp b/src/frameworks/UBCoreGraphicsScene.cpp index 1fe934ab3..5d16d0a54 100644 --- a/src/frameworks/UBCoreGraphicsScene.cpp +++ b/src/frameworks/UBCoreGraphicsScene.cpp @@ -88,10 +88,6 @@ bool UBCoreGraphicsScene::deleteItem(QGraphicsItem* item) { if(mItemsToDelete.contains(item)) { - UBGraphicsItem *item_casted = dynamic_cast(item); - if (item_casted != NULL) - item_casted->clearSource(); - mItemsToDelete.remove(item); delete item; item = NULL; diff --git a/src/tools/UBGraphicsCurtainItem.h b/src/tools/UBGraphicsCurtainItem.h index fcc68b8f6..cca53e26e 100644 --- a/src/tools/UBGraphicsCurtainItem.h +++ b/src/tools/UBGraphicsCurtainItem.h @@ -60,7 +60,6 @@ class UBGraphicsCurtainItem : public QObject, public QGraphicsRectItem, public U //TODO UB 4.x not nice ... void triggerRemovedSignal(); - virtual void clearSource(){;} virtual void setUuid(const QUuid &pUuid); From 1e26bdc31ca43c0bb9ff29953486a723f9781a65 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Tue, 8 Apr 2025 15:20:00 +0200 Subject: [PATCH 007/133] refactor: single place to copy scenes - add UBSvgSubsetAdaptor::replicateScene() to combine copying and changing the UUID - extend UBDocument::copyPage() to handle all scene copying - use copyPage() in UBBoardController::addScene() - use copyPage in UBDocumentTreeView::dropEvent() - replace UBPersistenceManager::duplicateDocumentScene() by copyDocumentScene() - change task split between UBDocument and UBPersistenceManager when deleting scenes - add UBDocument::pageRelativeDependencies() as preparation for later TOC handling Signed-off-by: letsfindaway --- src/adaptors/UBSvgSubsetAdaptor.cpp | 45 +++--- src/adaptors/UBSvgSubsetAdaptor.h | 1 + src/board/UBBoardController.cpp | 48 +----- src/board/UBBoardController.h | 1 - src/core/UBPersistenceManager.cpp | 210 +++++--------------------- src/core/UBPersistenceManager.h | 8 +- src/document/UBDocument.cpp | 53 ++++--- src/document/UBDocument.h | 6 +- src/document/UBDocumentController.cpp | 47 ++---- 9 files changed, 123 insertions(+), 296 deletions(-) diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index 910516172..db076b30f 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -187,52 +187,61 @@ QDomDocument UBSvgSubsetAdaptor::loadSceneDocument(std::shared_ptr proxy, const int pageIndex, QUuid pUuid) { - QString fileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg",pageIndex); + const QString path = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", pageIndex); + replicateScene(path, path, pUuid); +} - QFile file(fileName); +void UBSvgSubsetAdaptor::replicateScene(const QString& sourcePath, const QString& targetPath, QUuid uuid) +{ + QFile fromFile(sourcePath); - if (!file.exists() || !file.open(QIODevice::ReadOnly)) + if (!fromFile.exists() || !fromFile.open(QIODevice::ReadOnly)) + { return; + } - QTextStream textReadStream(&file); + QTextStream textReadStream(&fromFile); QString xmlContent = textReadStream.readAll(); - int uuidIndex = xmlContent.indexOf("uuid"); + fromFile.close(); + const int uuidIndex = xmlContent.indexOf("uuid"); + if (-1 == uuidIndex) { - qWarning() << "Cannot read UUID from file" << fileName << "to set new UUID"; - file.close(); + qWarning() << "Cannot read UUID from file" << sourcePath << "to set new UUID"; return; } + int quoteStartIndex = xmlContent.indexOf('"', uuidIndex); + if (-1 == quoteStartIndex) { - qWarning() << "Cannot read UUID from file" << fileName << "to set new UUID"; - file.close(); + qWarning() << "Cannot read UUID from file" << sourcePath << "to set new UUID"; return; } + int quoteEndIndex = xmlContent.indexOf('"', quoteStartIndex + 1); + if (-1 == quoteEndIndex) { - qWarning() << "Cannot read UUID from file" << fileName << "to set new UUID"; - file.close(); + qWarning() << "Cannot read UUID from file" << sourcePath << "to set new UUID"; return; } - file.close(); - QString newXmlContent = xmlContent.left(quoteStartIndex + 1); - newXmlContent.append(UBStringUtils::toCanonicalUuid(pUuid)); + newXmlContent.append(uuid.toString(QUuid::WithoutBraces)); newXmlContent.append(xmlContent.right(xmlContent.length() - quoteEndIndex)); - if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) + QFile toFile(targetPath); + + if (toFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - QTextStream textWriteStream(&file); + QTextStream textWriteStream(&toFile); textWriteStream << newXmlContent; - file.close(); + toFile.close(); } else { - qWarning() << "Cannot open file" << fileName << "to write UUID"; + qWarning() << "Cannot open file" << targetPath << "to write UUID"; } } diff --git a/src/adaptors/UBSvgSubsetAdaptor.h b/src/adaptors/UBSvgSubsetAdaptor.h index 689d4034b..e3a3cfe94 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.h +++ b/src/adaptors/UBSvgSubsetAdaptor.h @@ -93,6 +93,7 @@ class UBSvgSubsetAdaptor static QUuid sceneUuid(std::shared_ptr proxy, const int pageIndex); static void setSceneUuid(std::shared_ptr proxy, const int pageIndex, QUuid pUuid); + static void replicateScene(const QString& sourcePath, const QString& targetPath, QUuid uuid); static void convertPDFObjectsToImages(std::shared_ptr proxy); static void convertSvgImagesToImages(std::shared_ptr proxy); diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index b0d305e1e..3ea0c1419 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -658,52 +658,14 @@ void UBBoardController::addScene() UBPersistenceManager::persistenceManager()->persistDocumentMetadata(selectedDocument()); } -void UBBoardController::addScene(std::shared_ptr scene, bool replaceActiveIfEmpty) -{ - if (scene) - { - std::shared_ptr clone = scene->sceneDeepCopy(); - - if (scene->document() && (scene->document() != selectedDocument())) - { - foreach(QString relativeFile, scene->relativeDependencies()) - { - QString source = scene->document()->persistencePath() + "/" + relativeFile; - QString destination = selectedDocument()->persistencePath() + "/" + relativeFile; - - UBFileSystemUtils::copy(source, destination, true); - } - } - - auto document = UBDocument::getDocument(selectedDocument()); - - if (replaceActiveIfEmpty && mActiveScene->isEmpty()) - { - document->insertPage(clone, mActiveSceneIndex); - setActiveDocumentScene(mActiveSceneIndex); - deleteScene(mActiveSceneIndex + 1); - } - else - { - persistCurrentScene(false,true); - document->insertPage(clone, mActiveSceneIndex + 1); - setActiveDocumentScene(mActiveSceneIndex + 1); - } - - QDateTime now = QDateTime::currentDateTime(); - selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(now)); - } -} - void UBBoardController::addScene(std::shared_ptr proxy, int sceneIndex, bool replaceActiveIfEmpty) { - std::shared_ptr scene = UBPersistenceManager::persistenceManager()->loadDocumentScene(proxy, sceneIndex); - - if (scene) - { - addScene(scene, replaceActiveIfEmpty); - } + // copy scene after active scene index + auto sourceDocument = UBDocument::getDocument(proxy); + auto targetDocument = UBDocument::getDocument(selectedDocument()); + sourceDocument->copyPage(sceneIndex, targetDocument, mActiveSceneIndex + 1); + setActiveDocumentScene(mActiveSceneIndex + 1); } void UBBoardController::duplicateScene(int nIndex) diff --git a/src/board/UBBoardController.h b/src/board/UBBoardController.h index 82c0355c8..80eb1739c 100644 --- a/src/board/UBBoardController.h +++ b/src/board/UBBoardController.h @@ -200,7 +200,6 @@ class UBBoardController : public UBDocumentContainer void blackout(); void addScene(); void addScene(std::shared_ptr proxy, int sceneIndex, bool replaceActiveIfEmpty = false); - void addScene(std::shared_ptr scene, bool replaceActiveIfEmpty = false); void duplicateScene(); void importPage(); void clearScene(); diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index 2aaf23047..3b5efdb25 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -766,225 +766,96 @@ void UBPersistenceManager::deleteDocumentScenes(std::shared_ptr int pageCount = proxy->pageCount(); - QList compactedIndexes; - - foreach(int index, indexes) - { - if (!compactedIndexes.contains(index)) - compactedIndexes.append(index); - } - - if (compactedIndexes.size() == pageCount) + if (indexes.size() == pageCount) { deleteDocument(proxy); return; } - if (compactedIndexes.size() == 0) - return; - - QString sourceName = proxy->metaData(UBSettings::documentName).toString(); - std::shared_ptr trashDocProxy = createDocument(UBSettings::trashedDocumentGroupNamePrefix/* + sourceGroupName*/, sourceName, false); - - foreach(int index, compactedIndexes) - { - std::shared_ptr scene = loadDocumentScene(proxy, index); - if (scene) - { - //scene is about to move into new document - foreach (QString relativeFile, scene->relativeDependencies()) - { - QString source = scene->document()->persistencePath() + "/" + relativeFile; - QString target = trashDocProxy->persistencePath() + "/" + relativeFile; - - QFileInfo fi(target); - QDir d = fi.dir(); - - d.mkpath(d.absolutePath()); - QFile::copy(source, target); - } - insertDocumentSceneAt(trashDocProxy, scene, trashDocProxy->pageCount(), true, true); - } - } - - for (int i = 1; i < indexes.size(); i++) + if (indexes.size() == 0) { - renamePage(trashDocProxy, i , i - 1); + return; } - foreach(int index, compactedIndexes) + for (auto index : indexes) { QString svgFileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", index); - QFile::remove(svgFileName); QString thumbFileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", index); - QFile::remove(thumbFileName); mSceneCache.removeScene(proxy, index); proxy->decPageCount(); - } - std::sort(compactedIndexes.begin(), compactedIndexes.end()); - int offset = 1; - for (int i = compactedIndexes.at(0) + 1; i < pageCount; i++) + for (int i = indexes.at(0) + 1; i < pageCount; i++) { - if(compactedIndexes.contains(i)) + if (indexes.contains(i)) { offset++; } else { renamePage(proxy, i , i - offset); - mSceneCache.moveScene(proxy, i, i - offset); - } } + + // update metadata + QDateTime now = QDateTime::currentDateTime(); + proxy->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(now)); + persistDocumentMetadata(proxy); } -void UBPersistenceManager::duplicateDocumentScene(std::shared_ptr proxy, int index) +void UBPersistenceManager::copyDocumentScene(std::shared_ptr from, int fromIndex, + std::shared_ptr to, int toIndex, QList dependencies) { checkIfDocumentRepositoryExists(); auto scene = UBApplication::boardController->activeScene(); // save modified scene of the same document - if (scene && scene->document() == proxy && scene->isModified()) + if (scene && scene->document() == from && scene->isModified()) { auto page = UBApplication::boardController->activeSceneIndex(); - persistDocumentScene(proxy, scene, page, false, true); + persistDocumentScene(from, scene, page, false, true); } - for (int i = proxy->pageCount(); i > index + 1; i--) + // make room + for (int i = to->pageCount(); i > toIndex; i--) { - renamePage(proxy, i - 1 , i); - - mSceneCache.moveScene(proxy, i - 1, i); + renamePage(to, i - 1, i); + mSceneCache.moveScene(to, i - 1, i); } - copyPage(proxy, index , index + 1); - - //TODO: write a proper way to handle object on disk - scene = loadDocumentScene(proxy, index + 1); - - foreach(QGraphicsItem* item, scene->items()) + // adjust from index if necessary + if (from == to && toIndex <= fromIndex) { - UBGraphicsMediaItem *mediaItem = qgraphicsitem_cast (item); - - if (mediaItem){ - QString source = mediaItem->mediaFileUrl().toLocalFile(); - QString destination = source; - QUuid newUuid = QUuid::createUuid(); - QString fileName = QFileInfo(source).completeBaseName(); - destination = destination.replace(fileName,newUuid.toString()); - QFile::copy(source,destination); - mediaItem->setMediaFileUrl(QUrl::fromLocalFile(destination)); - continue; - } - - UBGraphicsWidgetItem* widget = qgraphicsitem_cast(item); - if(widget){ - QUuid newUUid = QUuid::createUuid(); - QString newUUidString = newUUid.toString().remove("{").remove("}"); - QString actualUuidString = widget->uuid().toString().remove("{").remove("}"); - - QString widgetSourcePath = proxy->persistencePath() + "/" + UBPersistenceManager::widgetDirectory + "/{" + actualUuidString + "}.wgt"; - QString screenshotSourcePath = proxy->persistencePath() + "/" + UBPersistenceManager::widgetDirectory + "/" + actualUuidString + ".png"; - - QString widgetDestinationPath = widgetSourcePath; - widgetDestinationPath = widgetDestinationPath.replace(actualUuidString,newUUidString); - QString screenshotDestinationPath = screenshotSourcePath; - screenshotDestinationPath = screenshotDestinationPath.replace(actualUuidString,newUUidString); - - UBFileSystemUtils::copyDir(widgetSourcePath,widgetDestinationPath); - QFile::copy(screenshotSourcePath,screenshotDestinationPath); - - widget->setUuid(newUUid); - - widget->widgetUrl(QUrl::fromLocalFile(widgetDestinationPath)); - - continue; - } - - UBGraphicsPixmapItem* pixmapItem = qgraphicsitem_cast(item); - if(pixmapItem){ - QDir imageDir = proxy->persistencePath() + "/" + UBPersistenceManager::imageDirectory; - QStringList imageFiles = imageDir.entryList({pixmapItem->uuid().toString() + ".*"}); - - if (!imageFiles.isEmpty()) - { - QString source = proxy->persistencePath() + "/" + UBPersistenceManager::imageDirectory + "/" + imageFiles.last(); - QString destination = source; - QUuid newUuid = QUuid::createUuid(); - QString fileName = QFileInfo(source).completeBaseName(); - destination = destination.replace(fileName,newUuid.toString()); - QFile::copy(source,destination); - pixmapItem->setUuid(newUuid); - } - - continue; - } - - UBGraphicsSvgItem* svgItem = qgraphicsitem_cast(item); - if(svgItem){ - QString source = proxy->persistencePath() + "/" + UBPersistenceManager::imageDirectory + "/" + svgItem->uuid().toString() + ".svg"; - QString destination = source; - QUuid newUuid = QUuid::createUuid(); - QString fileName = QFileInfo(source).completeBaseName(); - destination = destination.replace(fileName,newUuid.toString()); - QFile::copy(source,destination); - svgItem->setUuid(newUuid); - continue; - } - + ++fromIndex; } - scene->setModified(true); - - proxy->incPageCount(); - persistDocumentScene(proxy, scene, index + 1, false, true); + // copy SVG and thumbnail + copyPage(from, fromIndex, to, toIndex); - persistDocumentMetadata(proxy); -} - -void UBPersistenceManager::copyDocumentScene(std::shared_ptr from, int fromIndex, std::shared_ptr to, int toIndex) -{ - if (from == to && toIndex <= fromIndex) { - qDebug() << "operation is not supported" << Q_FUNC_INFO; - return; - } - - checkIfDocumentRepositoryExists(); - - for (int i = to->pageCount(); i > toIndex; i--) { - renamePage(to, i - 1, i); - mSceneCache.moveScene(to, i - 1, i); + // copy dependencies, don't overwrite + for (const auto relativeFile : dependencies) + { + QString source = from->persistencePath() + "/" + relativeFile; + QString target = to->persistencePath() + "/" + relativeFile; + UBFileSystemUtils::copy(source, target, false); } - UBForeighnObjectsHandler hl; - hl.copyPage(QUrl::fromLocalFile(from->persistencePath()), fromIndex, - QUrl::fromLocalFile(to->persistencePath()), toIndex); - to->incPageCount(); - QString thumbTmp(from->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", fromIndex)); - QString thumbTo(to->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", toIndex)); - - QFile::remove(thumbTo); - QFile::copy(thumbTmp, thumbTo); - - Q_ASSERT(QFileInfo(thumbTmp).exists()); - Q_ASSERT(QFileInfo(thumbTo).exists()); - auto pix = std::make_shared(thumbTmp); - UBDocumentController *ctrl = UBApplication::documentController; - ctrl->TreeViewSelectionChanged(ctrl->firstSelectedTreeIndex(), QModelIndex()); + // update metadata + QDateTime now = QDateTime::currentDateTime(); + to->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(now)); + persistDocumentMetadata(to); } @@ -1178,15 +1049,14 @@ void UBPersistenceManager::renamePage(std::shared_ptr pDocument } -void UBPersistenceManager::copyPage(std::shared_ptr pDocumentProxy, const int sourceIndex, const int targetIndex) +void UBPersistenceManager::copyPage(std::shared_ptr source, const int sourceIndex, std::shared_ptr target, const int targetIndex) { - QFile svg(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg",sourceIndex)); - svg.copy(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", targetIndex)); + const QString sourcePath = source->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", sourceIndex); + const QString targetPath = target->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", targetIndex); + UBSvgSubsetAdaptor::replicateScene(sourcePath, targetPath, QUuid::createUuid()); - UBSvgSubsetAdaptor::setSceneUuid(pDocumentProxy, targetIndex, QUuid::createUuid()); - - QFile thumb(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", sourceIndex)); - thumb.copy(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", targetIndex)); + QFile thumb(source->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", sourceIndex)); + thumb.copy(target->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", targetIndex)); } diff --git a/src/core/UBPersistenceManager.h b/src/core/UBPersistenceManager.h index 2ceee64c0..403222691 100644 --- a/src/core/UBPersistenceManager.h +++ b/src/core/UBPersistenceManager.h @@ -100,9 +100,7 @@ class UBPersistenceManager : public QObject virtual void deleteDocumentScenes(std::shared_ptr pDocumentProxy, const QList& indexes); - virtual void duplicateDocumentScene(std::shared_ptr pDocumentProxy, int index); - - virtual void copyDocumentScene(std::shared_ptrfrom, int fromIndex, std::shared_ptrto, int toIndex); + virtual void copyDocumentScene(std::shared_ptrfrom, int fromIndex, std::shared_ptrto, int toIndex, QList dependencies); virtual void persistDocumentScene(std::shared_ptr pDocumentProxy, std::shared_ptr pScene, const int pSceneIndex, bool isAnAutomaticBackup = false, bool forceImmediateSaving = false); @@ -171,8 +169,8 @@ class UBPersistenceManager : public QObject static QStringList getSceneFileNames(const QString& folder); void renamePage(std::shared_ptr pDocumentProxy, const int sourceIndex, const int targetIndex); - void copyPage(std::shared_ptr pDocumentProxy, - const int sourceIndex, const int targetIndex); + void copyPage(std::shared_ptr source, const int sourceIndex, + std::shared_ptr target, const int targetIndex); void generatePathIfNeeded(std::shared_ptr pDocumentProxy); void checkIfDocumentRepositoryExists(); diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index 7d669ec35..d95413228 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -83,6 +83,20 @@ void UBDocument::deletePages(QList indexes) } std::sort(indexes.begin(), indexes.end()); + indexes.erase(std::unique(indexes.begin(), indexes.end()), indexes.end()); + + // copy to-be-deleted pages to trash document + QString sourceName = mProxy->metaData(UBSettings::documentName).toString(); + auto trashDocProxy = UBPersistenceManager::persistenceManager()->createDocument(UBSettings::trashedDocumentGroupNamePrefix, sourceName, false); + auto trashDocument = UBDocument::getDocument(trashDocProxy); + int trashIndex = 0; + + for (auto index : indexes) + { + copyPage(index, trashDocument, trashIndex++); + } + + // delete the scenes UBPersistenceManager::persistenceManager()->deleteDocumentScenes(mProxy, indexes); for (int i = indexes.size() - 1; i >= 0; --i) @@ -93,20 +107,13 @@ void UBDocument::deletePages(QList indexes) mThumbnailScene->renumberThumbnails(indexes.first()); mThumbnailScene->arrangeThumbnails(indexes.first()); - - QDateTime now = QDateTime::currentDateTime(); - mProxy->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(now)); } void UBDocument::duplicatePage(int index) { - UBPersistenceManager::persistenceManager()->duplicateDocumentScene(mProxy, index); - + const auto dependencies = pageRelativeDependencies(index); + UBPersistenceManager::persistenceManager()->copyDocumentScene(mProxy, index, mProxy, index + 1, dependencies); mThumbnailScene->insertThumbnail(index + 1); - - QDateTime now = QDateTime::currentDateTime(); - mProxy->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(now)); - emit UBPersistenceManager::persistenceManager()->documentSceneDuplicated(mProxy, index + 1); } @@ -117,16 +124,11 @@ void UBDocument::movePage(int fromIndex, int toIndex) emit UBPersistenceManager::persistenceManager()->documentSceneMoved(mProxy, fromIndex, toIndex); } -void UBDocument::copyPage(int fromIndex, std::shared_ptr to, int toIndex) +void UBDocument::copyPage(int fromIndex, std::shared_ptr to, int toIndex) { - UBPersistenceManager::persistenceManager()->copyDocumentScene(mProxy, fromIndex, to, toIndex); - - const auto toDocument = findDocument(to); - - if (toDocument) - { - toDocument->mThumbnailScene->insertThumbnail(toIndex); - } + const auto dependencies = pageRelativeDependencies(fromIndex); + UBPersistenceManager::persistenceManager()->copyDocumentScene(mProxy, fromIndex, to->proxy(), toIndex, dependencies); + to->mThumbnailScene->insertThumbnail(toIndex); } void UBDocument::insertPage(std::shared_ptr scene, int index, bool persist, bool deleting) @@ -145,7 +147,7 @@ std::shared_ptr UBDocument::createPage(int index, bool useUndoR return scene; } -void UBDocument::persistPage(std::shared_ptr scene, const int index, bool isAutomaticBackup, +void UBDocument::persistPage(std::shared_ptr scene, int index, bool isAutomaticBackup, bool forceImmediateSaving) { UBPersistenceManager::persistenceManager()->persistDocumentScene(mProxy, scene, index, isAutomaticBackup, @@ -153,6 +155,19 @@ void UBDocument::persistPage(std::shared_ptr scene, const int i mThumbnailScene->reloadThumbnail(index); } +QList UBDocument::pageRelativeDependencies(int index) const +{ + // TODO use TOC when available + auto scene = UBPersistenceManager::persistenceManager()->loadDocumentScene(mProxy, index, false); + + if (scene) + { + return scene->relativeDependencies(); + } + + return {}; +} + UBThumbnailScene* UBDocument::thumbnailScene() const { return mThumbnailScene; diff --git a/src/document/UBDocument.h b/src/document/UBDocument.h index 7135e4765..6cad5c620 100644 --- a/src/document/UBDocument.h +++ b/src/document/UBDocument.h @@ -57,11 +57,13 @@ class UBDocument void deletePages(QList indexes); void duplicatePage(int index); void movePage(int fromIndex, int toIndex); - void copyPage(int fromIndex, std::shared_ptr to, int toIndex); + void copyPage(int fromIndex, std::shared_ptr to, int toIndex); + // FIXME invocations of insertPage are finally also just a copy void insertPage(std::shared_ptr scene, int index, bool persist = true, bool deleting = false); std::shared_ptr createPage(int index, bool useUndoRedoStack = true); - void persistPage(std::shared_ptr scene, const int index, bool isAutomaticBackup = false, + void persistPage(std::shared_ptr scene, int index, bool isAutomaticBackup = false, bool forceImmediateSaving = false); + QList pageRelativeDependencies(int index) const; UBThumbnailScene* thumbnailScene() const; static std::shared_ptr getDocument(std::shared_ptr proxy); diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index 3ab9f67eb..bceb780be 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -741,7 +741,8 @@ bool UBDocumentTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction act int toIndex = targetDocProxy->pageCount(); auto fromDocument = UBDocument::getDocument(fromProxy); - fromDocument->copyPage(fromIndex, targetDocProxy, toIndex); + auto targetDocument = UBDocument::getDocument(targetDocProxy); + fromDocument->copyPage(fromIndex, targetDocument, toIndex); } QApplication::restoreOverrideCursor(); @@ -1629,7 +1630,7 @@ void UBDocumentTreeView::dropEvent(QDropEvent *event) auto targetDocument = UBDocument::getDocument(targetDocProxy); const UBMimeData *ubMime = qobject_cast (event->mimeData()); - if (!targetDocProxy || !ubMime || !ubMime->items().count()) { + if (!targetDocument || !ubMime || !ubMime->items().count()) { qDebug() << "an error ocured while parsing " << UBApplication::mimeTypeUniboardPage; QTreeView::dropEvent(event); return; @@ -1645,45 +1646,15 @@ void UBDocumentTreeView::dropEvent(QDropEvent *event) int fromIndex = sourceItem.sceneIndex(); int toIndex = targetDocProxy->pageCount(); - count++; - - UBApplication::showMessage(tr("Copying page %1/%2").arg(count).arg(total), true); - // FIXME code is similar to UBPersistenceManager::copyDocumentScene() - // PersistenceManaget works with UBForeignObjectHandler, while we here ask the scene for relative dependencies - // one is at file level, the other at scene level. I prefer scene level, as it avoids another SVG parser. - // Implement one single UBDocument::copyPage - - // TODO UB 4.x Move following code to some controller class - std::shared_ptr scene = UBPersistenceManager::persistenceManager()->loadDocumentScene(sourceItem.documentProxy(), fromIndex); - if (scene) - { - std::shared_ptr sceneClone = scene->sceneDeepCopy(); - - std::shared_ptr targetDocProxy = docModel->proxyForIndex(targetIndex); - - foreach (QString relativeFile, scene->relativeDependencies()) - { - QString source = scene->document()->persistencePath() + "/" + relativeFile; - QString target = targetDocProxy->persistencePath() + "/" + relativeFile; - - if(QFileInfo(source).isDir()) - UBFileSystemUtils::copyDir(source,target); - else{ - QFileInfo fi(target); - QDir d = fi.dir(); - d.mkpath(d.absolutePath()); - QFile::copy(source, target); - } - } - - targetDocument->insertPage(sceneClone, toIndex); - } + UBApplication::showMessage(tr("Copying page %1/%2").arg(++count).arg(total), true); - QApplication::restoreOverrideCursor(); - - docModel->setHighLighted(QModelIndex()); + auto sourceDocument = UBDocument::getDocument(fromProxy); + sourceDocument->copyPage(fromIndex, targetDocument, toIndex); } + QApplication::restoreOverrideCursor(); + docModel->setHighLighted(QModelIndex()); + UBApplication::showMessage(tr("%1 pages copied", "", total).arg(total), false); } else From 3c9e26b7167415d3458a7e9e5a525052caf5bff1 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Fri, 11 Apr 2025 11:24:45 +0200 Subject: [PATCH 008/133] performance: hash map for fast item lookup by uuid - remove UBGraphicsItemData::ItemUuid - do not store UUID in item data, only in UBItem - remove all setUuid overwrites from item classes - add map to UBCoreGraphicsScene and manage it there - provide lookup function for map instead of linear search - adapt some usages to get UUID in UBSvgSubsetAdaptor and UBGraphicsScene Signed-off-by: letsfindaway --- src/adaptors/UBSvgSubsetAdaptor.cpp | 8 +++--- src/core/UB.h | 1 - src/domain/UBGraphicsGroupContainerItem.cpp | 6 ----- src/domain/UBGraphicsGroupContainerItem.h | 1 - src/domain/UBGraphicsMediaItem.cpp | 6 ----- src/domain/UBGraphicsMediaItem.h | 1 - src/domain/UBGraphicsPixmapItem.cpp | 6 ----- src/domain/UBGraphicsPixmapItem.h | 2 -- src/domain/UBGraphicsPolygonItem.cpp | 6 ----- src/domain/UBGraphicsPolygonItem.h | 2 -- src/domain/UBGraphicsScene.cpp | 27 +++------------------ src/domain/UBGraphicsScene.h | 4 --- src/domain/UBGraphicsStrokesGroup.cpp | 6 ----- src/domain/UBGraphicsStrokesGroup.h | 1 - src/domain/UBGraphicsTextItem.cpp | 6 ----- src/domain/UBGraphicsTextItem.h | 1 - src/domain/UBGraphicsWidgetItem.cpp | 18 -------------- src/domain/UBGraphicsWidgetItem.h | 2 -- src/domain/UBItem.cpp | 6 ----- src/domain/UBItem.h | 1 - src/frameworks/UBCoreGraphicsScene.cpp | 21 ++++++++++++++-- src/frameworks/UBCoreGraphicsScene.h | 3 +++ src/tools/UBGraphicsCurtainItem.cpp | 6 ----- src/tools/UBGraphicsCurtainItem.h | 2 -- 24 files changed, 31 insertions(+), 112 deletions(-) diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index db076b30f..69ac1cb94 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -1576,7 +1576,8 @@ bool UBSvgSubsetAdaptor::UBSvgSubsetWriter::persistScene(std::shared_ptr(groupItem); + QUuid uuid = ubitem ? ubitem->uuid() : QUuid{}; if (!uuid.isNull()) { QDomElement curGroupElement = groupDomDocument->createElement(tGroup); curGroupElement.setAttribute(aId, uuid.toString()); @@ -1600,7 +1601,8 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::persistGroupToDom(QGraphicsItem *gro } curParent->appendChild(curGroupElement); foreach (QGraphicsItem *item, groupItem->childItems()) { - QUuid tmpUuid = UBGraphicsScene::getPersonalUuid(item); + UBItem* ubitem = dynamic_cast(item); + QUuid tmpUuid = ubitem ? ubitem->uuid() : QUuid{}; if (!tmpUuid.isNull()) { if (item->type() == UBGraphicsGroupContainerItem::Type && item->childItems().count()) persistGroupToDom(item, curParent, groupDomDocument); @@ -1697,7 +1699,7 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::strokeToSvgPolyline(UBGraphicsStroke mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "uuid", UBStringUtils::toCanonicalUuid(firstPolygonItem->uuid())); if (firstPolygonItem->parentItem()) { - mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "parent", UBStringUtils::toCanonicalUuid(UBGraphicsItem::getOwnUuid(firstPolygonItem->strokesGroup()))); + mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "parent", firstPolygonItem->strokesGroup()->uuid().toString(QUuid::WithoutBraces)); } mXmlWriter.writeEndElement(); diff --git a/src/core/UB.h b/src/core/UB.h index bfa6a7654..c73a1506e 100644 --- a/src/core/UB.h +++ b/src/core/UB.h @@ -139,7 +139,6 @@ struct UBGraphicsItemData , ItemEditable//for text only , ItemOwnZValue , itemLayerType //use instead of deprecated ItemLayerType - , ItemUuid //storing uuid in QGraphicsItem for fast finding operations //Duplicating delegate's functions to make possible working with pure QGraphicsItem , ItemFlippable // (bool) , ItemRotatable // (bool) diff --git a/src/domain/UBGraphicsGroupContainerItem.cpp b/src/domain/UBGraphicsGroupContainerItem.cpp index 7daa31b1b..d19de3ade 100644 --- a/src/domain/UBGraphicsGroupContainerItem.cpp +++ b/src/domain/UBGraphicsGroupContainerItem.cpp @@ -245,12 +245,6 @@ void UBGraphicsGroupContainerItem::copyItemParameters(UBItem *copy) const } } -void UBGraphicsGroupContainerItem::setUuid(const QUuid &pUuid) -{ - UBItem::setUuid(pUuid); - setData(UBGraphicsItemData::ItemUuid, QVariant(pUuid)); //store item uuid inside the QGraphicsItem to fast operations with Items on the scene -} - void UBGraphicsGroupContainerItem::destroy(bool canUndo) { foreach (QGraphicsItem *item, childItems()) { diff --git a/src/domain/UBGraphicsGroupContainerItem.h b/src/domain/UBGraphicsGroupContainerItem.h index 9ae8d8aba..4e7047fe0 100644 --- a/src/domain/UBGraphicsGroupContainerItem.h +++ b/src/domain/UBGraphicsGroupContainerItem.h @@ -63,7 +63,6 @@ class UBGraphicsGroupContainerItem : public QGraphicsItem, public UBItem, public return Type; } - virtual void setUuid(const QUuid &pUuid); void destroy(bool canUndo = true); protected: diff --git a/src/domain/UBGraphicsMediaItem.cpp b/src/domain/UBGraphicsMediaItem.cpp index 0ab67c05c..f5b0cf948 100644 --- a/src/domain/UBGraphicsMediaItem.cpp +++ b/src/domain/UBGraphicsMediaItem.cpp @@ -327,12 +327,6 @@ void UBGraphicsMediaItem::setMinimumSize(const QSize& size) this->setSize(width, height); } -void UBGraphicsMediaItem::setUuid(const QUuid &pUuid) -{ - UBItem::setUuid(pUuid); - setData(UBGraphicsItemData::ItemUuid, QVariant(pUuid)); -} - void UBGraphicsMediaItem::setMediaFileUrl(QUrl url) { mMediaFileUrl = url; diff --git a/src/domain/UBGraphicsMediaItem.h b/src/domain/UBGraphicsMediaItem.h index e9bddfc15..ece59f53e 100644 --- a/src/domain/UBGraphicsMediaItem.h +++ b/src/domain/UBGraphicsMediaItem.h @@ -107,7 +107,6 @@ class UBGraphicsMediaItem : public QObject, public UBMediaAssetItem, public UBGr virtual void setSourceUrl(const QUrl &pSourceUrl) override; void setSelected(bool selected); void setMinimumSize(const QSize& size); - void setUuid(const QUuid &pUuid) override; virtual void copyItemParameters(UBItem *copy) const override; diff --git a/src/domain/UBGraphicsPixmapItem.cpp b/src/domain/UBGraphicsPixmapItem.cpp index 265aa52c3..e1a99a965 100644 --- a/src/domain/UBGraphicsPixmapItem.cpp +++ b/src/domain/UBGraphicsPixmapItem.cpp @@ -86,12 +86,6 @@ QVariant UBGraphicsPixmapItem::itemChange(GraphicsItemChange change, const QVari return QGraphicsPixmapItem::itemChange(change, newValue); } -void UBGraphicsPixmapItem::setUuid(const QUuid &pUuid) -{ - UBItem::setUuid(pUuid); - setData(UBGraphicsItemData::ItemUuid, QVariant(pUuid)); -} - void UBGraphicsPixmapItem::setMediaAsset(const QString& documentPath, const QString& mediaAsset) { mMediaAsset = mediaAsset; diff --git a/src/domain/UBGraphicsPixmapItem.h b/src/domain/UBGraphicsPixmapItem.h index 274d18136..b0a597728 100644 --- a/src/domain/UBGraphicsPixmapItem.h +++ b/src/domain/UBGraphicsPixmapItem.h @@ -66,8 +66,6 @@ class UBGraphicsPixmapItem : public QObject, public QGraphicsPixmapItem, public void setOpacity(qreal op); qreal opacity() const; - virtual void setUuid(const QUuid &pUuid) override; - virtual void setMediaAsset(const QString& documentPath, const QString& mediaAsset) override; protected: diff --git a/src/domain/UBGraphicsPolygonItem.cpp b/src/domain/UBGraphicsPolygonItem.cpp index 556a84b70..a3d2405d1 100644 --- a/src/domain/UBGraphicsPolygonItem.cpp +++ b/src/domain/UBGraphicsPolygonItem.cpp @@ -92,12 +92,6 @@ void UBGraphicsPolygonItem::initialize() setUuid(QUuid::createUuid()); } -void UBGraphicsPolygonItem::setUuid(const QUuid &pUuid) -{ - UBItem::setUuid(pUuid); - setData(UBGraphicsItemData::ItemUuid, QVariant(pUuid)); //store item uuid inside the QGraphicsItem to fast operations with Items on the scene -} - void UBGraphicsPolygonItem::clearStroke() { if (mStroke!=NULL) diff --git a/src/domain/UBGraphicsPolygonItem.h b/src/domain/UBGraphicsPolygonItem.h index c1311180d..cdfaa8c3c 100644 --- a/src/domain/UBGraphicsPolygonItem.h +++ b/src/domain/UBGraphicsPolygonItem.h @@ -53,8 +53,6 @@ class UBGraphicsPolygonItem : public QGraphicsPolygonItem, public UBItem void initialize(); - void setUuid(const QUuid &pUuid); - void setStrokesGroup(UBGraphicsStrokesGroup* group); UBGraphicsStrokesGroup* strokesGroup() const{return mpGroup;} void setColor(const QColor& color); diff --git a/src/domain/UBGraphicsScene.cpp b/src/domain/UBGraphicsScene.cpp index 21b272ab6..b0b95dae0 100644 --- a/src/domain/UBGraphicsScene.cpp +++ b/src/domain/UBGraphicsScene.cpp @@ -1522,9 +1522,11 @@ void UBGraphicsScene::clearContent(clearCase pCase) if (itemGroup) { itemGroup->removeFromGroup(item); - groupsMap.insert(itemGroup, UBGraphicsItem::getOwnUuid(item)); + UBItem* ubitem = dynamic_cast(item); + groupsMap.insert(itemGroup, ubitem ? ubitem->uuid() : QUuid{}); if (itemGroup->childItems().count() == 1) { - groupsMap.insert(itemGroup, UBGraphicsItem::getOwnUuid(itemGroup->childItems().constFirst())); + UBItem* ubitem = dynamic_cast(itemGroup->childItems().constFirst()); + groupsMap.insert(itemGroup, ubitem ? ubitem->uuid() : QUuid{}); QGraphicsItem *lastItem = itemGroup->childItems().constFirst(); bool isSelected = itemGroup->isSelected(); itemGroup->destroy(false); @@ -2182,21 +2184,6 @@ QRectF UBGraphicsScene::normalizedSceneRect(qreal ratio) return normalizedRect; } -QGraphicsItem *UBGraphicsScene::itemForUuid(QUuid uuid) -{ - QGraphicsItem *result = 0; - - //simple search before implementing container for fast access - foreach (QGraphicsItem *item, items()) - { - if (UBGraphicsScene::getPersonalUuid(item) == uuid && !uuid.isNull()) { - result = item; - } - } - - return result; -} - void UBGraphicsScene::setDocument(std::shared_ptr pDocument) { if (pDocument != mDocument) @@ -2785,12 +2772,6 @@ void UBGraphicsScene::setOwnZlevel(QGraphicsItem *item) item->setZValue(item->data(UBGraphicsItemData::ItemOwnZValue).toReal()); } -QUuid UBGraphicsScene::getPersonalUuid(QGraphicsItem *item) -{ - QString idCandidate = item->data(UBGraphicsItemData::ItemUuid).toString(); - return idCandidate == QUuid().toString() ? QUuid() : QUuid(idCandidate); -} - qreal UBGraphicsScene::changeZLevelTo(QGraphicsItem *item, UBZLayerController::moveDestination dest, bool addUndo) { qreal previousZVal = item->data(UBGraphicsItemData::ItemOwnZValue).toReal(); diff --git a/src/domain/UBGraphicsScene.h b/src/domain/UBGraphicsScene.h index 1552a3ea4..bdf41d3fe 100644 --- a/src/domain/UBGraphicsScene.h +++ b/src/domain/UBGraphicsScene.h @@ -187,8 +187,6 @@ class UBGraphicsScene: public UBCoreGraphicsScene, public UBItem, public std::en QRectF normalizedSceneRect(qreal ratio = -1.0); - QGraphicsItem *itemForUuid(QUuid uuid); - void moveTo(const QPointF& pPoint); void drawLineTo(const QPointF& pEndPoint, const qreal& pWidth, bool bLineStyle); void drawLineTo(const QPointF& pEndPoint, const qreal& pStartWidth, const qreal& endWidth, bool bLineStyle); @@ -330,8 +328,6 @@ class UBGraphicsScene: public UBCoreGraphicsScene, public UBItem, public std::en void setSelectedZLevel(QGraphicsItem *item); void setOwnZlevel(QGraphicsItem *item); - static QUuid getPersonalUuid(QGraphicsItem *item); - UBGraphicsPolygonItem* polygonToPolygonItem(const QPolygonF pPolygon); void clearSelectionFrame(); UBBoardView *controlView(); diff --git a/src/domain/UBGraphicsStrokesGroup.cpp b/src/domain/UBGraphicsStrokesGroup.cpp index fe5f7c3ef..85a9d4308 100644 --- a/src/domain/UBGraphicsStrokesGroup.cpp +++ b/src/domain/UBGraphicsStrokesGroup.cpp @@ -58,12 +58,6 @@ UBGraphicsStrokesGroup::~UBGraphicsStrokesGroup() { } -void UBGraphicsStrokesGroup::setUuid(const QUuid &pUuid) -{ - UBItem::setUuid(pUuid); - setData(UBGraphicsItemData::ItemUuid, QVariant(pUuid)); //store item uuid inside the QGraphicsItem to fast operations with Items on the scene -} - void UBGraphicsStrokesGroup::setColor(const QColor &color, colorType pColorType) { //TODO Implement common mechanism of managing groups, drop UBGraphicsStroke if it's obsolete diff --git a/src/domain/UBGraphicsStrokesGroup.h b/src/domain/UBGraphicsStrokesGroup.h index 87a5e36aa..9b55921ad 100644 --- a/src/domain/UBGraphicsStrokesGroup.h +++ b/src/domain/UBGraphicsStrokesGroup.h @@ -54,7 +54,6 @@ class UBGraphicsStrokesGroup : public QGraphicsItemGroup, public UBItem, public { return Type; } - virtual void setUuid(const QUuid &pUuid); void setColor(const QColor &color, colorType pColorType = currentColor); QColor color(colorType pColorType = currentColor) const; diff --git a/src/domain/UBGraphicsTextItem.cpp b/src/domain/UBGraphicsTextItem.cpp index 61b0bc232..d83bb3ecd 100644 --- a/src/domain/UBGraphicsTextItem.cpp +++ b/src/domain/UBGraphicsTextItem.cpp @@ -488,12 +488,6 @@ QSizeF UBGraphicsTextItem::size() const return QSizeF(textWidth(), textHeight()); } -void UBGraphicsTextItem::setUuid(const QUuid &pUuid) -{ - UBItem::setUuid(pUuid); - setData(UBGraphicsItemData::ItemUuid, QVariant(pUuid)); //store item uuid inside the QGraphicsItem to fast operations with Items on the scene -} - void UBGraphicsTextItem::undoCommandAdded() { diff --git a/src/domain/UBGraphicsTextItem.h b/src/domain/UBGraphicsTextItem.h index 62217029d..56f80b85c 100644 --- a/src/domain/UBGraphicsTextItem.h +++ b/src/domain/UBGraphicsTextItem.h @@ -95,7 +95,6 @@ class UBGraphicsTextItem : public QGraphicsTextItem, public UBItem, public UBRes mColorOnLightBackground = pColorOnLightBackground; } - virtual void setUuid(const QUuid &pUuid); void activateTextEditor(bool activate); void setSelected(bool selected); void recolor(); diff --git a/src/domain/UBGraphicsWidgetItem.cpp b/src/domain/UBGraphicsWidgetItem.cpp index 81420550e..b8788e9b2 100644 --- a/src/domain/UBGraphicsWidgetItem.cpp +++ b/src/domain/UBGraphicsWidgetItem.cpp @@ -398,12 +398,6 @@ QUrl UBGraphicsWidgetItem::getSnapshotPath() const return mSnapshotFile; } -void UBGraphicsWidgetItem::setUuid(const QUuid &pUuid) -{ - UBItem::setUuid(pUuid); - setData(UBGraphicsItemData::ItemUuid, QVariant(pUuid)); //store item uuid inside the QGraphicsItem to fast operations with Items on the scene -} - QSize UBGraphicsWidgetItem::nominalSize() const { return mNominalSize; @@ -1002,12 +996,6 @@ UBGraphicsAppleWidgetItem::~UBGraphicsAppleWidgetItem() /* NOOP */ } -void UBGraphicsAppleWidgetItem::setUuid(const QUuid &pUuid) -{ - UBItem::setUuid(pUuid); - setData(UBGraphicsItemData::ItemUuid, QVariant(pUuid)); //store item uuid inside the QGraphicsItem to fast operations with Items on the scene -} - UBItem* UBGraphicsAppleWidgetItem::deepCopy() const { UBGraphicsAppleWidgetItem *appleWidget = new UBGraphicsAppleWidgetItem(mWebEngineView->url(), parentItem()); @@ -1197,12 +1185,6 @@ UBGraphicsW3CWidgetItem::~UBGraphicsW3CWidgetItem() /* NOOP */ } -void UBGraphicsW3CWidgetItem::setUuid(const QUuid &pUuid) -{ - UBItem::setUuid(pUuid); - setData(UBGraphicsItemData::ItemUuid, QVariant(pUuid)); //store item uuid inside the QGraphicsItem to fast operations with Items on the scene -} - UBItem* UBGraphicsW3CWidgetItem::deepCopy() const { UBGraphicsW3CWidgetItem *copy = new UBGraphicsW3CWidgetItem(mWidgetUrl, parentItem()); diff --git a/src/domain/UBGraphicsWidgetItem.h b/src/domain/UBGraphicsWidgetItem.h index 25f150f64..7d77e6419 100644 --- a/src/domain/UBGraphicsWidgetItem.h +++ b/src/domain/UBGraphicsWidgetItem.h @@ -109,8 +109,6 @@ class UBGraphicsWidgetItem : public QGraphicsProxyWidget, public UBMediaAssetIte virtual void setSnapshotPath(const QUrl &newFilePath); virtual QUrl getSnapshotPath() const; - virtual void setUuid(const QUuid &pUuid) override; - QSize nominalSize() const; bool hasLoadedSuccessfully() const; diff --git a/src/domain/UBItem.cpp b/src/domain/UBItem.cpp index 80c489086..9a0cfa1e8 100644 --- a/src/domain/UBItem.cpp +++ b/src/domain/UBItem.cpp @@ -97,12 +97,6 @@ bool UBGraphicsItem::isHiddenOnDisplay(QGraphicsItem *item) return item->data(UBGraphicsItemData::ItemIsHiddenOnDisplay).toBool(); } -QUuid UBGraphicsItem::getOwnUuid(QGraphicsItem *item) -{ - QString idCandidate = item->data(UBGraphicsItemData::ItemUuid).toString(); - return idCandidate == QUuid().toString() ? QUuid() : QUuid(idCandidate); -} - void UBGraphicsItem::remove(bool canUndo) { if (Delegate()) diff --git a/src/domain/UBItem.h b/src/domain/UBItem.h index eef10ba3b..e96ca67ec 100644 --- a/src/domain/UBItem.h +++ b/src/domain/UBItem.h @@ -133,7 +133,6 @@ class UBGraphicsItem static bool isFlippable(QGraphicsItem *item); static bool isLocked(QGraphicsItem *item); static bool isHiddenOnDisplay(QGraphicsItem *item); - static QUuid getOwnUuid(QGraphicsItem *item); static UBGraphicsItemDelegate *Delegate(QGraphicsItem *pItem); diff --git a/src/frameworks/UBCoreGraphicsScene.cpp b/src/frameworks/UBCoreGraphicsScene.cpp index 5d16d0a54..f34e41ef9 100644 --- a/src/frameworks/UBCoreGraphicsScene.cpp +++ b/src/frameworks/UBCoreGraphicsScene.cpp @@ -29,8 +29,6 @@ #include "UBCoreGraphicsScene.h" -#include "domain/UBGraphicsMediaItem.h" -#include "domain/UBGraphicsWidgetItem.h" #include "domain/UBGraphicsGroupContainerItem.h" #include "core/memcheck.h" @@ -72,11 +70,25 @@ void UBCoreGraphicsScene::addItem(QGraphicsItem* item) if (item->scene() != this) QGraphicsScene::addItem(item); + + UBItem* ubitem = dynamic_cast(item); + + if (ubitem) + { + mItemsByUuid[ubitem->uuid()] = item; + } } void UBCoreGraphicsScene::removeItem(QGraphicsItem* item, bool forceDelete) { + UBItem* ubitem = dynamic_cast(item); + + if (ubitem) + { + mItemsByUuid.remove(ubitem->uuid()); + } + QGraphicsScene::removeItem(item); if (forceDelete) { @@ -110,3 +122,8 @@ void UBCoreGraphicsScene::addItemToDeletion(QGraphicsItem *item) mItemsToDelete.insert(item); } } + +QGraphicsItem* UBCoreGraphicsScene::itemForUuid(const QUuid& uuid) const +{ + return mItemsByUuid.value(uuid, nullptr); +} diff --git a/src/frameworks/UBCoreGraphicsScene.h b/src/frameworks/UBCoreGraphicsScene.h index 4df05d1fa..c010d87b3 100644 --- a/src/frameworks/UBCoreGraphicsScene.h +++ b/src/frameworks/UBCoreGraphicsScene.h @@ -33,6 +33,7 @@ #include #include #include +#include class UBCoreGraphicsScene : public QGraphicsScene { @@ -59,9 +60,11 @@ class UBCoreGraphicsScene : public QGraphicsScene mIsModified = pModified; } + QGraphicsItem* itemForUuid(const QUuid& uuid) const; private: QSet mItemsToDelete; + QHash mItemsByUuid; bool mIsModified; }; diff --git a/src/tools/UBGraphicsCurtainItem.cpp b/src/tools/UBGraphicsCurtainItem.cpp index 36fa5d688..5d7f6d0ac 100644 --- a/src/tools/UBGraphicsCurtainItem.cpp +++ b/src/tools/UBGraphicsCurtainItem.cpp @@ -86,12 +86,6 @@ QVariant UBGraphicsCurtainItem::itemChange(GraphicsItemChange change, const QVar return QGraphicsRectItem::itemChange(change, newValue); } -void UBGraphicsCurtainItem::setUuid(const QUuid &pUuid) -{ - UBItem::setUuid(pUuid); - setData(UBGraphicsItemData::ItemUuid, QVariant(pUuid)); //store item uuid inside the QGraphicsItem to fast operations with Items on the scene -} - void UBGraphicsCurtainItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (Delegate()->mousePressEvent(event)) diff --git a/src/tools/UBGraphicsCurtainItem.h b/src/tools/UBGraphicsCurtainItem.h index cca53e26e..6c8b6873b 100644 --- a/src/tools/UBGraphicsCurtainItem.h +++ b/src/tools/UBGraphicsCurtainItem.h @@ -61,8 +61,6 @@ class UBGraphicsCurtainItem : public QObject, public QGraphicsRectItem, public U //TODO UB 4.x not nice ... void triggerRemovedSignal(); - virtual void setUuid(const QUuid &pUuid); - signals: void removed(); From 2324ba7138c0701c243310a9dd3bb5309ac10710 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Fri, 11 Apr 2025 12:03:12 +0200 Subject: [PATCH 009/133] feat: asset based UUID for name of media asset files - create SHA-1 based UUIDs for media asset file names - such UUIDs are unique based on the file content - separate item UUID from asset UUID - don't treat as failure if target file exists: due to the hash based UUID it is very likely the correct file Signed-off-by: letsfindaway --- src/adaptors/UBSvgSubsetAdaptor.cpp | 12 ++--- src/board/UBBoardController.cpp | 77 +++++++++++------------------ src/board/UBBoardController.h | 4 +- src/core/UBDocumentManager.cpp | 10 ++++ src/core/UBPersistenceManager.cpp | 4 +- src/domain/CMakeLists.txt | 1 + src/domain/UBGraphicsPixmapItem.cpp | 1 + src/domain/UBGraphicsScene.cpp | 5 +- src/domain/UBGraphicsSvgItem.cpp | 5 +- src/domain/UBGraphicsSvgItem.h | 6 +-- src/domain/UBGraphicsWidgetItem.cpp | 2 +- src/domain/UBMediaAssetItem.cpp | 29 +++++++++++ src/domain/UBMediaAssetItem.h | 2 + src/domain/domain.pri | 1 + 14 files changed, 91 insertions(+), 68 deletions(-) create mode 100644 src/domain/UBMediaAssetItem.cpp diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index 69ac1cb94..56319efc3 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -2158,15 +2158,11 @@ QList UBSvgSubsetAdaptor::UBSvgSubsetReader::polygonItem void UBSvgSubsetAdaptor::UBSvgSubsetWriter::pixmapItemToLinkedImage(UBGraphicsPixmapItem* pixmapItem) { - // find image file - QDir imageDir = mDocumentPath + "/" + UBPersistenceManager::imageDirectory; - QStringList imageFiles = imageDir.entryList({pixmapItem->uuid().toString() + ".*"}); - - if (imageFiles.size() >= 1) + if (!pixmapItem->mediaAssets().isEmpty()) { mXmlWriter.writeStartElement("image"); - QString fileName = UBPersistenceManager::imageDirectory + "/" + imageFiles.last(); + QString fileName = pixmapItem->mediaAssets().at(0); mXmlWriter.writeAttribute(nsXLink, "href", fileName); @@ -2210,7 +2206,7 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::svgItemToLinkedSvg(UBGraphicsSvgItem mXmlWriter.writeStartElement("image"); - QString fileName = UBPersistenceManager::imageDirectory + "/" + svgItem->uuid().toString() + ".svg"; + QString fileName = svgItem->mediaAssets().at(0); mXmlWriter.writeAttribute(nsXLink, "href", fileName); @@ -2647,7 +2643,7 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::graphicsWidgetToSvg(UBGraphicsWidget QFileInfo fi(widgetRootDir); QString extension = fi.suffix(); - QString widgetTargetDir = widgetDirectoryPath + "/" + item->uuid().toString() + "." + extension; + QString widgetTargetDir = item->mediaAssets().at(0); QString path = mDocumentPath + "/" + widgetTargetDir; QDir dir(path); diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index 3ea0c1419..0b5eee26c 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -1381,9 +1381,10 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl qDebug() << "accepting mime type" << mimeType << "as video"; UBGraphicsMediaItem *mediaVideoItem = 0; - QUuid uuid = QUuid::createUuid(); + if (pData.length() > 0) { + QUuid uuid = UBMediaAssetItem::mediaAssetUuid(pData); QString destFile; bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(selectedDocument(), sourceUrl.toString(), @@ -1404,7 +1405,7 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl else { qDebug() << sourceUrl.toString(); - mediaVideoItem = addVideo(sourceUrl, false, pPos, true); + mediaVideoItem = addVideo(sourceUrl, false, pPos); } if(mediaVideoItem){ @@ -1412,7 +1413,6 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl mediaVideoItem->setSourceUrl(sourceUrl); else mediaVideoItem->setSourceUrl(contentUrl); - mediaVideoItem->setUuid(uuid); connect(this, SIGNAL(activeSceneChanged()), mediaVideoItem, SLOT(activeSceneChanged())); } @@ -1426,9 +1426,9 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl UBGraphicsMediaItem *audioMediaItem = 0; - QUuid uuid = QUuid::createUuid(); if (pData.length() > 0) { + QUuid uuid = UBMediaAssetItem::mediaAssetUuid(pData); QString destFile; bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(selectedDocument(), sourceUrl.toString(), @@ -1448,7 +1448,7 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl } else { - audioMediaItem = addAudio(sourceUrl, false, pPos, true); + audioMediaItem = addAudio(sourceUrl, false, pPos); } if(audioMediaItem){ @@ -1456,7 +1456,6 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl audioMediaItem->setSourceUrl(sourceUrl); else audioMediaItem->setSourceUrl(contentUrl); - audioMediaItem->setUuid(uuid); connect(this, SIGNAL(activeSceneChanged()), audioMediaItem, SLOT(activeSceneChanged())); } @@ -2339,29 +2338,11 @@ void UBBoardController::grabScene(const QRectF& pSceneRect) } } -UBGraphicsMediaItem* UBBoardController::addVideo(const QUrl& pSourceUrl, bool startPlay, const QPointF& pos, bool bUseSource) +UBGraphicsMediaItem* UBBoardController::addVideo(const QUrl& pSourceUrl, bool startPlay, const QPointF& pos) { QUuid uuid = QUuid::createUuid(); QUrl concreteUrl = pSourceUrl; - // media file is not in document folder yet - if (!bUseSource) - { - QString destFile; - bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(selectedDocument(), - pSourceUrl.toLocalFile(), - UBPersistenceManager::videoDirectory, - uuid, - destFile); - if (!b) - { - UBApplication::showMessage(tr("Add file operation failed: file copying error")); - return NULL; - } - concreteUrl = QUrl::fromLocalFile(destFile); - }// else we just use source Url. - - UBGraphicsMediaItem* vi = mActiveScene->addMedia(concreteUrl, startPlay, pos); QDateTime now = QDateTime::currentDateTime(); selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(now)); @@ -2375,28 +2356,11 @@ UBGraphicsMediaItem* UBBoardController::addVideo(const QUrl& pSourceUrl, bool st } -UBGraphicsMediaItem* UBBoardController::addAudio(const QUrl& pSourceUrl, bool startPlay, const QPointF& pos, bool bUseSource) +UBGraphicsMediaItem* UBBoardController::addAudio(const QUrl& pSourceUrl, bool startPlay, const QPointF& pos) { QUuid uuid = QUuid::createUuid(); QUrl concreteUrl = pSourceUrl; - // media file is not in document folder yet - if (!bUseSource) - { - QString destFile; - bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(selectedDocument(), - pSourceUrl.toLocalFile(), - UBPersistenceManager::audioDirectory, - uuid, - destFile); - if (!b) - { - UBApplication::showMessage(tr("Add file operation failed: file copying error")); - return NULL; - } - concreteUrl = QUrl::fromLocalFile(destFile); - }// else we just use source Url. - UBGraphicsMediaItem* ai = mActiveScene->addMedia(concreteUrl, startPlay, pos); QDateTime now = QDateTime::currentDateTime(); selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(now)); @@ -2414,21 +2378,40 @@ UBGraphicsWidgetItem *UBBoardController::addW3cWidget(const QUrl &pUrl, const QP { UBGraphicsWidgetItem* w3cWidgetItem = 0; - QUuid uuid = QUuid::createUuid(); + QDir widgetDir{pUrl.toLocalFile()}; + + if (!widgetDir.exists()) + { + return nullptr; + } + + const auto widgetFiles = widgetDir.entryInfoList({"*.xml", "*.html"}, QDir::Files, QDir::Name); + QByteArray data; + + for (const auto fileInfo : widgetFiles) + { + QFile file(fileInfo.absoluteFilePath()); + + if (file.open(QFile::ReadOnly)) + { + data.append(file.readAll()); + } + } + + QUuid assetUuid = UBMediaAssetItem::mediaAssetUuid(data); QString destPath; - if (!UBPersistenceManager::persistenceManager()->addGraphicsWidgetToDocument(selectedDocument(), pUrl.toLocalFile(), uuid, destPath)) + if (!UBPersistenceManager::persistenceManager()->addGraphicsWidgetToDocument(selectedDocument(), pUrl.toLocalFile(), assetUuid, destPath)) return NULL; QUrl newUrl = QUrl::fromLocalFile(destPath); w3cWidgetItem = mActiveScene->addW3CWidget(newUrl, pos); if (w3cWidgetItem) { - w3cWidgetItem->setUuid(uuid); w3cWidgetItem->setOwnFolder(newUrl); w3cWidgetItem->setSourceUrl(pUrl); - QString struuid = UBStringUtils::toCanonicalUuid(uuid); + QString struuid = w3cWidgetItem->uuid().toString(QUuid::WithoutBraces); QString snapshotPath = selectedDocument()->persistencePath() + "/" + UBPersistenceManager::widgetDirectory + "/" + struuid + ".png"; w3cWidgetItem->setSnapshotPath(QUrl::fromLocalFile(snapshotPath)); } diff --git a/src/board/UBBoardController.h b/src/board/UBBoardController.h index 80eb1739c..605e56034 100644 --- a/src/board/UBBoardController.h +++ b/src/board/UBBoardController.h @@ -234,8 +234,8 @@ class UBBoardController : public UBDocumentContainer void setRegularPageSize(bool checked); void stylusToolChanged(int tool); void grabScene(const QRectF& pSceneRect); - UBGraphicsMediaItem* addVideo(const QUrl& pUrl, bool startPlay, const QPointF& pos, bool bUseSource = false); - UBGraphicsMediaItem* addAudio(const QUrl& pUrl, bool startPlay, const QPointF& pos, bool bUseSource = false); + UBGraphicsMediaItem* addVideo(const QUrl& pUrl, bool startPlay, const QPointF& pos); + UBGraphicsMediaItem* addAudio(const QUrl& pUrl, bool startPlay, const QPointF& pos); UBGraphicsWidgetItem *addW3cWidget(const QUrl& pUrl, const QPointF& pos); void adjustDisplayViews(); void cut(); diff --git a/src/core/UBDocumentManager.cpp b/src/core/UBDocumentManager.cpp index 2669d6dd1..4597f103a 100644 --- a/src/core/UBDocumentManager.cpp +++ b/src/core/UBDocumentManager.cpp @@ -44,6 +44,7 @@ #include "board/UBBoardController.h" #include "domain/UBGraphicsScene.h" +#include "domain/UBMediaAssetItem.h" #include "document/UBDocumentProxy.h" #include "document/UBDocumentController.h" @@ -279,7 +280,16 @@ int UBDocumentManager::addFilesToDocument(std::shared_ptr docum { UBPageBasedImportAdaptor* importAdaptor = (UBPageBasedImportAdaptor*)adaptor; + QByteArray data; QUuid uuid = QUuid::createUuid(); + + if (file.open(QFile::ReadOnly)) + { + data = file.readAll(); + file.close(); + uuid = UBMediaAssetItem::mediaAssetUuid(data); + } + QString filepath = file.fileName(); if (importAdaptor->folderToCopy() != "") { diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index 3b5efdb25..fe274370a 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -1238,7 +1238,7 @@ bool UBPersistenceManager::addFileToDocument(std::shared_ptr pD } else { - return false; + return true; } } @@ -1264,7 +1264,7 @@ bool UBPersistenceManager::addGraphicsWidgetToDocument(std::shared_ptrsetSourceUrl(this->sourceUrl()); cp->setZValue(this->zValue()); + cp->mMediaAsset = mMediaAsset; } } diff --git a/src/domain/UBGraphicsScene.cpp b/src/domain/UBGraphicsScene.cpp index b0b95dae0..fd76058d3 100644 --- a/src/domain/UBGraphicsScene.cpp +++ b/src/domain/UBGraphicsScene.cpp @@ -1401,6 +1401,7 @@ std::shared_ptr UBGraphicsScene::sceneDeepCopy() const { std::shared_ptr copy = std::make_shared(this->document(), this->mUndoRedoStackEnabled); + copy->setUuid(this->uuid()); copy->setBackground(this->isDarkBackground(), mPageBackground); copy->setBackgroundGridSize(mBackgroundGridSize); copy->setSceneRect(this->sceneRect()); @@ -1636,7 +1637,7 @@ UBGraphicsPixmapItem* UBGraphicsScene::addImage(QByteArray pData, QGraphicsItem* format = "png." + format; } - QString fileName = UBPersistenceManager::imageDirectory + "/" + pixmapItem->uuid().toString() + "." + format; + QString fileName = UBPersistenceManager::imageDirectory + "/" + UBMediaAssetItem::mediaAssetUuid(pData).toString() + "." + format; pixmapItem->setMediaAsset(documentPath, fileName); QString path = documentPath + "/" + fileName; @@ -1865,7 +1866,7 @@ UBGraphicsSvgItem* UBGraphicsScene::addSvg(const QUrl& pSvgFileUrl, const QPoint QString documentPath = UBApplication::boardController->selectedDocument()->persistencePath(); - QString fileName = UBPersistenceManager::imageDirectory + "/" + svgItem->uuid().toString() + ".svg"; + QString fileName = svgItem->mediaAssets().at(0); QString completePath = documentPath + "/" + fileName; diff --git a/src/domain/UBGraphicsSvgItem.cpp b/src/domain/UBGraphicsSvgItem.cpp index b5965573c..cbfa26cba 100644 --- a/src/domain/UBGraphicsSvgItem.cpp +++ b/src/domain/UBGraphicsSvgItem.cpp @@ -55,6 +55,7 @@ UBGraphicsSvgItem::UBGraphicsSvgItem(const QString& pFilePath, QGraphicsItem* pa { mFileData = f.readAll(); f.close(); + mMediaAssetUuid = mediaAssetUuid(mFileData); } } @@ -67,6 +68,7 @@ UBGraphicsSvgItem::UBGraphicsSvgItem(const QByteArray& pFileData, QGraphicsItem* setSharedRenderer(renderer); mFileData = pFileData; + mMediaAssetUuid = mediaAssetUuid(mFileData); } @@ -98,7 +100,7 @@ UBGraphicsSvgItem::~UBGraphicsSvgItem() QList UBGraphicsSvgItem::mediaAssets() const { - return {UBPersistenceManager::imageDirectory + "/" + uuid().toString() + ".svg"}; + return {UBPersistenceManager::imageDirectory + "/" + mMediaAssetUuid.toString() + ".svg"}; } @@ -191,6 +193,7 @@ void UBGraphicsSvgItem::copyItemParameters(UBItem *copy) const cp->setData(UBGraphicsItemData::ItemOwnZValue, this->data(UBGraphicsItemData::ItemOwnZValue)); cp->setSourceUrl(this->sourceUrl()); cp->setZValue(this->zValue()); + cp->mMediaAssetUuid = mMediaAssetUuid; } } diff --git a/src/domain/UBGraphicsSvgItem.h b/src/domain/UBGraphicsSvgItem.h index 799941be5..0e0413aed 100644 --- a/src/domain/UBGraphicsSvgItem.h +++ b/src/domain/UBGraphicsSvgItem.h @@ -54,11 +54,6 @@ class UBGraphicsSvgItem: public QGraphicsSvgItem, public UBMediaAssetItem, publi QByteArray fileData() const; - void setFileData(const QByteArray& pFileData) - { - mFileData = pFileData; - } - enum { Type = UBGraphicsItemType::SvgItemType }; virtual int type() const override @@ -87,6 +82,7 @@ class UBGraphicsSvgItem: public QGraphicsSvgItem, public UBMediaAssetItem, publi virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; QByteArray mFileData; + QUuid mMediaAssetUuid; }; #endif /* UBGRAPHICSSVGITEM_H_ */ diff --git a/src/domain/UBGraphicsWidgetItem.cpp b/src/domain/UBGraphicsWidgetItem.cpp index b8788e9b2..78bafdb25 100644 --- a/src/domain/UBGraphicsWidgetItem.cpp +++ b/src/domain/UBGraphicsWidgetItem.cpp @@ -201,7 +201,7 @@ UBGraphicsWidgetItem::~UBGraphicsWidgetItem() QList UBGraphicsWidgetItem::mediaAssets() const { - const QString widgetPath = UBPersistenceManager::widgetDirectory + "/" + uuid().toString() + ".wgt"; + const QString widgetPath = UBPersistenceManager::widgetDirectory + "/" + mWidgetUrl.fileName(); const QString screenshotPath = UBPersistenceManager::widgetDirectory + "/" + uuid().toString(QUuid::WithoutBraces) + ".png"; return {widgetPath, screenshotPath}; } diff --git a/src/domain/UBMediaAssetItem.cpp b/src/domain/UBMediaAssetItem.cpp new file mode 100644 index 000000000..b582c415f --- /dev/null +++ b/src/domain/UBMediaAssetItem.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + +#include "UBMediaAssetItem.h" + +QUuid UBMediaAssetItem::mediaAssetUuid(const QByteArray& data) +{ + static QUuid namespaceUuid{QUuid::createUuidV5(QUuid(), QString("OpenBoard"))}; + + return QUuid::createUuidV5(namespaceUuid, data); +} diff --git a/src/domain/UBMediaAssetItem.h b/src/domain/UBMediaAssetItem.h index ac9f8a50b..2d3def474 100644 --- a/src/domain/UBMediaAssetItem.h +++ b/src/domain/UBMediaAssetItem.h @@ -37,4 +37,6 @@ class UBMediaAssetItem : public UBItem virtual QList mediaAssets() const = 0; virtual void setMediaAsset(const QString& documentPath, const QString& mediaAsset) {} + + static QUuid mediaAssetUuid(const QByteArray& data); }; diff --git a/src/domain/domain.pri b/src/domain/domain.pri index 3db8010df..0776fe94d 100644 --- a/src/domain/domain.pri +++ b/src/domain/domain.pri @@ -38,6 +38,7 @@ SOURCES += src/domain/UBGraphicsScene.cpp \ src/domain/UBGraphicsSvgItem.cpp \ src/domain/UBGraphicsPolygonItem.cpp \ src/domain/UBItem.cpp \ + src/domain/UBMediaAssetItem.cpp \ src/domain/UBGraphicsWidgetItem.cpp \ src/domain/UBGraphicsPDFItem.cpp \ src/domain/UBGraphicsTextItem.cpp \ From 614629a0db689a66f72a38f15f82b1bc67a56f78 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sat, 12 Apr 2025 07:49:47 +0200 Subject: [PATCH 010/133] cleanup: remove UBForeignObjectsHandler - class is no longer used or referenced anywhere Signed-off-by: letsfindaway --- src/adaptors/UBExportDocumentSetAdaptor.cpp | 8 - src/core/CMakeLists.txt | 2 - src/core/UBForeignObjectsHandler.cpp | 651 -------------------- src/core/UBForeignObjectsHandler.h | 54 -- src/core/UBPersistenceManager.cpp | 1 - src/core/core.pri | 6 +- 6 files changed, 2 insertions(+), 720 deletions(-) delete mode 100644 src/core/UBForeignObjectsHandler.cpp delete mode 100644 src/core/UBForeignObjectsHandler.h diff --git a/src/adaptors/UBExportDocumentSetAdaptor.cpp b/src/adaptors/UBExportDocumentSetAdaptor.cpp index 752b5ea38..2413ebb92 100644 --- a/src/adaptors/UBExportDocumentSetAdaptor.cpp +++ b/src/adaptors/UBExportDocumentSetAdaptor.cpp @@ -38,7 +38,6 @@ #include "globals/UBGlobals.h" #include "core/UBPersistenceManager.h" -#include "core/UBForeignObjectsHandler.h" #ifdef Q_OS_OSX #include @@ -165,14 +164,7 @@ bool UBExportDocumentSetAdaptor::addDocumentToZip(const QModelIndex &pIndex, UBD std::shared_ptrpDocumentProxy = model->proxyForIndex(parentIndex); if (pDocumentProxy) { - -// Q_ASSERT(QFileInfo(pDocumentProxy->persistencePath()).exists()); -// UBForeighnObjectsHandler cleaner; -// cleaner.cure(pDocumentProxy->persistencePath()); - - //UniboardSankoreTransition document; QString documentPath(pDocumentProxy->persistencePath()); - //document.checkDocumentDirectory(documentPath); QDir documentDir = QDir(pDocumentProxy->persistencePath()); QuaZipFile zipFile(&zip); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4ac038907..6bbca8173 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -13,8 +13,6 @@ target_sources(${PROJECT_NAME} PRIVATE UBDownloadManager.h UBDownloadThread.cpp UBDownloadThread.h - UBForeignObjectsHandler.cpp - UBForeignObjectsHandler.h UBIdleTimer.cpp UBIdleTimer.h UBMimeData.cpp diff --git a/src/core/UBForeignObjectsHandler.cpp b/src/core/UBForeignObjectsHandler.cpp deleted file mode 100644 index 1ad3ee982..000000000 --- a/src/core/UBForeignObjectsHandler.cpp +++ /dev/null @@ -1,651 +0,0 @@ -/* - * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) - * - * Copyright (C) 2013 Open Education Foundation - * - * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour - * l'Education Numérique en Afrique (GIP ENA) - * - * This file is part of OpenBoard. - * - * OpenBoard is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License, - * with a specific linking exception for the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the - * same license as the "OpenSSL" library). - * - * OpenBoard is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with OpenBoard. If not, see . - */ - -#include "UBForeignObjectsHandler.h" - -#include -#include -#include "UBSettings.h" - -const QString tVideo = "video"; -const QString tAudio = "audio"; -const QString tImage = "image"; -const QString tForeignObject = "foreignObject"; -const QString tTeacherGuide = "teacherGuide"; -const QString tMedia = "media"; -const QString tGroups = "groups"; - -const QString aHref = "xlink:href"; -const QString aType = "ub:type"; -const QString aReqExt = "requiredExtensions"; -const QString aSrc = "ub:src"; -const QString aMediaType = "mediaType"; -const QString aRelativePath = "relativePath"; -const QString aActionMedia = "ub:actionFirstParameter"; - -const QString vText = "text"; -const QString vReqExt = "http://ns.adobe.com/pdf/1.3/"; - -const QString wgtSuff = ".wgt"; -const QString thumbSuff = ".png"; - -const QString scanDirs = "audios,images,videos,teacherGuideObjects,widgets"; -const QStringList trashFilter = QStringList() << "*.swf"; - - -static QString strIdFrom(const QString &filePath) -{ - if ((filePath).isEmpty()) { - return QString(); - } - - static const QRegularExpression rx("\\{.(?!.*\\{).*\\}"); - QRegularExpressionMatch match = rx.match(filePath); - if (!match.hasMatch()) { - return QString(); - } - - return match.captured(); -} - -static bool rm_r(const QString &rmPath) -{ - QFileInfo fi(rmPath); - if (!fi.exists()) { - qDebug() << rmPath << "does not exist"; - return false; - } else if (fi.isFile()) { - if (!QFile::remove(rmPath)) { - qDebug() << "can't remove file" << rmPath; - return false; - } - return true; - } else if (fi.isDir()) { - QFileInfoList fList = QDir(rmPath).entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot); - foreach (QFileInfo sub, fList) { - rm_r(sub.absoluteFilePath()); - } - if (!QDir().rmdir(rmPath)) { - qDebug() << "can't remove dir" << rmPath; - return false; - } - return true; - } - return false; -} - -static bool cp_rf(const QString &what, const QString &where) -{ - QFileInfo whatFi(what); - QFileInfo whereFi = QFileInfo(where); - - if (!whatFi.exists()) { - qDebug() << what << "does not exist" << Q_FUNC_INFO; - return false; - } else if (whatFi.isFile()) { - QString whereDir = where.section("/", 0, -2, QString::SectionSkipEmpty | QString::SectionIncludeLeadingSep); - QString newFilePath = where; - if (!whereFi.exists()) { - QDir().mkpath(whereDir); - } else if (whereFi.isDir()) { - newFilePath = whereDir + "/" + whatFi.fileName(); - } - if (QFile::exists(newFilePath)) { - QFile::remove(newFilePath); - } - if (!QFile::copy(what, newFilePath)) { - qDebug() << "can't copy" << what << "to" << where << Q_FUNC_INFO; - return false; - } - return true; - } else if (whatFi.isDir()) { - - if (whereFi.isFile() && whereFi.fileName().toLower() == whatFi.fileName().toLower()) { - qDebug() << "can't copy dir" << what << "to file" << where << Q_FUNC_INFO; - return false; - } else if (whereFi.isDir()) { - rm_r(where); - } - - QDir().mkpath(where); - - QFileInfoList fList = QDir(what).entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot); - foreach (QFileInfo sub, fList) { - if (!cp_rf(sub.absoluteFilePath(), where + "/" + sub.fileName())) - return false; - } - return true; - } - return true; -} - -static QString thumbFileNameFrom(const QString &filePath) -{ - if (filePath.isEmpty()) { - return QString(); - } - - static const QRegularExpression braces("[\\{\\}]"); - QString thumbPath = filePath; - thumbPath.replace(braces, "").replace(wgtSuff, thumbSuff); - - return thumbPath; -} - - -QString svgPageName(int pageIndex) -{ - return QString("page%1.svg").arg(pageIndex, 3, 10, QLatin1Char('0')); -} - -static QDomDocument createDomFromSvg(const QString &svgUrl) -{ - Q_ASSERT(QFile::exists(svgUrl)); - QString mFoldersXmlStorageName = svgUrl; - - if (QFileInfo(mFoldersXmlStorageName).exists()) { - QDomDocument xmlDom; - QFile inFile(mFoldersXmlStorageName); - if (inFile.open(QIODevice::ReadOnly)) { - QString domString(inFile.readAll()); - - int errorLine = 0; int errorColumn = 0; - QString errorStr; - - if (xmlDom.setContent(domString, &errorStr, &errorLine, &errorColumn)) { - return xmlDom; - } else { - qDebug() << "Error reading content of " << mFoldersXmlStorageName << '\n' - << "Error:" << inFile.errorString() - << "Line:" << errorLine - << "Column:" << errorColumn; - } - inFile.close(); - } else { - qDebug() << "Error reading" << mFoldersXmlStorageName << '\n' - << "Error:" << inFile.errorString(); - } - } - - return QDomDocument(); -} - -class Cleaner -{ -public: - void cure(const QUrl &dir) - { - mCurrentDir = dir.toLocalFile(); - cleanTrash(); - - // Gathering information from svg files - QFileInfoList svgInfos = QDir(mCurrentDir).entryInfoList(QStringList() << "*.svg", QDir::NoDotAndDotDot | QDir::Files); - foreach (QFileInfo svgInfo, svgInfos) { - cureIdsFromSvgDom(createDomFromSvg(svgInfo.absoluteFilePath())); - } - - fitIdsFromFileSystem(); - QVector deleteCandidates; - findRedundandElements(deleteCandidates); - - foreach (QString key, deleteCandidates) { - QString delPath = mPresentIdsMap.value(key); - if (delPath.isNull()) { - continue; - } else if (delPath.endsWith(wgtSuff)) { //remove corresponding thumb - QString thumbPath = thumbFileNameFrom(delPath); - - //N/C - NNE - 20140417 - if (QFile::exists(thumbPath)) { - rm_r(thumbPath); - } - } - rm_r(delPath); - // Clear parent dir if empty - QDir dir(delPath); - dir.cdUp(); - if (dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot).isEmpty()) { - dir.rmdir(dir.absolutePath()); - } - } - - qDebug() << "Ok on cure"; - } - -private: - void cleanTrash() - { - QFileInfoList ifs = QDir(mCurrentDir).entryInfoList(trashFilter, QDir::NoDotAndDotDot | QDir::Files); - foreach (QFileInfo ifo, ifs) { - rm_r(ifo.absoluteFilePath()); - } - } - - void cureIdsFromSvgDom(const QDomDocument &dom) - { - Q_ASSERT(!dom.isNull()); - - QDomElement nextElement = dom.documentElement().firstChildElement(); - while (!nextElement.isNull()) { - QString nextTag = nextElement.tagName(); - qDebug() << "Tag name of the next parsed element is" << nextTag; - if (nextTag == tGroups) - { - nextElement = nextElement.firstChildElement("group"); - } - - invokeFromText(nextTag, nextElement); - nextElement = nextElement.nextSiblingElement(); - } - } - - void fitIdsFromFileSystem() - { - QString absPrefix = mCurrentDir + "/"; - QStringList dirsList = scanDirs.split(",", UB::SplitBehavior::SkipEmptyParts); - foreach (QString dirName, dirsList) { - QString absPath = absPrefix + dirName; - if (!QFile::exists(absPath)) { - continue; - } - fitIdsFromDir(absPath); - } - - } - - void fitIdsFromDir(const QString &scanDir) - { - QFileInfoList fileList = QDir(scanDir).entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); - foreach (QFileInfo nInfo, fileList) { - QString uid = strIdFrom(nInfo.fileName()); - if (uid.isNull()) { - continue; - } - mPresentIdsMap.insert(uid, nInfo.absoluteFilePath()); - } - } - - void findRedundandElements(QVector &v) - { - // Taking information from the physical file system - QStringList domIds = mDomIdsMap.keys(); - QStringList presentIds = mPresentIdsMap.keys(); - v.resize(qMax(domIds.count(), presentIds.count())); - QVector::iterator it_diff; - - it_diff=std::set_symmetric_difference(domIds.begin(), domIds.end() - , presentIds.begin(), presentIds.end() - , v.begin()); - v.resize(it_diff - v.begin()); - } - - void invokeFromText(const QString &what, const QDomElement &element) - { - if (what == tVideo - || what == tAudio - || what == tImage) { - mediaToContainer(element); - } else if (what == tForeignObject) { - foreingObjectToContainer(element); - - //N/C - NNE - 20140317 - cleanObjectFolder(element); - - //N/C - NNE - 20140520 - //foreign object may referer resource which are not present in the svg - addResourceIdToSvg(element); - } else if (what == tTeacherGuide) { - teacherGuideToContainer(element); - } - - pullActionFromElement(element); - } - - // N/C - NNE - 20140317 : When export, reduce the size of the ubz file - void cleanObjectFolder(const QDomElement &element) - { - //QDomElement preference = element.firstChildElement("ub:preference"); - - //N/C - NNE - 20141021 - QDomNodeList childrenNode = element.elementsByTagName("ub:preference"); - - QVector objectsIdUsed; - - for(int i = 0; i < childrenNode.size(); i++){ - QDomElement preference = childrenNode.at(i).toElement(); - - if(!preference.isNull()){ - QString value = preference.attribute("value"); - - int findPos = value.indexOf("objects/"); - int endPos; - - //find all objects used - while(findPos != -1){ - endPos = value.indexOf("\"", findPos); - objectsIdUsed << value.mid(findPos, endPos - findPos); - findPos = value.indexOf("objects/", endPos); - } - } - } - //N/C - NNE - 20141021 : END - - - QString path = element.attribute(aSrc); - QString objectsFolderPath = mCurrentDir + "/" + path + "/objects/"; - - QDir dir(objectsFolderPath); - dir.setFilter(QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot); - - //then check all files in the objects directory - //delete the file not used (not in te objectIdUsed variable) - QFileInfoList list = dir.entryInfoList(); - for (int i = 0; i < list.size(); i++) { - QFileInfo fileInfo = list.at(i); - - if(!objectsIdUsed.contains("objects/"+fileInfo.fileName())){ - QFile(fileInfo.filePath()).remove(); - } - - } - } - // N/C - NNE - 20140317 : END - - //N/C - NNE - 20140520 - void addResourceIdToSvg(const QDomElement& element) - { - QDomElement textContent = element.firstChildElement("itemTextContent"); - - QString value = textContent.text(); - - int findPos = value.indexOf("images/"); - int endPos; - - //find all objects used - while(findPos != -1){ - endPos = value.indexOf("\"", findPos); - - QString path = value.mid(findPos, endPos - findPos); - - QString uuid = path.split("/").at(1).split(".").at(0); - - mDomIdsMap.insert(uuid, path); - - findPos = value.indexOf("images/", endPos); - } - } - //N/C - NNE - 20140520 : END - - void pullActionFromElement(const QDomElement &element) - { - if (!element.hasAttribute(aActionMedia)) { - return; - } - - QString path = element.attribute(aActionMedia); - if (path.isNull()) { - return; - } - - QString uid = strIdFrom(path); - if (uid.isNull()) { - return; - } - - mDomIdsMap.insert(uid, path); - } - - void teacherGuideToContainer(const QDomElement &element) - { - QDomElement nMediaElement = element.firstChildElement(tMedia); - while (!nMediaElement.isNull()) { - - QString path = nMediaElement.attribute(aRelativePath); - if (path.isNull()) { - continue; - } - - QString uid = strIdFrom(path); - if (uid.isNull()) { - return; - } - mDomIdsMap.insert(uid, path); - - nMediaElement = nMediaElement.nextSiblingElement(tMedia); - } - } - - void mediaToContainer(const QDomElement &element) - { - QString path = element.attribute(aHref); - if (path.isNull()) { - return; - } - QString uid = strIdFrom(path); - if (uid.isNull()) { - return; - } - mDomIdsMap.insert(uid, path); - } - - void foreingObjectToContainer(const QDomElement &element) - { - QString type = element.attribute(aType); - if (type == vText) { // We don't have to care of the text object - return; - } - - QString path = element.attribute(aSrc); - if (path.isNull()) { - return; - } - - QString uid = strIdFrom(path); - if (uid.isNull()) { - return; - } - - mDomIdsMap.insert(uid, path); - } - -private: - QString mCurrentDir; - QDomDocument mSvgData; - QMap mDomIdsMap; - QMap mPresentIdsMap; -}; - -class PageCopier -{ -public: - void copyPage (const QUrl &fromDir, int fromIndex, const QUrl &toDir, int toIndex) - { - mFromDir = fromDir.toLocalFile(); - mToDir = toDir.toLocalFile(); - mFromIndex = fromIndex; - mToIndex = toIndex; - - QString svgFrom = mFromDir + "/" + svgPageName(fromIndex); - QString svgTo = toDir.toLocalFile() + "/" + svgPageName(toIndex); - QDomDocument dd = createDomFromSvg(svgFrom); - QFile fl(svgTo); - if (!fl.open(QIODevice::WriteOnly)) { - qDebug() << Q_FUNC_INFO << "can't open" << fl.fileName() << "for writing"; - return; - } - cureIdsFromSvgDom(dd); - - QTextStream str(&fl); - dd.save(str, 0); - fl.close(); - qDebug() << Q_FUNC_INFO; - } - -private: - void cureIdsFromSvgDom(const QDomDocument &dom) - { - Q_ASSERT(!dom.isNull()); - - QDomElement nextElement = dom.documentElement().firstChildElement(); - while (!nextElement.isNull( )) { - qDebug() << "Tag name of the next parsed element is" << nextElement.tagName(); - QString nextTag = nextElement.tagName(); - cureFromText(nextTag, nextElement); - nextElement = nextElement.nextSiblingElement(); - } - } - - void cureFromText(const QString &tagName, QDomElement element) - { - if (tagName == tVideo - || tagName == tAudio - || tagName == tImage) { - QString newRelative = cureNCopy(element.attribute(aHref)); - element.setAttribute(aHref, newRelative); - if (element.hasAttribute(aActionMedia)) { - QString newActionPath = cureNCopy(element.attribute(aActionMedia)); - element.setAttribute(aActionMedia, newActionPath); - } - } else if (tagName == tForeignObject) { - //Pdf object is a special case. Detect if it ends with #reference - QString reqExt = element.attribute(aReqExt); - if (reqExt == vReqExt) { //pdf reference - QString ref = element.attribute(aHref); - int i = ref.indexOf("#page"); - QString dest = ref.replace(i, ref.length()-i, ""); - if (!QFileInfo::exists(dest)) - cureNCopy(dest, false); - if (ref.isEmpty()) { - return; - } - static const QRegularExpression pdfReference("^(.*pdf\\#page\\=).*$"); - ref.replace(pdfReference, QString("\\1%1").arg(mToIndex)); - return; - } - - QString type = element.attribute(aType); - if (type == vText) { // We don't have to care of the text object - if (element.hasAttribute(aActionMedia)) { - QString newRelative = cureNCopy(element.attribute(aActionMedia)); - element.setAttribute(aActionMedia, newRelative); - } - return; - } - QString newRelative = cureNCopy(element.attribute(aSrc)); - element.setAttribute(aSrc, newRelative); - } else if (tagName == tTeacherGuide) { - QDomElement nMediaElement = element.firstChildElement(tMedia); - while (!nMediaElement.isNull()) { - QString newRelative = cureNCopy(nMediaElement.attribute(aRelativePath)); - nMediaElement.setAttribute(aRelativePath, newRelative); - nMediaElement = nMediaElement.nextSiblingElement(tMedia); - } - } - } - - QString cureNCopy(const QString &relativePath, bool createNewUuid=true) - { - QString relative = relativePath; - if (createNewUuid) - { - QUuid newUuid = QUuid::createUuid(); - static const QRegularExpression bracedUuid("\\{.*\\}"); - QString newPath = relative.replace(bracedUuid, newUuid.toString()); - - cp_rf(mFromDir + "/" + relativePath, mToDir + "/" + newPath); - - return newPath; - } - else - { - cp_rf(mFromDir + "/" + relativePath, mToDir + "/" + relativePath); - return relativePath; - } - } - -private: - QString mFromDir; - QString mToDir; - int mFromIndex; - int mToIndex; -}; - -class UBForeighnObjectsHandlerPrivate { - UBForeighnObjectsHandlerPrivate(UBForeighnObjectsHandler *pq) - : q(pq) - { - } - -public: - void cure(const QUrl &dir) - { - Cleaner *cleaner = new Cleaner; - cleaner->cure(dir); - delete cleaner; - cleaner = 0; - } - - void copyPage (const QUrl &fromDir, int fromIndex, const QUrl &toDir, int toIndex) - { - PageCopier *copier = new PageCopier; - copier->copyPage(fromDir, fromIndex, toDir, toIndex); - delete copier; - copier = 0; - } - -private: - UBForeighnObjectsHandler *q; - friend class UBForeighnObjectsHandler; -}; - -UBForeighnObjectsHandler::UBForeighnObjectsHandler() - : d(new UBForeighnObjectsHandlerPrivate(this)) -{ - -} - -UBForeighnObjectsHandler::~UBForeighnObjectsHandler() -{ - delete d; -} - -void UBForeighnObjectsHandler::cure(const QList &dirs) -{ - foreach (QUrl dir, dirs) { - cure(dir); - } -} - -void UBForeighnObjectsHandler::cure(const QUrl &dir) -{ - d->cure(dir); -} - -void UBForeighnObjectsHandler::copyPage(const QUrl &fromDir, int fromIndex, const QUrl &toDir, int toIndex) -{ - d->copyPage(fromDir, fromIndex, toDir, toIndex); -} - diff --git a/src/core/UBForeignObjectsHandler.h b/src/core/UBForeignObjectsHandler.h deleted file mode 100644 index 7d03464b9..000000000 --- a/src/core/UBForeignObjectsHandler.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) - * - * Copyright (C) 2013 Open Education Foundation - * - * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour - * l'Education Numérique en Afrique (GIP ENA) - * - * This file is part of OpenBoard. - * - * OpenBoard is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License, - * with a specific linking exception for the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the - * same license as the "OpenSSL" library). - * - * OpenBoard is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with OpenBoard. If not, see . - */ - -#ifndef UBFOREIGHNOBJECTSHANDLER_H -#define UBFOREIGHNOBJECTSHANDLER_H - -#include -#include -#include - -class UBForeighnObjectsHandlerPrivate; - -class UBForeighnObjectsHandler -{ -public: - UBForeighnObjectsHandler(); - ~UBForeighnObjectsHandler(); - - void cure(const QList &dirs); - void cure(const QUrl &dir); - - void copyPage(const QUrl &fromDir, int fromIndex, - const QUrl &toDir, int toIndex); - -private: - UBForeighnObjectsHandlerPrivate *d; - - friend class UBForeighnObjectsHandlerPrivate; -}; - -#endif // UBFOREIGHNOBJECTSHANDLER_H diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index fe274370a..3fcbedf59 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -42,7 +42,6 @@ #include "core/UBApplication.h" #include "core/UBSettings.h" #include "core/UBSetting.h" -#include "core/UBForeignObjectsHandler.h" #include "document/UBDocumentProxy.h" diff --git a/src/core/core.pri b/src/core/core.pri index 293e143e6..5732e8bdf 100644 --- a/src/core/core.pri +++ b/src/core/core.pri @@ -15,8 +15,7 @@ HEADERS += src/core/UB.h \ src/core/UBDownloadManager.h \ src/core/UBDownloadThread.h \ src/core/UBTextTools.h \ - src/core/UBPersistenceWorker.h \ - $$PWD/UBForeignObjectsHandler.h + src/core/UBPersistenceWorker.h SOURCES += src/core/main.cpp \ src/core/UBShortcutManager.cpp \ @@ -34,5 +33,4 @@ SOURCES += src/core/main.cpp \ src/core/UBDownloadManager.cpp \ src/core/UBDownloadThread.cpp \ src/core/UBTextTools.cpp \ - src/core/UBPersistenceWorker.cpp \ - $$PWD/UBForeignObjectsHandler.cpp + src/core/UBPersistenceWorker.cpp From 01ddb53d228ff939c1c1bbb2e66d1ee7dbf55de6 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Thu, 13 Mar 2025 16:38:46 +0100 Subject: [PATCH 011/133] drop: CFF support - drop CFF import support - drop CFF export support (was already disabled) Signed-off-by: letsfindaway --- CMakeLists.txt | 1 - OpenBoard.pro | 4 - plugins/cffadaptor/UBCFFAdaptor.pro | 69 - plugins/cffadaptor/postScript_mac.sh | 5 - .../cffadaptor/resources/images/soundOn.svg | 9 - plugins/cffadaptor/resources/resources.qrc | 5 - plugins/cffadaptor/src/CMakeLists.txt | 7 - plugins/cffadaptor/src/UBCFFAdaptor.cpp | 2081 ----------------- plugins/cffadaptor/src/UBCFFAdaptor.h | 180 -- plugins/cffadaptor/src/UBCFFAdaptor_global.h | 34 - plugins/cffadaptor/src/UBCFFConstants.h | 397 ---- plugins/cffadaptor/src/UBGlobals.h | 74 - plugins/plugins.pri | 6 - src/adaptors/CMakeLists.txt | 6 - src/adaptors/UBCFFSubsetAdaptor.cpp | 1570 ------------- src/adaptors/UBCFFSubsetAdaptor.h | 158 -- src/adaptors/UBExportCFF.cpp | 104 - src/adaptors/UBExportCFF.h | 53 - src/adaptors/UBImportCFF.cpp | 302 --- src/adaptors/UBImportCFF.h | 55 - src/adaptors/adaptors.pri | 10 +- src/core/UBDocumentManager.cpp | 6 - 22 files changed, 2 insertions(+), 5134 deletions(-) delete mode 100644 plugins/cffadaptor/UBCFFAdaptor.pro delete mode 100644 plugins/cffadaptor/postScript_mac.sh delete mode 100644 plugins/cffadaptor/resources/images/soundOn.svg delete mode 100644 plugins/cffadaptor/resources/resources.qrc delete mode 100644 plugins/cffadaptor/src/CMakeLists.txt delete mode 100644 plugins/cffadaptor/src/UBCFFAdaptor.cpp delete mode 100644 plugins/cffadaptor/src/UBCFFAdaptor.h delete mode 100644 plugins/cffadaptor/src/UBCFFAdaptor_global.h delete mode 100644 plugins/cffadaptor/src/UBCFFConstants.h delete mode 100644 plugins/cffadaptor/src/UBGlobals.h delete mode 100644 plugins/plugins.pri delete mode 100644 src/adaptors/UBCFFSubsetAdaptor.cpp delete mode 100644 src/adaptors/UBCFFSubsetAdaptor.h delete mode 100644 src/adaptors/UBExportCFF.cpp delete mode 100644 src/adaptors/UBExportCFF.h delete mode 100644 src/adaptors/UBImportCFF.cpp delete mode 100644 src/adaptors/UBImportCFF.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 33a5599b2..b32a8d84f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,7 +139,6 @@ add_subdirectory(src/podcast) add_subdirectory(src/singleapplication) add_subdirectory(src/tools) add_subdirectory(src/web) -add_subdirectory(plugins/cffadaptor/src) add_subdirectory(resources/forms) # statically link singleapplication diff --git a/OpenBoard.pro b/OpenBoard.pro index 17fb4e75a..d36986f19 100644 --- a/OpenBoard.pro +++ b/OpenBoard.pro @@ -66,10 +66,6 @@ DEPENDPATH += src/pdf-merger INCLUDEPATH += src/pdf-merger include(src/pdf-merger/pdfMerger.pri) -#plugins -include(plugins/plugins.pri) -INCLUDEPATH += plugins/cffadaptor/src - FORMS += resources/forms/mainWindow.ui \ resources/forms/preferences.ui \ resources/forms/brushProperties.ui \ diff --git a/plugins/cffadaptor/UBCFFAdaptor.pro b/plugins/cffadaptor/UBCFFAdaptor.pro deleted file mode 100644 index f8214d5de..000000000 --- a/plugins/cffadaptor/UBCFFAdaptor.pro +++ /dev/null @@ -1,69 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2012-02-14T13:30:14 -# -#------------------------------------------------- - -TARGET = CFF_Adaptor -TEMPLATE = lib - -win32: SUB_DIR = win32 -macx: SUB_DIR = macx -linux-g++: SUB_DIR = linux -linux-g++-32: SUB_DIR = linux -linux-g++-64: SUB_DIR = linux - -THIRD_PARTY_PATH = ../../../Sankore-ThirdParty -QUAZIP_DIR = "$$PWD/../../../Sankore-ThirdParty/quazip/quazip-0.3" - -BUILD_DIR = build/$$SUB_DIR -CONFIG(debug, debug|release):BUILD_DIR = $$BUILD_DIR/debug -CONFIG(release, debug|release) { - BUILD_DIR = $$BUILD_DIR/release - CONFIG += warn_off -} - -win32{ - CONFIG += dll -} - -OBJECTS_DIR = $$BUILD_DIR/objects -MOC_DIR = $$BUILD_DIR/moc -DESTDIR = $$BUILD_DIR/lib -RCC_DIR = $$BUILD_DIR/rcc -SANKORE_DIR = ../.. -win32:{ - QMAKE_POST_LINK += copy $$replace(DESTDIR,/,\\)\\CFF_Adaptor.dll" $$replace(SANKORE_DIR,/,\\)\\CFF_Adaptor.dll /y" -} -macx:{ - QMAKE_POST_LINK += bash postScript_mac.sh "$$DESTDIR" "$$SANKORE_DIR/$$BUILD_DIR/product/Open-Sankore.app/Contents/MacOS" -} - -LIBS += "-L$$THIRD_PARTY_PATH/quazip/lib/$$SUB_DIR" "-lquazip" - -QT += xml xmlpatterns core -QT += gui -QT += svg - - -DEFINES += UBCFFADAPTOR_LIBRARY -DEFINES += NO_THIRD_PARTY_WARNINGS - -INCLUDEPATH += src - -DEPENDPATH += $$THIRD_PARTY_PATH/quazip/ -INCLUDEPATH += $$THIRD_PARTY_PATH/quazip/ -include($$THIRD_PARTY_PATH/quazip/quazip.pri) - - -SOURCES += \ - src/UBCFFAdaptor.cpp - -HEADERS +=\ - $$PWD/../../src/globals/UBGlobals.h \ - src/UBCFFAdaptor.h \ - src/UBCFFAdaptor_global.h \ - src/UBCFFConstants.h - -RESOURCES += \ - resources/resources.qrc \ No newline at end of file diff --git a/plugins/cffadaptor/postScript_mac.sh b/plugins/cffadaptor/postScript_mac.sh deleted file mode 100644 index dfe0fb639..000000000 --- a/plugins/cffadaptor/postScript_mac.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -SOURCE=$1 -DESTINATION=$2 -mkdir -p $DESTINATION -cp -R $SOURCE/ $DESTINATION \ No newline at end of file diff --git a/plugins/cffadaptor/resources/images/soundOn.svg b/plugins/cffadaptor/resources/images/soundOn.svg deleted file mode 100644 index 79d27706f..000000000 --- a/plugins/cffadaptor/resources/images/soundOn.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - diff --git a/plugins/cffadaptor/resources/resources.qrc b/plugins/cffadaptor/resources/resources.qrc deleted file mode 100644 index 0a4ec4710..000000000 --- a/plugins/cffadaptor/resources/resources.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - images/soundOn.svg - - diff --git a/plugins/cffadaptor/src/CMakeLists.txt b/plugins/cffadaptor/src/CMakeLists.txt deleted file mode 100644 index 6109d8fb2..000000000 --- a/plugins/cffadaptor/src/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -target_sources(openboard PRIVATE - UBCFFAdaptor.cpp -) - -target_include_directories(${PROJECT_NAME} PRIVATE - . -) diff --git a/plugins/cffadaptor/src/UBCFFAdaptor.cpp b/plugins/cffadaptor/src/UBCFFAdaptor.cpp deleted file mode 100644 index 8363e4963..000000000 --- a/plugins/cffadaptor/src/UBCFFAdaptor.cpp +++ /dev/null @@ -1,2081 +0,0 @@ -/* - * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) - * - * Copyright (C) 2013 Open Education Foundation - * - * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour - * l'Education Numérique en Afrique (GIP ENA) - * - * This file is part of OpenBoard. - * - * OpenBoard is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License, - * with a specific linking exception for the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the - * same license as the "OpenSSL" library). - * - * OpenBoard is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with OpenBoard. If not, see . - */ - - - - -#include "UBCFFAdaptor.h" - -#include -#include -#include -#include -#include -#include - -#include "UBCFFConstants.h" -#include "core/UB.h" - -//THIRD_PARTY_WARNINGS_DISABLE -#ifdef Q_OS_OSX - #include - #include - #include -#else - #include "quazip.h" - #include "quazipfile.h" - #include "quazipfileinfo.h" -#endif -//THIRD_PARTY_WARNINGS_ENABLE - - -UBCFFAdaptor::UBCFFAdaptor() -{} - -bool UBCFFAdaptor::convertUBZToIWB(const QString &from, const QString &to) -{ - qDebug() << "starting conversion from" << from << "to" << to; - - QString source = QString(); - if (QFileInfo(from).isDir() && QFile::exists(from)) { - qDebug() << "File specified is a directory, continuing conversion"; - source = from; - } else { - source = uncompressZip(from); - if (!source.isNull()) qDebug() << "File specified is a zip file. Uncompressed to tmp dir, continuing conversion"; - } - if (source.isNull()) { - qDebug() << "File specified is not a dir nor a zip file, stopping conversion"; - return false; - } - - QString tmpDestination = createNewTmpDir(); - if (tmpDestination.isNull()) { - qDebug() << "can't create temp destination folder. Stopping parsing..."; - return false; - } - - UBToCFFConverter tmpConvertrer(source, tmpDestination); - if (!tmpConvertrer) { - qDebug() << "The converter class is invalid, stopping conversion. Error message" << tmpConvertrer.lastErrStr(); - return false; - } - - bool bParceRes = tmpConvertrer.parse(); - - mConversionMessages << tmpConvertrer.getMessages(); - - if (!bParceRes) { - return false; - } - - if (!compressZip(tmpDestination, to)) - qDebug() << "error in compression"; - - //Cleanning tmp souces in filesystem - if (!QFileInfo(from).isDir()) - if (!freeDir(source)) - qDebug() << "can't delete tmp directory" << QDir(source).absolutePath() << "try to delete them manually"; - - if (!freeDir(tmpDestination)) - qDebug() << "can't delete tmp directory" << QDir(tmpDestination).absolutePath() << "try to delete them manually"; - - return true; -} - -QString UBCFFAdaptor::uncompressZip(const QString &zipFile) -{ - QuaZip zip(zipFile); - - if(!zip.open(QuaZip::mdUnzip)) { - qWarning() << "Import failed. Cause zip.open(): " << zip.getZipError(); - return QString(); - } - - zip.setFileNameCodec("UTF-8"); - QuaZipFileInfo info; - QuaZipFile file(&zip); - - //create unique cff document root fodler - QString documentRootFolder = createNewTmpDir(); - - if (documentRootFolder.isNull()) { - qDebug() << "can't create tmp directory for zip file" << zipFile; - return QString(); - } - - QDir rootDir(documentRootFolder); - QFile out; - char c; - bool allOk = true; - for(bool more = zip.goToFirstFile(); more; more=zip.goToNextFile()) { - if(!zip.getCurrentFileInfo(&info)) { - qWarning() << "Import failed. Cause: getCurrentFileInfo(): " << zip.getZipError(); - allOk = false; - break; - } - if(!file.open(QIODevice::ReadOnly)) { - allOk = false; - break; - } - if(file.getZipError()!= UNZ_OK) { - qWarning() << "Import failed. Cause: file.getFileName(): " << zip.getZipError(); - allOk = false; - break; - } - - QString newFileName = documentRootFolder + "/" + file.getActualFileName(); - - QFileInfo newFileInfo(newFileName); - rootDir.mkpath(newFileInfo.absolutePath()); - - out.setFileName(newFileName); - out.open(QIODevice::WriteOnly); - - while(file.getChar(&c)) - out.putChar(c); - - out.close(); - - if(file.getZipError()!=UNZ_OK) { - qWarning() << "Import failed. Cause: " << zip.getZipError(); - allOk = false; - break; - } - if(!file.atEnd()) { - qWarning() << "Import failed. Cause: read all but not EOF"; - allOk = false; - break; - } - file.close(); - - if(file.getZipError()!=UNZ_OK) { - qWarning() << "Import failed. Cause: file.close(): " << file.getZipError(); - allOk = false; - break; - } - } - - if (!allOk) { - out.close(); - file.close(); - zip.close(); - return QString(); - } - - if(zip.getZipError()!=UNZ_OK) { - qWarning() << "Import failed. Cause: zip.close(): " << zip.getZipError(); - return QString(); - } - - return documentRootFolder; -} - -bool UBCFFAdaptor::compressZip(const QString &source, const QString &destination) -{ - QDir toDir = QFileInfo(destination).dir(); - if (!toDir.exists()) - if (!QDir().mkpath(toDir.absolutePath())) { - qDebug() << "Can't create destination folder to uncompress file"; - return false; - } - - QuaZip zip(destination); - zip.setFileNameCodec("UTF-8"); - if(!zip.open(QuaZip::mdCreate)) { - qDebug("Export failed. Cause: zip.open(): %d", zip.getZipError()); - return false; - } - - QuaZipFile outZip(&zip); - - QFileInfo sourceInfo(source); - if (sourceInfo.isDir()) { - if (!compressDir(QFileInfo(source).absoluteFilePath(), "", &outZip)) - return false; - } else if (sourceInfo.isFile()) { - if (!compressFile(QFileInfo(source).absoluteFilePath(), "", &outZip)) - return false; - } - - return true; -} - -bool UBCFFAdaptor::compressDir(const QString &dirName, const QString &parentDir, QuaZipFile *outZip) -{ - QFileInfoList dirFiles = QDir(dirName).entryInfoList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); - QListIterator iter(dirFiles); - while (iter.hasNext()) { - QFileInfo curFile = iter.next(); - - if (curFile.isDir()) { - if (!compressDir(curFile.absoluteFilePath(), parentDir + curFile.fileName() + "/", outZip)) { - qDebug() << "Error at compressing dir" << curFile.absoluteFilePath(); - return false; - } - } else if (curFile.isFile()) { - if (!compressFile(curFile.absoluteFilePath(), parentDir, outZip)) { - return false; - } - } - } - - return true; -} - -bool UBCFFAdaptor::compressFile(const QString &fileName, const QString &parentDir, QuaZipFile *outZip) -{ - QFile sourceFile(fileName); - - if(!sourceFile.open(QIODevice::ReadOnly)) { - qDebug() << "Compression of file" << sourceFile.fileName() << " failed. Cause: inFile.open(): " << sourceFile.errorString(); - return false; - } - - if(!outZip->open(QIODevice::WriteOnly, QuaZipNewInfo(parentDir + QFileInfo(fileName).fileName(), sourceFile.fileName()))) { - qDebug() << "Compression of file" << sourceFile.fileName() << " failed. Cause: outFile.open(): " << outZip->getZipError(); - sourceFile.close(); - return false; - } - - outZip->write(sourceFile.readAll()); - if(outZip->getZipError() != UNZ_OK) { - qDebug() << "Compression of file" << sourceFile.fileName() << " failed. Cause: outFile.write(): " << outZip->getZipError(); - - sourceFile.close(); - outZip->close(); - return false; - } - - if(outZip->getZipError() != UNZ_OK) - { - qWarning() << "Compression of file" << sourceFile.fileName() << " failed. Cause: outFile.close(): " << outZip->getZipError(); - - sourceFile.close(); - outZip->close(); - return false; - } - - outZip->close(); - sourceFile.close(); - - return true; -} - -QString UBCFFAdaptor::createNewTmpDir() -{ - int tmpNumber = 0; - QDir systemTmp = QDir::temp(); - - while (true) { - QString dirName = QString("CFF_adaptor_filedata_store%1.%2") - .arg(QDateTime::currentDateTime().toString("dd_MM_yyyy_HH-mm")) - .arg(tmpNumber++); - if (!systemTmp.exists(dirName)) { - if (systemTmp.mkdir(dirName)) { - QString result = systemTmp.absolutePath() + "/" + dirName; - tmpDirs.append(result); - return result; - } else { - qDebug() << "Can't create temporary directory maybe due to permissions"; - return QString(); - } - } else if (tmpNumber == 10) { - qWarning() << "Import failed. Failed to create temporary file "; - return QString(); - } - tmpNumber++; - } - - return QString(); -} -bool UBCFFAdaptor::deleteDir(const QString& pDirPath) const -{ - if (pDirPath == "" || pDirPath == "." || pDirPath == "..") - return false; - - QDir dir(pDirPath); - - if (dir.exists()) - { - foreach(QFileInfo dirContent, dir.entryInfoList(QDir::Files | QDir::Dirs - | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::Name)) - { - if (dirContent.isDir()) - { - deleteDir(dirContent.absoluteFilePath()); - } - else - { - if (!dirContent.dir().remove(dirContent.fileName())) - { - return false; - } - } - } - } - - return dir.rmdir(pDirPath); -} - -QList UBCFFAdaptor::getConversionMessages() -{ - return mConversionMessages; -} - -bool UBCFFAdaptor::freeDir(const QString &dir) -{ - bool result = true; - if (!deleteDir(dir)) - result = false; - - tmpDirs.removeAll(QDir(dir).absolutePath()); - - return result; -} -void UBCFFAdaptor::freeTmpDirs() -{ - foreach (QString dir, tmpDirs) - freeDir(dir); -} - -UBCFFAdaptor::~UBCFFAdaptor() -{ - freeTmpDirs(); -} - -UBCFFAdaptor::UBToCFFConverter::UBToCFFConverter(const QString &source, const QString &destination) -{ - sourcePath = source; - destinationPath = destination; - - errorStr = noErrorMsg; - mDataModel = new QDomDocument; - mDocumentToWrite = new QDomDocument; - mDocumentToWrite->setContent(QString("")); - - mIWBContentWriter = new QXmlStreamWriter; - mIWBContentWriter->setAutoFormatting(true); - - iwbSVGItemsAttributes.insert(tIWBImage, iwbSVGImageAttributes); - iwbSVGItemsAttributes.insert(tIWBVideo, iwbSVGVideoAttributes); - iwbSVGItemsAttributes.insert(tIWBText, iwbSVGTextAttributes); - iwbSVGItemsAttributes.insert(tIWBTextArea, iwbSVGTextAreaAttributes); - iwbSVGItemsAttributes.insert(tIWBPolyLine, iwbSVGPolyLineAttributes); - iwbSVGItemsAttributes.insert(tIWBPolygon, iwbSVGPolygonAttributes); - iwbSVGItemsAttributes.insert(tIWBRect, iwbSVGRectAttributes); - iwbSVGItemsAttributes.insert(tIWBLine, iwbSVGLineAttributes); - iwbSVGItemsAttributes.insert(tIWBTspan, iwbSVGTspanAttributes); -} - -bool UBCFFAdaptor::UBToCFFConverter::parse() -{ - if(!isValid()) { - qDebug() << "document metadata is not valid. Can't parse"; - return false; - } - - qDebug() << "begin parsing ubz"; - - QFile outFile(contentIWBFileName()); - if (!outFile.open(QIODevice::WriteOnly| QIODevice::Text)) { - qDebug() << "can't open output file for writing"; - errorStr = "createXMLOutputPatternError"; - return false; - } - - mIWBContentWriter->setDevice(&outFile); - - mIWBContentWriter->writeStartDocument(); - mIWBContentWriter->writeStartElement(tIWBRoot); - - fillNamespaces(); - - mIWBContentWriter->writeAttribute(aIWBVersion, avIWBVersionNo); - - if (!parseMetadata()) { - if (errorStr == noErrorMsg) - errorStr = "MetadataParsingError"; - - outFile.close(); - return false; - } - - if (!parseContent()) { - if (errorStr == noErrorMsg) - errorStr = "ContentParsingError"; - outFile.close(); - return false; - } - - mIWBContentWriter->writeEndElement(); - mIWBContentWriter->writeEndDocument(); - - outFile.close(); - - qDebug() << "finished with success"; - - return true; -} -bool UBCFFAdaptor::UBToCFFConverter::parseMetadata() -{ - int errorLine, errorColumn; - QFile metaDataFile(sourcePath + "/" + fMetadata); - - if (!metaDataFile.open(QIODevice::ReadOnly | QIODevice::Text)) { - errorStr = "can't open" + QFileInfo(sourcePath + "/" + fMetadata).absoluteFilePath(); - qDebug() << errorStr; - return false; - - } else if (!mDataModel->setContent(metaDataFile.readAll(), true, &errorStr, &errorLine, &errorColumn)) { - qWarning() << "Error:Parseerroratline" << errorLine << "," - << "column" << errorColumn << ":" << errorStr; - return false; - } - - QDomElement nextInElement = mDataModel->documentElement(); - - nextInElement = nextInElement.firstChildElement(tDescription); - if (!nextInElement.isNull()) { - - mIWBContentWriter->writeStartElement(iwbNS, tIWBMeta); - mIWBContentWriter->writeAttribute(aIWBName, aCreator); - mIWBContentWriter->writeAttribute(aIWBContent, avCreator); - mIWBContentWriter->writeEndElement(); - - mIWBContentWriter->writeStartElement(iwbNS, tIWBMeta); - mIWBContentWriter->writeAttribute(aIWBName, aOwner); - mIWBContentWriter->writeAttribute(aIWBContent, avOwner); - mIWBContentWriter->writeEndElement(); - - mIWBContentWriter->writeStartElement(iwbNS, tIWBMeta); - mIWBContentWriter->writeAttribute(aIWBName, aDescription); - mIWBContentWriter->writeAttribute(aIWBContent, avDescription); - mIWBContentWriter->writeEndElement(); - - mIWBContentWriter->writeStartElement(iwbNS, tIWBMeta); - mIWBContentWriter->writeAttribute(aIWBName, aAbout); - mIWBContentWriter->writeAttribute(aIWBContent, nextInElement.attribute(aAbout)); - mIWBContentWriter->writeEndElement(); - - nextInElement = nextInElement.firstChildElement(); - while (!nextInElement.isNull()) { - - QString textContent = nextInElement.text(); - if (!textContent.trimmed().isEmpty()) { - if (nextInElement.tagName() == tUBZSize) { //taking main viewbox rect since for CFF specificaton we have static viewbox - QSize tmpSize = getSVGDimentions(nextInElement.text()); - if (!tmpSize.isNull()) { - mSVGSize = tmpSize; - } else { - qDebug() << "can't interpret svg section size"; - errorStr = "InterpretSvgSizeError"; - return false; - } - } else { - mIWBContentWriter->writeStartElement(iwbNS, tIWBMeta); - mIWBContentWriter->writeAttribute(aIWBName, nextInElement.tagName()); - mIWBContentWriter->writeAttribute(aIWBContent, textContent); - mIWBContentWriter->writeEndElement(); - } - - } - nextInElement = nextInElement.nextSiblingElement(); - } - } - - metaDataFile.close(); - return true; -} -bool UBCFFAdaptor::UBToCFFConverter::parseContent() { - - QDir sourceDir(sourcePath); - QStringList fileFilters; - fileFilters << QString(pageAlias + "???." + pageFileExtentionUBZ); - QStringList pageList = sourceDir.entryList(fileFilters, QDir::Files, QDir::Name | QDir::IgnoreCase); - - QDomElement svgDocumentSection = mDataModel->createElementNS(svgIWBNS, ":"+tSvg); - - if (!pageList.count()) { - qDebug() << "can't find any content file"; - errorStr = "ErrorContentFile"; - return false; - } else - { - QDomElement pageset = parsePageset(pageList); - if (pageset.isNull()) - return false; - else - svgDocumentSection.appendChild(pageset); - } - - - if (QRect() == mViewbox) - { - mViewbox.setRect(0,0, mSVGSize.width(), mSVGSize.height()); - } - - svgDocumentSection.setAttribute(aIWBViewBox, rectToIWBAttr(mViewbox)); - svgDocumentSection.setAttribute(aWidth, QString("%1").arg(mViewbox.width())); - svgDocumentSection.setAttribute(aHeight, QString("%1").arg(mViewbox.height())); - - - writeQDomElementToXML(svgDocumentSection); - - - if (!writeExtendedIwbSection()) { - if (errorStr == noErrorMsg) - errorStr = "writeExtendedIwbSectionError"; - return false; - } - - return true; -} - -QDomElement UBCFFAdaptor::UBToCFFConverter::parsePage(const QString &pageFileName) -{ - qDebug() << "begin parsing page" + pageFileName; - mSvgElements.clear(); //clean Svg elements map before parsing new page - - int errorLine, errorColumn; - - QFile pageFile(sourcePath + "/" + pageFileName); - if (!pageFile.open(QIODevice::ReadOnly | QIODevice::Text)) { - qDebug() << "can't open file" << pageFileName << "for reading"; - return QDomElement(); - } else if (!mDataModel->setContent(pageFile.readAll(), true, &errorStr, &errorLine, &errorColumn)) { - qWarning() << "Error:Parseerroratline" << errorLine << "," - << "column" << errorColumn << ":" << errorStr; - pageFile.close(); - return QDomElement(); - } - - QDomElement page; - QDomElement group; - - QDomElement nextTopElement = mDataModel->firstChildElement(); - while (!nextTopElement.isNull()) { - QString tagname = nextTopElement.tagName(); - if (tagname == tSvg) { - page = parseSvgPageSection(nextTopElement); - if (page.isNull()) { - qDebug() << "The page is empty."; - pageFile.close(); - return QDomElement(); - } - } else if (tagname == tUBZGroups) { - group = parseGroupsPageSection(nextTopElement); - if (group.isNull()) { - qDebug() << "Page doesn't contains any groups."; - pageFile.close(); - return QDomElement(); - } - } - - nextTopElement = nextTopElement.nextSiblingElement(); - } - - pageFile.close(); - - return page.hasChildNodes() ? page : QDomElement(); -} - -QDomElement UBCFFAdaptor::UBToCFFConverter::parsePageset(const QStringList &pageFileNames) -{ - QMultiMap pageList; - int iPageNo = 1; - - QStringListIterator curPage(pageFileNames); - - while (curPage.hasNext()) { - - QString curPageFile = curPage.next(); - QDomElement iterElement = parsePage(curPageFile); - if (!iterElement.isNull()) - { - iterElement.setAttribute(tId, iPageNo); - addSVGElementToResultModel(iterElement, pageList, iPageNo); - iPageNo++; - } - else - return QDomElement(); - } - - - if (!pageList.count()) - return QDomElement(); - - - QDomElement svgPagesetElement = mDocumentToWrite->createElementNS(svgIWBNS,":"+ tIWBPageSet); - - for (const auto &value : std::as_const(pageList)) { - svgPagesetElement.appendChild(value); - } - - return svgPagesetElement.hasChildNodes() ? svgPagesetElement : QDomElement(); -} -QDomElement UBCFFAdaptor::UBToCFFConverter::parseSvgPageSection(const QDomElement &element) -{ - //we don't know about page number, so return QDomElement. - - //Parsing top level tag attributes - - //getting current page viewbox to be able to convert coordinates to global viewbox parameter - if (element.hasAttribute(aUBZViewBox)) { - setViewBox(getViewboxRect(element.attribute(aUBZViewBox))); - } - - QMultiMap svgElements; - - QDomElement svgElementPart = mDocumentToWrite->createElementNS(svgIWBNS,":"+ tIWBPage); - - if (element.hasAttribute(aDarkBackground)) { - createBackground(element, svgElements); - } - - //Parsing svg children attributes - // Elements can know about its layer, so it must add result QDomElements to ordrered list. - QDomElement nextElement = element.firstChildElement(); - while (!nextElement.isNull()) { - QString tagName = nextElement.tagName(); - if (tagName == tUBZG) parseSVGGGroup(nextElement, svgElements); - else if (tagName == tUBZImage) parseUBZImage(nextElement, svgElements); - else if (tagName == tUBZVideo) parseUBZVideo(nextElement, svgElements); - else if (tagName == tUBZAudio) parseUBZAudio(nextElement, svgElements); - else if (tagName == tUBZForeignObject) parseForeignObject(nextElement, svgElements); - else if (tagName == tUBZLine) parseUBZLine(nextElement, svgElements); - else if (tagName == tUBZPolygon) parseUBZPolygon(nextElement, svgElements); - else if (tagName == tUBZPolyline) parseUBZPolyline(nextElement, svgElements); - else if (tagName == tUBZGroups) parseGroupsPageSection(nextElement); - - nextElement = nextElement.nextSiblingElement(); - } - - if (0 == svgElements.count()) - return QDomElement(); - - // to do: - // there we must to sort elements (take elements from list and assign parent ordered like in parseSVGGGroup) - // we returns just element because we don't care about layer. - for (const auto &value : std::as_const(svgElements)) { - svgElementPart.appendChild(value); - } - - return svgElementPart.hasChildNodes() ? svgElementPart : QDomElement(); -} - -void UBCFFAdaptor::UBToCFFConverter::writeQDomElementToXML(const QDomNode &node) -{ - if (!node.isNull()) { - if (node.isText()) - mIWBContentWriter->writeCharacters(node.nodeValue()); - else { - mIWBContentWriter->writeStartElement(node.namespaceURI(), node.toElement().tagName()); - - for (int i = 0; i < node.toElement().attributes().count(); i++) { - QDomAttr attr = node.toElement().attributes().item(i).toAttr(); - mIWBContentWriter->writeAttribute(attr.name(), attr.value()); - } - QDomNode child = node.firstChild(); - while(!child.isNull()) { - writeQDomElementToXML(child); - child = child.nextSibling(); - } - - mIWBContentWriter->writeEndElement(); - } - } -} - -bool UBCFFAdaptor::UBToCFFConverter::writeExtendedIwbSection() -{ - if (!mExtendedElements.count()) { - qDebug() << "extended iwb content list is empty"; - errorStr = "EmptyExtendedIwbSectionContentError"; - return false; - } - QListIterator nextExtendedIwbElement(mExtendedElements); - while (nextExtendedIwbElement.hasNext()) { - writeQDomElementToXML(nextExtendedIwbElement.next()); - //TODO write iwb extended element to mIWBContentWriter - } - - return true; -} - -// extended element options -// editable, background, locked are supported for now - -QDomElement UBCFFAdaptor::UBToCFFConverter::parseGroupsPageSection(const QDomElement &groupRoot) -{ -// First sankore side implementation needed. TODO in Sankore 1.5 - if (!groupRoot.hasChildNodes()) { - qDebug() << "Group root is empty"; - return QDomElement(); - } - - QDomElement groupElement = groupRoot.firstChildElement(); - - while (!groupElement.isNull()) { - QDomElement extendedElement = mDataModel->createElementNS(iwbNS, groupElement.tagName()); - QDomElement groupChildElement = groupElement.firstChildElement(); - while (!groupChildElement.isNull()) { - QDomElement extSubElement = mDataModel->createElementNS(iwbNS, groupChildElement.tagName()); - extSubElement.setAttribute(aRef, groupChildElement.attribute(aID, QUuid().toString())); - extendedElement.appendChild(extSubElement); - - groupChildElement = groupChildElement.nextSiblingElement(); - } - - mExtendedElements.append(extendedElement); - - groupElement = groupElement.nextSiblingElement(); - } - - qDebug() << "parsing ubz group section"; - return groupRoot; -} - -QString UBCFFAdaptor::UBToCFFConverter::getDstContentFolderName(const QString &elementType) -{ - QString sRet; - QString sDstContentFolderName; - - // widgets must be saved as .png images. - if ((tIWBImage == elementType) || (tUBZForeignObject == elementType)) - sDstContentFolderName = cfImages; - else - if (tIWBVideo == elementType) - sDstContentFolderName = cfVideos; - else - if (tIWBAudio == elementType) - sDstContentFolderName = cfAudios; - - sRet = sDstContentFolderName; - - return sRet; -} - -QString UBCFFAdaptor::UBToCFFConverter::getSrcContentFolderName(QString href) -{ - QString sRet; - - QStringList ls = href.split("/"); - for (int i = 0; i < ls.count()-1; i++) - { - QString sPart = ls.at(i); - if (ubzContentFolders.contains(sPart)) - { - sRet = sPart; - } - } - -// if (0 < ls.count()) -// sRet = ls.at(ls.count()-1); -// -// sRet = href.remove(sRet); -// -// if (sRet.endsWith("/")) -// sRet.remove("/"); - - return sRet; -} - -QString UBCFFAdaptor::UBToCFFConverter::getFileNameFromPath(const QString sPath) -{ - QString sRet; - QStringList sl = sPath.split("/",UB::SplitBehavior::SkipEmptyParts); - - if (0 < sl.count()) - { - QString name = sl.at(sl.count()-1); - QString extention = getExtentionFromFileName(name); - - if (feWgt == extention) - { - name.remove("{"); - name.remove("}"); - } - - name.remove(name.length()-extention.length(), extention.length()); - name += convertExtention(extention); - - sRet = name; - } - return sRet; -} - -QString UBCFFAdaptor::UBToCFFConverter::getExtentionFromFileName(const QString &filename) -{ - QStringList sl = filename.split("/",UB::SplitBehavior::SkipEmptyParts); - - if (0 < sl.count()) - { - QString name = sl.at(sl.count()-1); - QStringList tl = name.split("."); - return tl.at(tl.count()-1); - } - return QString(); -} - -QString UBCFFAdaptor::UBToCFFConverter::convertExtention(const QString &ext) -{ - QString sRet; - - if (feSvg == ext) - sRet = fePng; - else - if (feWgt == ext) - sRet = fePng; - else - sRet = ext; - - return sRet; -} - -QString UBCFFAdaptor::UBToCFFConverter::getElementTypeFromUBZ(const QDomElement &element) -{ - QString sRet; - if (tUBZForeignObject == element.tagName()) - { - QString sPath; - if (element.hasAttribute(aUBZType)) - { - if (avUBZText == element.attribute(aUBZType)) - sRet = tIWBTextArea; - else - sRet = element.attribute(aUBZType); - } - else - { - if (element.hasAttribute(aSrc)) - sPath = element.attribute(aSrc); - else - if (element.hasAttribute(aUBZHref)) - sPath = element.attribute(aUBZHref); - - QStringList tsl = sPath.split(".", UB::SplitBehavior::SkipEmptyParts); - if (0 < tsl.count()) - { - QString elementType = tsl.at(tsl.count()-1); - if (iwbElementImage.contains(elementType)) - sRet = tIWBImage; - else - if (iwbElementAudio.contains(elementType)) - sRet = tIWBAudio; - else - if (iwbElementVideo.contains(elementType)) - sRet = tIWBVideo; - } - } - } - else - sRet = element.tagName(); - - return sRet; -} - -int UBCFFAdaptor::UBToCFFConverter::getElementLayer(const QDomElement &element) -{ - int iRetLayer = 0; - if (element.hasAttribute(aZLayer)) - iRetLayer = (int)element.attribute(aZLayer).toDouble(); - else - iRetLayer = DEFAULT_LAYER; - - return iRetLayer; -} - -bool UBCFFAdaptor::UBToCFFConverter::itIsSupportedFormat(const QString &format) const -{ - bool bRet; - - QStringList tsl = format.split(".", UB::SplitBehavior::SkipEmptyParts); - if (0 < tsl.count()) - bRet = cffSupportedFileFormats.contains(tsl.at(tsl.count()-1).toLower()); - else - bRet = false; - - return bRet; -} - -bool UBCFFAdaptor::UBToCFFConverter::itIsFormatToConvert(const QString &format) const -{ - foreach (QString f, ubzFormatsToConvert.split(",")) - { - if (format == f) - return true; - } - return false; -} - -bool UBCFFAdaptor::UBToCFFConverter::itIsSVGElementAttribute(const QString ItemType, const QString &AttrName) -{ - QString allowedElementAttributes = iwbSVGItemsAttributes[ItemType]; - - allowedElementAttributes.remove("/t"); - allowedElementAttributes.remove(" "); - foreach(QString attr, allowedElementAttributes.split(",")) - { - if (AttrName == attr.trimmed()) - return true; - } - return false; -} - - -bool UBCFFAdaptor::UBToCFFConverter::itIsIWBAttribute(const QString &attribute) const -{ - foreach (QString attr, iwbElementAttributes.split(",")) - { - if (attribute == attr.trimmed()) - return true; - } - return false; -} - -bool UBCFFAdaptor::UBToCFFConverter::itIsUBZAttributeToConvert(const QString &attribute) const -{ - foreach (QString attr, ubzElementAttributesToConvert.split(",")) - { - if (attribute == attr.trimmed()) - return true; - } - return false; -} - -bool UBCFFAdaptor::UBToCFFConverter::ibwAddLine(int x1, int y1, int x2, int y2, QString color, int width, bool isBackground) -{ - bool bRet = true; - - QDomDocument doc; - - QDomElement svgBackgroundCrossPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":line"); - QDomElement iwbBackgroundCrossPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement); - - QString sUUID = QUuid::createUuid().toString(); - - svgBackgroundCrossPart.setTagName(tIWBLine); - - svgBackgroundCrossPart.setAttribute(aX+"1", x1); - svgBackgroundCrossPart.setAttribute(aY+"1", y1); - svgBackgroundCrossPart.setAttribute(aX+"2", x2); - svgBackgroundCrossPart.setAttribute(aY+"2", y2); - - svgBackgroundCrossPart.setAttribute(aStroke, color); - svgBackgroundCrossPart.setAttribute(aStrokeWidth, width); - - svgBackgroundCrossPart.setAttribute(aID, sUUID); - - if (isBackground) - { - iwbBackgroundCrossPart.setAttribute(aRef, sUUID); - iwbBackgroundCrossPart.setAttribute(aLocked, avTrue); - - addIWBElementToResultModel(iwbBackgroundCrossPart); - } - - addSVGElementToResultModel(svgBackgroundCrossPart, mSvgElements, DEFAULT_BACKGROUND_CROSS_LAYER); - - if (!bRet) - { - qDebug() << "|error at creating crosses on background"; - errorStr = "CreatingCrossedBackgroundParsingError."; - } - - return bRet; -} - -QTransform UBCFFAdaptor::UBToCFFConverter::getTransformFromUBZ(const QDomElement &ubzElement) -{ - QTransform trRet; - - QStringList transformParameters; - - QString ubzTransform = ubzElement.attribute(aTransform); - ubzTransform.remove("matrix"); - ubzTransform.remove("("); - ubzTransform.remove(")"); - - transformParameters = ubzTransform.split(",", UB::SplitBehavior::SkipEmptyParts); - - if (6 <= transformParameters.count()) - { - QTransform *tr = NULL; - tr = new QTransform(transformParameters.at(0).toDouble(), - transformParameters.at(1).toDouble(), - transformParameters.at(2).toDouble(), - transformParameters.at(3).toDouble(), - transformParameters.at(4).toDouble(), - transformParameters.at(5).toDouble()); - - trRet = *tr; - - delete tr; - } - - if (6 <= transformParameters.count()) - { - QTransform *tr = NULL; - tr = new QTransform(transformParameters.at(0).toDouble(), - transformParameters.at(1).toDouble(), - transformParameters.at(2).toDouble(), - transformParameters.at(3).toDouble(), - transformParameters.at(4).toDouble(), - transformParameters.at(5).toDouble()); - - trRet = *tr; - - delete tr; - } - return trRet; -} - -qreal UBCFFAdaptor::UBToCFFConverter::getAngleFromTransform(const QTransform &tr) -{ - qreal angle = -(atan(tr.m21()/tr.m11())*180/PI); - if (tr.m21() > 0 && tr.m11() < 0) - angle += 180; - else - if (tr.m21() < 0 && tr.m11() < 0) - angle += 180; - return angle; -} - -void UBCFFAdaptor::UBToCFFConverter::setGeometryFromUBZ(const QDomElement &ubzElement, QDomElement &iwbElement) -{ - setCoordinatesFromUBZ(ubzElement,iwbElement); - - - -} - -void UBCFFAdaptor::UBToCFFConverter::setCoordinatesFromUBZ(const QDomElement &ubzElement, QDomElement &iwbElement) -{ - QTransform tr; - - if (QString() != ubzElement.attribute(aTransform)) - tr = getTransformFromUBZ(ubzElement); - - qreal x = ubzElement.attribute(aX).toDouble(); - qreal y = ubzElement.attribute(aY).toDouble(); - qreal height = ubzElement.attribute(aHeight).toDouble(); - qreal width = ubzElement.attribute(aWidth).toDouble(); - - qreal alpha = getAngleFromTransform(tr); - - QRectF itemRect; - QGraphicsRectItem item; - - item.setRect(0,0, width, height); - item.setTransform(tr); - item.setRotation(-alpha); - QTransform sceneMatrix = item.sceneTransform(); - - iwbElement.setAttribute(aX, x); - iwbElement.setAttribute(aY, y); - iwbElement.setAttribute(aHeight, height*sceneMatrix.m22()); - iwbElement.setAttribute(aWidth, width*sceneMatrix.m11()); - iwbElement.setAttribute(aTransform, QString("rotate(%1) translate(%2,%3)").arg(alpha) - .arg(sceneMatrix.dx()) - .arg(sceneMatrix.dy())); -} - -bool UBCFFAdaptor::UBToCFFConverter::setContentFromUBZ(const QDomElement &ubzElement, QDomElement &svgElement) -{ - bool bRet = true; - - QString srcPath; - if (tUBZForeignObject != ubzElement.tagName()) - srcPath = ubzElement.attribute(aUBZHref); - else - srcPath = ubzElement.attribute(aSrc); - - QString sSrcContentFolder = getSrcContentFolderName(srcPath); - QString sSrcFileName = sourcePath + "/" + srcPath ; - QString fileExtention = getExtentionFromFileName(sSrcFileName); - QString sDstContentFolder = getDstContentFolderName(ubzElement.tagName()); - QString sDstFileName(QString(QUuid::createUuid().toString()+"."+convertExtention(fileExtention))); - - - if (itIsSupportedFormat(fileExtention)) // format is supported and we can copy src. files without changing. - { - sSrcFileName = sourcePath + "/" + sSrcContentFolder + "/" + getFileNameFromPath(srcPath); // some elements must be exported as images, so we take hes existing thumbnails. - - QFile srcFile; - srcFile.setFileName(sSrcFileName); - - QDir dstDocFolder(destinationPath); - - if (!dstDocFolder.exists(sDstContentFolder)) - bRet &= dstDocFolder.mkdir(sDstContentFolder); - - if (bRet) - { - QString dstFilePath = destinationPath+"/"+sDstContentFolder+"/"+sDstFileName; - bRet &= srcFile.copy(dstFilePath); - } - - if (bRet) - { - svgElement.setAttribute(aSVGHref, sDstContentFolder+"/"+sDstFileName); - // NOT by standard! Enable it later! - // validator http://validator.imsglobal.org/iwb/index.jsp?validate=package - //svgElement.setAttribute(aSVGRequiredExtension, svgRequiredExtensionPrefix+convertExtention(fileExtention)); - } - } - else - if (itIsFormatToConvert(fileExtention)) // we cannot copy that source files. We need to create dst. file from src. file without copy. - { - if (feSvg == fileExtention) - { - QDir dstDocFolder(destinationPath); - - if (!dstDocFolder.exists(sDstContentFolder)) - bRet &= dstDocFolder.mkdir(sDstContentFolder); - - if (bRet) - { - if (feSvg == fileExtention) // svg images must be converted to PNG. - { - QString dstFilePath = destinationPath+"/"+sDstContentFolder+"/"+sDstFileName; - bRet &= createPngFromSvg(sSrcFileName, dstFilePath, getTransformFromUBZ(ubzElement)); - } - else - bRet = false; - } - - if (bRet) - { - svgElement.setAttribute(aSVGHref, sDstContentFolder+"/"+sDstFileName); - // NOT by standard! Enable it later! - // validator http://validator.imsglobal.org/iwb/index.jsp?validate=package - //svgElement.setAttribute(aSVGRequiredExtension, svgRequiredExtensionPrefix+fePng); - } - } - }else - { - addLastExportError(QObject::tr("Element ID = ") + QString("%1 \r\n").arg(ubzElement.attribute(aUBZUuid)) - + QString("Source file = ") + QString("%1 \r\n").arg(ubzElement.attribute(aUBZSource)) - + QObject::tr("Content is not supported in destination format.")); - bRet = false; - } - - if (!bRet) - { - qDebug() << "format is not supported by CFF"; - } - - return bRet; -} - -void UBCFFAdaptor::UBToCFFConverter::setCFFTextFromHTMLTextNode(const QDomElement htmlTextNode, QDomElement &iwbElement) -{ - - QDomDocument textDoc; - - QDomElement textParentElement = iwbElement; - - QString textString; - QDomNode htmlPNode = htmlTextNode.firstChild(); - bool bTbreak = false; - - // reads HTML text strings - each string placed in separate

section - while(!htmlPNode.isNull()) - { - // add for split strings - if (bTbreak) - { - bTbreak = false; - - QDomElement tbreakNode = textDoc.createElementNS(svgIWBNS, svgIWBNSPrefix+":"+tIWBTbreak); - textParentElement.appendChild(tbreakNode.cloneNode(true)); - } - - QDomNode spanNode = htmlPNode.firstChild(); - - while (!spanNode.isNull()) - { - if (spanNode.isText()) - { - QDomText nodeText = textDoc.createTextNode(spanNode.nodeValue()); - textParentElement.appendChild(nodeText.cloneNode(true)); - } - else - if (spanNode.isElement()) - { - QDomElement pElementIwb; - QDomElement spanElement = textDoc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBTspan); - setCommonAttributesFromUBZ(htmlPNode.toElement(), pElementIwb, spanElement); - - if (spanNode.hasAttributes()) - { - int attrCount = spanNode.attributes().count(); - if (0 < attrCount) - { - for (int i = 0; i < attrCount; i++) - { - // html attributes like: style="font-size:40pt; color:"red";". - QStringList cffAttributes = spanNode.attributes().item(i).nodeValue().split(";", UB::SplitBehavior::SkipEmptyParts); - { - for (int i = 0; i < cffAttributes.count(); i++) - { - QString attr = cffAttributes.at(i).trimmed(); - QStringList AttrVal = attr.split(":", UB::SplitBehavior::SkipEmptyParts); - if(1 < AttrVal.count()) - { - QString sAttr = ubzAttrNameToCFFAttrName(AttrVal.at(0)); - if (itIsSVGElementAttribute(spanElement.tagName(), sAttr)) - spanElement.setAttribute(sAttr, ubzAttrValueToCFFAttrName(AttrVal.at(1))); - } - } - } - } - } - } - QDomText nodeText = textDoc.createTextNode(spanNode.firstChild().nodeValue()); - spanElement.appendChild(nodeText); - textParentElement.appendChild(spanElement.cloneNode(true)); - } - spanNode = spanNode.nextSibling(); - } - - bTbreak = true; - htmlPNode = htmlPNode.nextSibling(); - } -} - -QString UBCFFAdaptor::UBToCFFConverter::ubzAttrNameToCFFAttrName(QString cffAttrName) -{ - QString sRet = cffAttrName; - if (QString("color") == cffAttrName) - sRet = QString("fill"); - if (QString("align") == cffAttrName) - sRet = QString("text-align"); - - return sRet; -} -QString UBCFFAdaptor::UBToCFFConverter::ubzAttrValueToCFFAttrName(QString cffValue) -{ - QString sRet = cffValue; - if (QString("text") == cffValue) - sRet = QString("normal"); - - return sRet; -} - -bool UBCFFAdaptor::UBToCFFConverter::setCFFAttribute(const QString &attributeName, const QString &attributeValue, const QDomElement &ubzElement, QDomElement &iwbElement, QDomElement &svgElement) -{ - bool bRet = true; - bool bNeedsIWBSection = false; - - if (itIsIWBAttribute(attributeName)) - { - if (!((aBackground == attributeName) && (avFalse == attributeValue))) - { - iwbElement.setAttribute(attributeName, attributeValue); - bNeedsIWBSection = true; - } - } - else - if (itIsUBZAttributeToConvert(attributeName)) - { - if (aTransform == attributeName) - { - setGeometryFromUBZ(ubzElement, svgElement); - } - else - if (attributeName.contains(aUBZUuid)) - { - - QString parentId = ubzElement.attribute(aUBZParent); - QString id; - if (!parentId.isEmpty()) - id = "{" + parentId + "}" + "{" + ubzElement.attribute(aUBZUuid)+"}"; - else - id = "{" + ubzElement.attribute(aUBZUuid)+"}"; - - svgElement.setAttribute(aID, id); - } - else - if (attributeName.contains(aUBZHref)||attributeName.contains(aSrc)) - { - bRet &= setContentFromUBZ(ubzElement, svgElement); - bNeedsIWBSection = bRet||bNeedsIWBSection; - } - } - else - if (itIsSVGElementAttribute(svgElement.tagName(),attributeName)) - { - svgElement.setAttribute(attributeName, attributeValue); - } - - if (bNeedsIWBSection) - { - if (0 < iwbElement.attributes().count()) - { - - QStringList tl = ubzElement.attribute(aSVGHref).split("/"); - QString id = tl.at(tl.count()-1); - // if element already have an ID, we use it. Else we create new id for element. - if (QString() == id) - id = QUuid::createUuid().toString(); - - svgElement.setAttribute(aID, id); - iwbElement.setAttribute(aRef, id); - } - } - - return bRet; -} - -bool UBCFFAdaptor::UBToCFFConverter::setCommonAttributesFromUBZ(const QDomElement &ubzElement, QDomElement &iwbElement, QDomElement &svgElement) -{ - bool bRet = true; - - for (int i = 0; i < ubzElement.attributes().count(); i++) - { - QDomNode attribute = ubzElement.attributes().item(i); - QString attributeName = ubzAttrNameToCFFAttrName(attribute.nodeName().remove("ub:")); - - bRet &= setCFFAttribute(attributeName, ubzAttrValueToCFFAttrName(attribute.nodeValue()), ubzElement, iwbElement, svgElement); - if (!bRet) break; - } - return bRet; -} - -void UBCFFAdaptor::UBToCFFConverter::setViewBox(QRect viewbox) -{ - mViewbox |= viewbox; -} - -QDomNode UBCFFAdaptor::UBToCFFConverter::findTextNode(const QDomNode &node) -{ - QDomNode iterNode = node; - - while (!iterNode.isNull()) - { - if (iterNode.isText()) - { - if (!iterNode.isNull()) - return iterNode; - } - else - { - if (!iterNode.firstChild().isNull()) - { - QDomNode foundNode = findTextNode(iterNode.firstChild()); - if (!foundNode.isNull()) - if (foundNode.isText()) - return foundNode; - } - } - if (!iterNode.nextSibling().isNull()) - iterNode = iterNode.nextSibling(); - else - break; - } - return iterNode; -} - -QDomNode UBCFFAdaptor::UBToCFFConverter::findNodeByTagName(const QDomNode &node, QString tagName) -{ - QDomNode iterNode = node; - - while (!iterNode.isNull()) - { - QString t = iterNode.toElement().tagName(); - if (tagName == t) - return iterNode; - else - { - if (!iterNode.firstChildElement().isNull()) - { - QDomNode foundNode = findNodeByTagName(iterNode.firstChildElement(), tagName); - if (!foundNode.isNull()){ - if (foundNode.isElement()) - { - if (tagName == foundNode.toElement().tagName()) - return foundNode; - } - else - break; - } - } - } - - if (!iterNode.nextSibling().isNull()) - iterNode = iterNode.nextSibling(); - else - break; - } - return QDomNode(); - -} - -bool UBCFFAdaptor::UBToCFFConverter::createBackground(const QDomElement &element, QMultiMap &dstSvgList) -{ - qDebug() << "|creating element background"; - - - QDomDocument doc; - - //QDomElement svgBackgroundElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tUBZImage); - QDomElement svgBackgroundElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBRect); - QDomElement iwbBackgroundElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement); - - - QRect bckRect(mViewbox); - - if (0 <= mViewbox.topLeft().x()) - bckRect.topLeft().setX(0); - - if (0 <= mViewbox.topLeft().y()) - bckRect.topLeft().setY(0); - - if (QRect() != bckRect) - { - QString sElementID = QUuid::createUuid().toString(); - - bool darkBackground = (avTrue == element.attribute(aDarkBackground)); - svgBackgroundElementPart.setAttribute(aFill, darkBackground ? "black" : "white"); - svgBackgroundElementPart.setAttribute(aID, sElementID); - svgBackgroundElementPart.setAttribute(aX, bckRect.x()); - svgBackgroundElementPart.setAttribute(aY, bckRect.y()); - svgBackgroundElementPart.setAttribute(aHeight, bckRect.height()); - svgBackgroundElementPart.setAttribute(aWidth, bckRect.width()); - - //svgBackgroundElementPart.setAttribute(aSVGHref, backgroundImagePath); - - iwbBackgroundElementPart.setAttribute(aRef, sElementID); - iwbBackgroundElementPart.setAttribute(aBackground, avTrue); - //iwbBackgroundElementPart.setAttribute(aLocked, avTrue); - - addSVGElementToResultModel(svgBackgroundElementPart, dstSvgList, DEFAULT_BACKGROUND_LAYER); - addIWBElementToResultModel(iwbBackgroundElementPart); - return true; - } - else - { - qDebug() << "|error at creating element background"; - errorStr = "CreatingElementBackgroundParsingError."; - return false; - } -} - -QString UBCFFAdaptor::UBToCFFConverter::createBackgroundImage(const QDomElement &element, QSize size) -{ - QString sRet; - - QString sDstFileName(fIWBBackground); - - bool bDirExists = true; - QDir dstDocFolder(destinationPath); - - if (!dstDocFolder.exists(cfImages)) - bDirExists &= dstDocFolder.mkdir(cfImages); - - QString dstFilePath; - if (bDirExists) - dstFilePath = destinationPath+"/"+cfImages+"/"+sDstFileName; - - if (!QFile().exists(dstFilePath)) - { - QRect rect(0,0, size.width(), size.height()); - - QImage *bckImage = new QImage(size, QImage::Format_RGB888); - - QPainter *painter = new QPainter(bckImage); - - bool darkBackground = (avTrue == element.attribute(aDarkBackground)); - - QColor bCrossColor; - - bCrossColor = darkBackground?QColor(Qt::white):QColor(Qt::blue); - int penAlpha = (int)(255/2); // default Sankore value for transform.m11 < 1 - bCrossColor.setAlpha(penAlpha); - painter->setPen(bCrossColor); - painter->setBrush(darkBackground?QColor(Qt::black):QColor(Qt::white)); - - painter->drawRect(rect); - - if (avTrue == element.attribute(aCrossedBackground)) - { - qreal firstY = ((int) (rect.y () / iCrossSize)) * iCrossSize; - - for (qreal yPos = firstY; yPos <= rect.y () + rect.height (); yPos += iCrossSize) - { - painter->drawLine (rect.x (), yPos, rect.x () + rect.width (), yPos); - } - - qreal firstX = ((int) (rect.x () / iCrossSize)) * iCrossSize; - - for (qreal xPos = firstX; xPos <= rect.x () + rect.width (); xPos += iCrossSize) - { - painter->drawLine (xPos, rect.y (), xPos, rect.y () + rect.height ()); - } - } - - painter->end(); - painter->save(); - - if (QString() != dstFilePath) - if (bckImage->save(dstFilePath)) - sRet = cfImages+"/"+sDstFileName; - - delete bckImage; - delete painter; - } - else - sRet = cfImages+"/"+sDstFileName; - - return sRet; -} - -bool UBCFFAdaptor::UBToCFFConverter::createPngFromSvg(QString &svgPath, QString &dstPath, QTransform transformation, QSize size) -{ - if (QFile().exists(svgPath)) - { - QImage i(svgPath); - - QSize iSize = (QSize() == size)?QSize(i.size().width()*transformation.m11(), i.size().height()*transformation.m22()):size; - - QImage image(iSize, QImage::Format_ARGB32_Premultiplied); - image.fill(0); - QPainter imagePainter(&image); - QSvgRenderer renderer(svgPath); - renderer.render(&imagePainter); - - return image.save(dstPath); - - } - else - return false; -} - - -bool UBCFFAdaptor::UBToCFFConverter::parseSVGGGroup(const QDomElement &element, QMultiMap &dstSvgList) -{ - qDebug() << "|parsing g section"; - QDomElement nextElement = element.firstChildElement(); - if (nextElement.isNull()) { - qDebug() << "Empty g element"; - errorStr = "EmptyGSection"; - return false; - } - - QMultiMap svgElements; - - QDomDocument doc; - QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBG); - QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement); - - // Elements can know about its layer, so it must add result QDomElements to ordrered list. - while (!nextElement.isNull()) { - QString tagName = nextElement.tagName(); - if (tagName == tUBZLine) parseUBZLine(nextElement, svgElements); - else if (tagName == tUBZPolygon) parseUBZPolygon(nextElement, svgElements); - else if (tagName == tUBZPolyline) parseUBZPolyline(nextElement, svgElements); - - nextElement = nextElement.nextSiblingElement(); - } - - QList layers; - const auto keys = svgElements.keys(); - for (const auto key : keys) { - layers << key; - } - - std::sort(layers.begin(), layers.end()); - int layer = layers.at(0); - - for (const auto &value : std::as_const(svgElements)) { - svgElementPart.appendChild(value); - } - - addSVGElementToResultModel(svgElementPart, dstSvgList, layer); - - return true; -} -bool UBCFFAdaptor::UBToCFFConverter::parseUBZImage(const QDomElement &element, QMultiMap &dstSvgList) -{ - qDebug() << "|parsing image"; - - QDomDocument doc; - - QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element)); - QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement); - - if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart)) - { - addSVGElementToResultModel(svgElementPart, dstSvgList, getElementLayer(element)); - - if (0 < iwbElementPart.attributes().count()) - addIWBElementToResultModel(iwbElementPart); - return true; - } - else - { - qDebug() << "|error at image parsing"; - errorStr = "ImageParsingError"; - return false; - - } -} - -bool UBCFFAdaptor::UBToCFFConverter::parseUBZVideo(const QDomElement &element, QMultiMap &dstSvgList) -{ - qDebug() << "|parsing video"; - - QDomDocument doc; - - QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element)); - QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement); - - if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart)) - { - QDomElement svgSwitchSection = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBSwitch); - svgSwitchSection.appendChild(svgElementPart); - - // if viewer cannot open that content - it must use that: - QDomElement svgText = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBTextArea); - svgText.setAttribute(aX, svgElementPart.attribute(aX)); - svgText.setAttribute(aY, svgElementPart.attribute(aY)); - svgText.setAttribute(aWidth, svgElementPart.attribute(aWidth)); - svgText.setAttribute(aHeight, svgElementPart.attribute(aHeight)); - svgText.setAttribute(aTransform, svgElementPart.attribute(aTransform)); - - QDomText text = doc.createTextNode("Cannot Open Content"); - svgText.appendChild(text); - - svgSwitchSection.appendChild(svgText); - - addSVGElementToResultModel(svgSwitchSection, dstSvgList, getElementLayer(element)); - - if (0 < iwbElementPart.attributes().count()) - addIWBElementToResultModel(iwbElementPart); - return true; - } - else - { - qDebug() << "|error at video parsing"; - errorStr = "VideoParsingError"; - return false; - } -} - -bool UBCFFAdaptor::UBToCFFConverter::parseUBZAudio(const QDomElement &element, QMultiMap &dstSvgList) -{ - qDebug() << "|parsing audio"; - - // audio file must be linked to cff item excluding video. - // to do: - // 1 add image for audio element. - // 2 set id for this element - // 3 add section with xlink:href to audio file - // 4 add shild to a section with id of the image - - QDomDocument doc; - - QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element)); - QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement); - - if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart)) - { - //we must create image-containers for audio files - int audioImageDimention = qMin(svgElementPart.attribute(aWidth).toInt(), svgElementPart.attribute(aHeight).toInt()); - QString srcAudioImageFile(sAudioElementImage); - QString elementId = QString(QUuid::createUuid().toString()); - QString sDstAudioImageFileName = elementId+"."+fePng; - QString dstAudioImageFilePath = destinationPath+"/"+cfImages+"/"+sDstAudioImageFileName; - QString dstAudioImageRelativePath = cfImages+"/"+sDstAudioImageFileName; - - QFile srcFile(srcAudioImageFile); - - //creating folder for audioImage - QDir dstDocFolder(destinationPath); - bool bRes = true; - if (!dstDocFolder.exists(cfImages)) - bRes &= dstDocFolder.mkdir(cfImages); - - // CFF cannot show SVG images, so we need to convert it to png. - if (bRes && createPngFromSvg(srcAudioImageFile, dstAudioImageFilePath, getTransformFromUBZ(element), QSize(audioImageDimention, audioImageDimention))) - { - // switch section disabled because of imcompatibility with validator http://validator.imsglobal.org/iwb/index.jsp?validate=package - // QDomElement svgSwitchSection = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBSwitch); - - // first we place content - QDomElement svgASection = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBA); - svgASection.setAttribute(aSVGHref, svgElementPart.attribute(aSVGHref)); - - svgElementPart.setTagName(tIWBImage); - svgElementPart.setAttribute(aSVGHref, dstAudioImageRelativePath); - svgElementPart.setAttribute(aHeight, audioImageDimention); - svgElementPart.setAttribute(aWidth, audioImageDimention); - - svgASection.appendChild(svgElementPart); - // switch section disabled because of imcompatibility with validator http://validator.imsglobal.org/iwb/index.jsp?validate=package - // svgSwitchSection.appendChild(svgASection); - - // if viewer cannot open that content - it must use that: - QDomElement svgText = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBTextArea); - svgText.setAttribute(aX, svgElementPart.attribute(aX)); - svgText.setAttribute(aY, svgElementPart.attribute(aY)); - svgText.setAttribute(aWidth, svgElementPart.attribute(aWidth)); - svgText.setAttribute(aHeight, svgElementPart.attribute(aHeight)); - svgText.setAttribute(aTransform, svgElementPart.attribute(aTransform)); - - QDomText text = doc.createTextNode("Cannot Open Content"); - svgText.appendChild(text); - - // switch section disabled because of imcompatibility with validator http://validator.imsglobal.org/iwb/index.jsp?validate=package - // svgSwitchSection.appendChild(svgText); - - // switch section disabled because of imcompatibility with validator http://validator.imsglobal.org/iwb/index.jsp?validate=package - addSVGElementToResultModel(svgASection/*svgSwitchSection*/, dstSvgList, getElementLayer(element)); - - if (0 < iwbElementPart.attributes().count()) - addIWBElementToResultModel(iwbElementPart); - return true; - } - return false; - } - else - { - qDebug() << "|error at audio parsing"; - errorStr = "AudioParsingError"; - return false; - } -} - -bool UBCFFAdaptor::UBToCFFConverter::parseForeignObject(const QDomElement &element, QMultiMap &dstSvgList) -{ - - if (element.attribute(aUBZType) == avUBZText) { - return parseUBZText(element, dstSvgList); - } - - qDebug() << "|parsing foreign object"; - - QDomDocument doc; - - QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element)); - QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement); - - if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart)) - { - addSVGElementToResultModel(svgElementPart, dstSvgList, getElementLayer(element)); - if (0 < iwbElementPart.attributes().count()) - addIWBElementToResultModel(iwbElementPart); - return true; - } - else - { - qDebug() << "|error at parsing foreign object"; - errorStr = "ForeignObjectParsingError"; - return false; - } -} - -bool UBCFFAdaptor::UBToCFFConverter::parseUBZText(const QDomElement &element, QMultiMap &dstSvgList) -{ - qDebug() << "|parsing text"; - - QDomDocument doc; - - QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element)); - QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement); - - if (element.hasChildNodes()) - { - QDomDocument htmlDoc; - htmlDoc.setContent(findTextNode(element).nodeValue()); - QDomNode bodyNode = findNodeByTagName(htmlDoc.firstChildElement(), "body"); - - setCFFTextFromHTMLTextNode(bodyNode.toElement(), svgElementPart); - - if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart)) - { - QString commonParams; - for (int i = 0; i < bodyNode.attributes().count(); i++) - { - commonParams += " " + bodyNode.attributes().item(i).nodeValue(); - } - commonParams.remove(" "); - commonParams.remove("'"); - - QStringList commonAttributes = commonParams.split(";", UB::SplitBehavior::SkipEmptyParts); - for (int i = 0; i < commonAttributes.count(); i++) - { - QStringList AttrVal = commonAttributes.at(i).split(":", UB::SplitBehavior::SkipEmptyParts); - if (1 < AttrVal.count()) - { - QString sAttr = ubzAttrNameToCFFAttrName(AttrVal.at(0)); - QString sVal = ubzAttrValueToCFFAttrName(AttrVal.at(1)); - - setCFFAttribute(sAttr, sVal, element, iwbElementPart, svgElementPart); - } - } - addSVGElementToResultModel(svgElementPart, dstSvgList, getElementLayer(element)); - if (0 < iwbElementPart.attributes().count()) - addIWBElementToResultModel(iwbElementPart); - return true; - } - return false; - } - else - { - qDebug() << "|error at text parsing"; - errorStr = "TextParsingError"; - return false; - } -} - -bool UBCFFAdaptor::UBToCFFConverter::parseUBZPolygon(const QDomElement &element, QMultiMap &dstSvgList) -{ - qDebug() << "||parsing polygon"; - - QDomDocument doc; - - QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element)); - QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement); - - if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart)) - { - svgElementPart.setAttribute(aStroke, svgElementPart.attribute(aFill)); - addSVGElementToResultModel(svgElementPart, dstSvgList, getElementLayer(element)); - - if (0 < iwbElementPart.attributes().count()) - { - QString id = svgElementPart.attribute(aUBZUuid); - if (id.isEmpty()) - id = QUuid::createUuid().toString(); - - svgElementPart.setAttribute(aID, id); - iwbElementPart.setAttribute(aRef, id); - - addIWBElementToResultModel(iwbElementPart); - } - return true; - } - else - { - qDebug() << "||error at parsing polygon"; - errorStr = "PolygonParsingError"; - return false; - } - -} - -bool UBCFFAdaptor::UBToCFFConverter::parseUBZPolyline(const QDomElement &element, QMultiMap &dstSvgList) -{ - qDebug() << "||parsing polyline"; - QDomElement resElement; - - QDomDocument doc; - - QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element)); - QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement); - - if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart)) - { - svgElementPart.setAttribute(aStroke, svgElementPart.attribute(aFill)); - addSVGElementToResultModel(svgElementPart, dstSvgList, getElementLayer(element)); - - if (0 < iwbElementPart.attributes().count()) - { - QString id = QUuid::createUuid().toString(); - svgElementPart.setAttribute(aID, id); - iwbElementPart.setAttribute(aRef, id); - - addIWBElementToResultModel(iwbElementPart); - } - return true; - } - else - { - qDebug() << "||error at parsing polygon"; - errorStr = "PolylineParsingError"; - return false; - } - -} - -bool UBCFFAdaptor::UBToCFFConverter::parseUBZLine(const QDomElement &element, QMultiMap &dstSvgList) -{ - qDebug() << "||parsing line"; - QDomElement resElement; - QDomDocument doc; - - QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element)); - QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement); - - if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart)) - { - svgElementPart.setAttribute(aStroke, svgElementPart.attribute(aFill)); - addSVGElementToResultModel(svgElementPart, dstSvgList, getElementLayer(element)); - - if (0 < iwbElementPart.attributes().count()) - { - QString id = QUuid::createUuid().toString(); - svgElementPart.setAttribute(aID, id); - iwbElementPart.setAttribute(aRef, id); - - addIWBElementToResultModel(iwbElementPart); - } - } - else - { - qDebug() << "||error at parsing polygon"; - errorStr = "LineParsingError"; - return false; - } - return true; -} - -void UBCFFAdaptor::UBToCFFConverter::addSVGElementToResultModel(const QDomElement &element, QMultiMap &dstList, int layer) -{ - int elementLayer = (DEFAULT_LAYER == layer) ? DEFAULT_LAYER : layer; - - QDomElement rootElement = element.cloneNode(true).toElement(); - mDocumentToWrite->firstChildElement().appendChild(rootElement); - dstList.insert(elementLayer, rootElement); -} - -void UBCFFAdaptor::UBToCFFConverter::addIWBElementToResultModel(const QDomElement &element) -{ - QDomElement rootElement = element.cloneNode(true).toElement(); - mDocumentToWrite->firstChildElement().appendChild(rootElement); - mExtendedElements.append(rootElement); -} - -UBCFFAdaptor::UBToCFFConverter::~UBToCFFConverter() -{ - if (mDataModel) - delete mDataModel; - if (mIWBContentWriter) - delete mIWBContentWriter; - if (mDocumentToWrite) - delete mDocumentToWrite; -} -bool UBCFFAdaptor::UBToCFFConverter::isValid() const -{ - bool result = QFileInfo(sourcePath).exists() - && QFileInfo(sourcePath).isDir() - && errorStr == noErrorMsg; - - if (!result) { - qDebug() << "specified data is not valid"; - errorStr = "ValidateDataError"; - } - - return result; -} - -void UBCFFAdaptor::UBToCFFConverter::fillNamespaces() -{ - mIWBContentWriter->writeDefaultNamespace(svgUBZNS); - mIWBContentWriter->writeNamespace(iwbNS, iwbNsPrefix); - mIWBContentWriter->writeNamespace(svgIWBNS, svgIWBNSPrefix); - mIWBContentWriter->writeNamespace(xlinkNS, xlinkNSPrefix); -} - -QString UBCFFAdaptor::UBToCFFConverter::digitFileFormat(int digit) const -{ - return QString("%1").arg(digit, 3, 10, QLatin1Char('0')); -} -QString UBCFFAdaptor::UBToCFFConverter::contentIWBFileName() const -{ - return destinationPath + "/" + fIWBContent; -} - -//setting SVG dimenitons -QSize UBCFFAdaptor::UBToCFFConverter::getSVGDimentions(const QString &element) -{ - - QStringList dimList; - - dimList = element.split(dimensionsDelimiter1); - if (dimList.count() != 2) // row unlike 0x0 - return QSize(); - - bool ok; - - int width = dimList.takeFirst().toInt(&ok); - if (!ok || !width) - return QSize(); - - int height = dimList.takeFirst().toInt(&ok); - if (!ok || !height) - return QSize(); - - return QSize(width, height); -} - -//Setting viewbox rectangle -QRect UBCFFAdaptor::UBToCFFConverter::getViewboxRect(const QString &element) const -{ - QStringList dimList; - - dimList = element.split(dimensionsDelimiter2); - if (dimList.count() != 4) // row unlike 0 0 0 0 - return QRect(); - - bool ok = false; - - int x = dimList.takeFirst().toInt(&ok); - if (!ok || !x) - return QRect(); - - int y = dimList.takeFirst().toInt(&ok); - if (!ok || !y) - return QRect(); - - int width = dimList.takeFirst().toInt(&ok); - if (!ok || !width) - return QRect(); - - int height = dimList.takeFirst().toInt(&ok); - if (!ok || !height) - return QRect(); - - return QRect(x, y, width, height); -} - -QString UBCFFAdaptor::UBToCFFConverter::rectToIWBAttr(const QRect &rect) const -{ - if (rect.isNull()) return QString(); - - return QString("%1 %2 %3 %4").arg(rect.topLeft().x()) - .arg(rect.topLeft().y()) - .arg(rect.width()) - .arg(rect.height()); -} - -UBCFFAdaptor::UBToUBZConverter::UBToUBZConverter() -{ - -} diff --git a/plugins/cffadaptor/src/UBCFFAdaptor.h b/plugins/cffadaptor/src/UBCFFAdaptor.h deleted file mode 100644 index 5de50ec39..000000000 --- a/plugins/cffadaptor/src/UBCFFAdaptor.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) - * - * Copyright (C) 2013 Open Education Foundation - * - * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour - * l'Education Numérique en Afrique (GIP ENA) - * - * This file is part of OpenBoard. - * - * OpenBoard is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License, - * with a specific linking exception for the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the - * same license as the "OpenSSL" library). - * - * OpenBoard is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with OpenBoard. If not, see . - */ - - -#ifndef UBCFFADAPTOR_H -#define UBCFFADAPTOR_H - -#include "UBCFFAdaptor_global.h" - -#include - -class QTransform; -class QDomDocument; -class QDomElement; -class QDomNode; -class QuaZipFile; - -class UBCFFADAPTORSHARED_EXPORT UBCFFAdaptor { - class UBToCFFConverter; - -public: - UBCFFAdaptor(); - ~UBCFFAdaptor(); - - bool convertUBZToIWB(const QString &from, const QString &to); - bool deleteDir(const QString& pDirPath) const; - QList getConversionMessages(); - -private: - QString uncompressZip(const QString &zipFile); - bool compressZip(const QString &source, const QString &destination); - bool compressDir(const QString &dirName, const QString &parentDir, QuaZipFile *outZip); - bool compressFile(const QString &fileName, const QString &parentDir, QuaZipFile *outZip); - - QString createNewTmpDir(); - bool freeDir(const QString &dir); - void freeTmpDirs(); - -private: - QStringList tmpDirs; - QList mConversionMessages; - -private: - - class UBToCFFConverter { - - static const int DEFAULT_LAYER = -100000; - - public: - UBToCFFConverter(const QString &source, const QString &destination); - ~UBToCFFConverter(); - bool isValid() const; - QString lastErrStr() const {return errorStr;} - bool parse(); - QList getMessages() {return mExportErrorList;} - - private: - - void addLastExportError(QString error) {mExportErrorList.append(error);} - - void fillNamespaces(); - - bool parseMetadata(); - bool parseContent(); - QDomElement parsePageset(const QStringList &pageFileNames); - QDomElement parsePage(const QString &pageFileName); - QDomElement parseSvgPageSection(const QDomElement &element); - void writeQDomElementToXML(const QDomNode &node); - bool writeExtendedIwbSection(); - QDomElement parseGroupsPageSection(const QDomElement &groupRoot); - - bool createBackground(const QDomElement &element, QMultiMap &dstSvgList); - QString createBackgroundImage(const QDomElement &element, QSize size); - bool createPngFromSvg(QString &svgPath, QString &dstPath, QTransform transformation, QSize size = QSize()); - - bool parseSVGGGroup(const QDomElement &element, QMultiMap &dstSvgList); - bool parseUBZImage(const QDomElement &element, QMultiMap &dstSvgList); - bool parseUBZVideo(const QDomElement &element, QMultiMap &dstSvgList); - bool parseUBZAudio(const QDomElement &element, QMultiMap &dstSvgList); - bool parseForeignObject(const QDomElement &element, QMultiMap &dstSvgList); - bool parseUBZText(const QDomElement &element, QMultiMap &dstSvgList); - - bool parseUBZPolygon(const QDomElement &element, QMultiMap &dstSvgList); - bool parseUBZPolyline(const QDomElement &element, QMultiMap &dstSvgList); - bool parseUBZLine(const QDomElement &element, QMultiMap &dstSvgList); - void addSVGElementToResultModel(const QDomElement &element, QMultiMap &dstList, int layer = DEFAULT_LAYER); - void addIWBElementToResultModel(const QDomElement &element); - - qreal getAngleFromTransform(const QTransform &tr); - QString getDstContentFolderName(const QString &elementType); - QString getSrcContentFolderName(QString href); - QString getFileNameFromPath(QString sPath); - QString getExtentionFromFileName(const QString &filename); - QString convertExtention(const QString &ext); - QString getElementTypeFromUBZ(const QDomElement &element); - - int getElementLayer(const QDomElement &element); - - bool itIsSupportedFormat(const QString &format) const; - bool itIsFormatToConvert(const QString &format) const; - bool itIsSVGElementAttribute(const QString ItemType, const QString &AttrName); - bool itIsIWBAttribute(const QString &attribute) const; - bool itIsUBZAttributeToConvert(const QString &attribute) const; - - bool ibwAddLine(int x1, int y1, int x2, int y2, QString color=QString(), int width=1, bool isBackground=false); - - QTransform getTransformFromUBZ(const QDomElement &ubzElement); - void setGeometryFromUBZ(const QDomElement &ubzElement, QDomElement &iwbElement); - void setCoordinatesFromUBZ(const QDomElement &ubzElement, QDomElement &iwbElement); - bool setContentFromUBZ(const QDomElement &ubzElement, QDomElement &svgElement); - void setCFFTextFromUBZ(const QDomElement &ubzElement, QDomElement &iwbElement, QDomElement &svgElement); - void setCFFTextFromHTMLTextNode(const QDomElement htmlTextNode, QDomElement &iwbElement); - QString ubzAttrNameToCFFAttrName(QString cffAttrName); - QString ubzAttrValueToCFFAttrName(QString cffAttrValue); - - bool setCFFAttribute(const QString &attributeName, const QString &attributeValue, const QDomElement &ubzElement, QDomElement &iwbElement, QDomElement &svgElement); - bool setCommonAttributesFromUBZ(const QDomElement &ubzElement, QDomElement &iwbElement, QDomElement &svgElement); - void setViewBox(QRect viewbox); - - QDomNode findTextNode(const QDomNode &node); - QDomNode findNodeByTagName(const QDomNode &node, QString tagName); - - QSize getSVGDimentions(const QString &element); - - inline QRect getViewboxRect(const QString &element) const; - inline QString rectToIWBAttr(const QRect &rect) const; - inline QString digitFileFormat(int num) const; - inline bool strToBool(const QString &in) const {return in == "true";} - QString contentIWBFileName() const; - - private: - QList mExportErrorList; - QMap iwbSVGItemsAttributes; - QDomDocument *mDataModel; //model for reading indata - QXmlStreamWriter *mIWBContentWriter; //stream to write outdata - QSize mSVGSize; //svg page size - QRect mViewbox; //Main viewbox parameter for CFF - QString sourcePath; // dir with unpacked source data (ubz) - QString destinationPath; //dir with unpacked destination data (iwb) - QDomDocument *mDocumentToWrite; //document for saved QDomElements from mSvgElements and mExtendedElements - QMultiMap mSvgElements; //Saving svg elements to have a sorted by z order list of elements to write; - QList mExtendedElements; //Saving extended options of elements to be able to add them to the end of result iwb document; - mutable QString errorStr; // last error string message - - public: - operator bool() const {return isValid();} - }; - - class UBToUBZConverter { - public: - UBToUBZConverter(); - }; - - -}; - -#endif // UBCFFADAPTOR_H diff --git a/plugins/cffadaptor/src/UBCFFAdaptor_global.h b/plugins/cffadaptor/src/UBCFFAdaptor_global.h deleted file mode 100644 index 3f060b96d..000000000 --- a/plugins/cffadaptor/src/UBCFFAdaptor_global.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour l'Education Numérique en Afrique (GIP ENA) - * - * This file is part of Open-Sankoré. - * - * Open-Sankoré is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License, - * with a specific linking exception for the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the - * same license as the "OpenSSL" library). - * - * Open-Sankoré is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Open-Sankoré. If not, see . - */ - - -#ifndef UBCFFADAPTOR_GLOBAL_H -#define UBCFFADAPTOR_GLOBAL_H - -#include - -#if defined(UBCFFADAPTOR_LIBRARY) -# define UBCFFADAPTORSHARED_EXPORT Q_DECL_EXPORT -#else -# define UBCFFADAPTORSHARED_EXPORT Q_DECL_IMPORT -#endif - -#endif // UBCFFADAPTOR_GLOBAL_H diff --git a/plugins/cffadaptor/src/UBCFFConstants.h b/plugins/cffadaptor/src/UBCFFConstants.h deleted file mode 100644 index 276eb75a6..000000000 --- a/plugins/cffadaptor/src/UBCFFConstants.h +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour l'Education Numérique en Afrique (GIP ENA) - * - * This file is part of Open-Sankoré. - * - * Open-Sankoré is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License, - * with a specific linking exception for the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the - * same license as the "OpenSSL" library). - * - * Open-Sankoré is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Open-Sankoré. If not, see . - */ - - -#ifndef UBCFFCONSTANTS_H -#define UBCFFCONSTANTS_H - -#define PI 3.1415926535 - -const int DEFAULT_BACKGROUND_LAYER = -20000002; -const int DEFAULT_BACKGROUND_CROSS_LAYER = -20000001; - -// Constant names. Use only them instead const char* in each function - -// Constant fileNames; -const QString fMetadata = "metadata.rdf"; -const QString fIWBContent = "content.xml"; -const QString fIWBBackground = "background.png"; -const QString sAudioElementImage = ":images/soundOn.svg"; - -// Constant messages; -const QString noErrorMsg = "NoError"; - -// Tag names -const QString tDescription = "Description"; -const QString tIWBRoot = "iwb"; -const QString tIWBMeta = "meta"; -const QString tUBZSize = "size"; -const QString tSvg = "svg"; -const QString tIWBPage = "page"; -const QString tIWBPageSet = "pageset"; -const QString tId = "id"; -const QString tElement = "element"; -const QString tUBZGroup = "group"; -const QString tUBZGroups = "groups"; -const QString tUBZG = "g"; -const QString tUBZPolygon = "polygon"; -const QString tUBZPolyline = "polyline"; -const QString tUBZLine = "line"; -const QString tUBZAudio = "audio"; -const QString tUBZVideo = "video"; -const QString tUBZImage = "image"; -const QString tUBZForeignObject = "foreignObject"; -const QString tUBZTextContent = "itemTextContent"; - -const QString tIWBA = "a"; -const QString tIWBG = "g"; -const QString tIWBSwitch = "switch"; -const QString tIWBImage = "image"; -const QString tIWBVideo = "video"; -const QString tIWBAudio = "audio"; -const QString tIWBText = "text"; -const QString tIWBTextArea = "textarea"; -const QString tIWBPolyLine = "polyline"; -const QString tIWBPolygon = "polygon"; -const QString tIWBFlash = "video"; -const QString tIWBRect = "rect"; -const QString tIWBLine = "line"; -const QString tIWBTbreak = "tbreak"; -const QString tIWBTspan = "tspan"; - -// Attributes names -const QString aIWBVersion = "version"; -const QString aOwner = "owner"; -const QString aDescription = "description"; -const QString aCreator = "creator"; -const QString aAbout = "about"; -const QString aIWBViewBox = "viewbox"; -const QString aUBZViewBox = "viewBox"; -const QString aDarkBackground = "dark-background"; -const QString aBackground = "background"; -const QString aCrossedBackground = "crossed-background"; -const QString aUBZType = "type"; -const QString aUBZUuid = "uuid"; -const QString aUBZParent = "parent"; -const QString aFill = "fill"; // IWB attribute contans color to fill - -const QString aID = "id"; // ID of any svg element can be placed in to iwb section -const QString aRef = "ref"; // as reference for applying additional attributes -const QString aSVGHref = "xlink:href"; // reference to file -const QString aIWBHref = "ref"; // reference to element ID -const QString aUBZHref = "href"; -const QString aUBZSource = "source"; -const QString aSrc = "src"; -const QString aSVGRequiredExtension = "requiredExtensions"; - -const QString aX = "x"; -const QString aY = "y"; -const QString aWidth = "width"; -const QString aHeight = "height"; -const QString aStroke = "stroke"; -const QString aStrokeWidth = "stroke-width"; -const QString aPoints = "points"; -const QString aZLayer = "z-value"; -const QString aLayer = "layer"; -const QString aTransform = "transform"; -const QString aLocked = "locked"; -const QString aIWBName = "name"; -const QString aIWBContent = "content"; - - -// Attribute values -const QString avIWBVersionNo = "1.0"; -const QString avUBZText = "text"; -const QString avFalse = "false"; -const QString avTrue = "true"; - -// Namespaces and prefixes -const QString svgRequiredExtensionPrefix = "http://www.imsglobal.org/iwb/"; -const QString dcNS = "http://purl.org/dc/elements/1.1/"; -const QString ubNS = "http://uniboard.mnemis.com/document"; -const QString svgUBZNS = "http://www.imsglobal.org/xsd/iwb_v1p0"; -const QString svgIWBNS = "http://www.w3.org/2000/svg"; -const QString xlinkNS = "http://www.w3.org/1999/xlink"; -const QString iwbNS = "http://www.imsglobal.org/xsd/iwb_v1p0"; -const QString xsiNS = "http://www.w3.org/2001/XMLSchema-instance"; -const QString xsiShemaLocation = "\ -http://www.imsglobal.org/xsd/iwb_v1p0 \ -http://www.imsglobal.org/profile/iwb/iwbv1p0_v1p0.xsd \ -http://www.w3.org/2000/svg http://www.imsglobal.org/profile/iwb/svgsubsetv1p0_v1p0.xsd \ -http://www.w3.org/1999/xlink http://www.imsglobal.org/xsd/w3/1999/xlink.xsd"; -const QString dcNSPrefix = "dc"; -const QString ubNSPrefix = "ub"; -const QString svgIWBNSPrefix = "svg"; -const QString xlinkNSPrefix = "xlink"; -const QString iwbNsPrefix = "iwb"; -const QString xsiPrefix = "xsi"; -const QString xsiSchemaLocationPrefix = "schemaLocation"; - -const QString avOwner = ""; -const QString avCreator = ""; -const QString avDescription = ""; - -//constant symbols and words etc -const QString dimensionsDelimiter1 = "x"; -const QString dimensionsDelimiter2 = " "; -const QString pageAlias = "page"; -const QString pageFileExtentionUBZ = "svg"; - -//content folder names -const QString cfImages = "images"; -const QString cfVideos = "video"; -const QString cfAudios = "audio"; -const QString cfFlash = "flash"; - -//known file extentions -const QString feSvg = "svg"; -const QString feWgt = "wgt"; -const QString fePng = "png"; - -const int iCrossSize = 32; -const int iCrossWidth = 1; - -// Image formats supported by CFF exclude wgt. Wgt is Sankore widget, which is considered as a .png preview. -const QString iwbElementImage(" \ -wgt, \ -jpeg, \ -jpg, \ -bmp, \ -gif, \ -wmf, \ -emf, \ -png, \ -tif, \ -tiff \ -"); - -// Video formats supported by CFF -const QString iwbElementVideo(" \ -mpg, \ -mpeg, \ -swf, \ -"); - -// Audio formats supported by CFF -const QString iwbElementAudio(" \ -mp3, \ -wav \ -"); - -const QString cffSupportedFileFormats(iwbElementImage + iwbElementVideo + iwbElementAudio); -const QString ubzFormatsToConvert("svg"); - - -const QString iwbSVGImageAttributes(" \ -id, \ -xlink:href, \ -x, \ -y, \ -height, \ -width, \ -fill-opacity, \ -requiredExtentions, \ -transform \ -"); - - -const QString iwbSVGAudioAttributes(" \ -id, \ -xlink:href, \ -x, \ -y, \ -height, \ -width, \ -fill-opacity, \ -requiredExtentions, \ -transform \ -"); - -const QString iwbSVGVideoAttributes(" \ -id, \ -xlink:href, \ -x, \ -y, \ -height, \ -width, \ -fill-opacity, \ -requiredExtentions, \ -transform \ -"); - -const QString iwbSVGRectAttributes(" \ -id, \ -x, \ -y, \ -height, \ -width, \ -fill, \ -fill-opacity, \ -stroke, \ -stroke-dasharray, \ -stroke-linecap, \ -stroke-linejoin, \ -stroke-opacity, \ -stroke-width, \ -transform \ -"); - - - -const QString iwbSVGTextAttributes(" \ -id, \ -x, \ -y, \ -fill, \ -font-family, \ -font-size, \ -font-style, \ -font-weight, \ -font-stretch, \ -transform \ -"); - -const QString iwbSVGTextAreaAttributes(" \ -id, \ -x, \ -y, \ -height, \ -width, \ -fill, \ -font-family, \ -font-size, \ -font-style, \ -font-weight, \ -font-stretch, \ -text-align, \ -transform \ -"); - -const QString iwbSVGTspanAttributes(" \ -id, \ -fill, \ -font-family, \ -font-size, \ -font-style, \ -font-weight, \ -font-stretch, \ -text-align, \ -"); - -const QString iwbSVGLineAttributes(" \ -id, \ -x1, \ -y1, \ -x2, \ -y2, \ -stroke, \ -stroke-dasharray, \ -stroke-width, \ -stroke-opacity, \ -stroke-linecap, \ -transform \ -"); - -const QString iwbSVGPolyLineAttributes(" \ -id, \ -points, \ -stroke, \ -stroke-width, \ -stroke-dasharray, \ -stroke-opacity, \ -stroke-linecap, \ -transform \ -"); - -const QString iwbSVGPolygonAttributes(" \ -id, \ -points, \ -fill, \ -fill-opacity, \ -stroke, \ -stroke-dasharray, \ -stroke-width, \ -stroke-linecap, \ -stroke-linejoin, \ -stroke-opacity, \ -stroke-width, \ -transform \ -"); - -// 1 to 1 copy to SVG section -const QString iwbElementAttributes(" \ -background, \ -background-fill, \ -background-posture, \ -flip, \ -freehand, \ -highlight, \ -highlight-fill, \ -list-style-type, \ -list-style-type-fill, \ -locked, \ -replicate, \ -revealer, \ -stroke-lineshape-start, \ -stroke-lineshape-end \ -"); - -// cannot be copied 1 to 1 to SVG section -const QString ubzElementAttributesToConvert(" \ -xlink:href, \ -src, \ -transform, \ -uuid \ -" -); - -// additional attributes. Have references in SVG section. -const QString svgElementAttributes(" \ -points, \ -fill, \ -fill-opacity, \ -stroke, \ -stroke-dasharray, \ -stroke-linecap, \ -stroke-opacity, \ -stroke-width, \ -stroke_linejoin, \ -requiredExtensions, \ -viewbox, \ -x, \ -y, \ -x1, \ -y1, \ -x2, \ -y2, \ -height, \ -width, \ -font-family, \ -font-size, \ -font-style, \ -font-weight, \ -font-stretch, \ -text-align \ -"); - -const QString ubzContentFolders("audios,videos,images,widgets"); - -#endif // UBCFFCONSTANTS_H diff --git a/plugins/cffadaptor/src/UBGlobals.h b/plugins/cffadaptor/src/UBGlobals.h deleted file mode 100644 index d49c11cfa..000000000 --- a/plugins/cffadaptor/src/UBGlobals.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) - * - * Copyright (C) 2013 Open Education Foundation - * - * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour - * l'Education Numérique en Afrique (GIP ENA) - * - * This file is part of OpenBoard. - * - * OpenBoard is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License, - * with a specific linking exception for the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the - * same license as the "OpenSSL" library). - * - * OpenBoard is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with OpenBoard. If not, see . - */ - - -#ifndef UBGLOBALS_H -#define UBGLOBALS_H - -#define DELETEPTR(ptr) if(NULL != ptr){ \ - delete ptr; \ - ptr = NULL; \ - } - -#ifdef Q_WS_WIN - -#define WARNINGS_DISABLE __pragma(warning(push, 0)); -#define WARNINGS_ENABLE __pragma(warning(pop)); - -#ifdef NO_THIRD_PARTY_WARNINGS -// disabling warning level to 0 and save old state -#define THIRD_PARTY_WARNINGS_DISABLE WARNINGS_DISABLE -#else -// just save old state (needs for not empty define) -#define THIRD_PARTY_WARNINGS_DISABLE __pragma(warning(push)); -#endif //#ifdef NO_THIRD_PARTY_WARNINGS -// anyway on WIN -#define THIRD_PARTY_WARNINGS_ENABLE WARNINGS_ENABLE - -#else //#ifdef Q_WS_WIN - -#define WARNINGS_DISABLE _Pragma("GCC diagnostic push"); \ -_Pragma("GCC diagnostic ignored \"-Wunused-parameter\""); \ -_Pragma("GCC diagnostic ignored \"-Wunused-variable\""); \ -_Pragma("GCC diagnostic ignored \"-Wsign-compare\""); - -#define WARNINGS_ENABLE _Pragma("GCC diagnostic pop"); - -#ifdef NO_THIRD_PARTY_WARNINGS -//disabling some warnings -#define THIRD_PARTY_WARNINGS_DISABLE WARNINGS_DISABLE - -#define THIRD_PARTY_WARNINGS_ENABLE WARNINGS_ENABLE -#else -// just save old state (needs for not empty define) -#define THIRD_PARTY_WARNINGS_ENABLE WARNINGS_ENABLE - -#endif //#ifdef NO_THIRD_PARTY_WARNINGS - -#endif //#ifdef Q_WS_WIN - -#endif // UBGLOBALS_H - diff --git a/plugins/plugins.pri b/plugins/plugins.pri deleted file mode 100644 index ddf3113a6..000000000 --- a/plugins/plugins.pri +++ /dev/null @@ -1,6 +0,0 @@ -HEADERS += plugins/cffadaptor/src/UBCFFAdaptor_global.h \ - plugins/cffadaptor/src/UBCFFAdaptor.h \ - plugins/cffadaptor/src/UBCFFConstants.h \ - plugins/cffadaptor/src/UBGlobals.h - -SOURCES += plugins/cffadaptor/src/UBCFFAdaptor.cpp diff --git a/src/adaptors/CMakeLists.txt b/src/adaptors/CMakeLists.txt index ef91e1096..e9a43b2ad 100644 --- a/src/adaptors/CMakeLists.txt +++ b/src/adaptors/CMakeLists.txt @@ -1,10 +1,6 @@ target_sources(${PROJECT_NAME} PRIVATE - UBCFFSubsetAdaptor.cpp - UBCFFSubsetAdaptor.h UBExportAdaptor.cpp UBExportAdaptor.h - UBExportCFF.cpp - UBExportCFF.h UBExportDocument.cpp UBExportDocument.h UBExportDocumentSetAdaptor.cpp @@ -17,8 +13,6 @@ target_sources(${PROJECT_NAME} PRIVATE UBExportWeb.h UBImportAdaptor.cpp UBImportAdaptor.h - UBImportCFF.cpp - UBImportCFF.h UBImportDocument.cpp UBImportDocument.h UBImportDocumentSetAdaptor.cpp diff --git a/src/adaptors/UBCFFSubsetAdaptor.cpp b/src/adaptors/UBCFFSubsetAdaptor.cpp deleted file mode 100644 index bec770dcf..000000000 --- a/src/adaptors/UBCFFSubsetAdaptor.cpp +++ /dev/null @@ -1,1570 +0,0 @@ -/* - * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) - * - * Copyright (C) 2013 Open Education Foundation - * - * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour - * l'Education Numérique en Afrique (GIP ENA) - * - * This file is part of OpenBoard. - * - * OpenBoard is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License, - * with a specific linking exception for the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the - * same license as the "OpenSSL" library). - * - * OpenBoard is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with OpenBoard. If not, see . - */ - - - -#include -#include -#include -#include -#include -#include - -#include "core/UBApplication.h" -#include "core/UBDisplayManager.h" -#include "core/UBPersistenceManager.h" - -#include "document/UBDocumentProxy.h" - -#include "domain/UBItem.h" -#include "domain/UBGraphicsPolygonItem.h" -#include "domain/UBGraphicsStroke.h" -#include "domain/UBGraphicsTextItem.h" -#include "domain/UBGraphicsSvgItem.h" -#include "domain/UBGraphicsPixmapItem.h" -#include "domain/UBGraphicsMediaItem.h" -#include "domain/UBGraphicsWidgetItem.h" -#include "domain/UBGraphicsTextItem.h" -#include "domain/UBGraphicsTextItemDelegate.h" -#include "domain/UBGraphicsWidgetItem.h" -#include "domain/UBGraphicsGroupContainerItem.h" - -#include "frameworks/UBFileSystemUtils.h" - -#include "UBCFFSubsetAdaptor.h" -#include "UBMetadataDcSubsetAdaptor.h" -#include "UBThumbnailAdaptor.h" -#include "UBSvgSubsetAdaptor.h" - -#include "core/memcheck.h" -//#include "qtlogger.h" - -//tag names definition. Use them everiwhere! -static QString tElement = "element"; -static QString tGroup = "group"; -static QString tEllipse = "ellipse"; -static QString tIwb = "iwb"; -static QString tMeta = "meta"; -static QString tPage = "page"; -static QString tPageset = "pageset"; -static QString tG = "g"; -static QString tSwitch = "switch"; -static QString tPolygon = "polygon"; -static QString tPolyline = "polyline"; -static QString tRect = "rect"; -static QString tSvg = "svg"; -static QString tText = "text"; -static QString tTextarea = "textarea"; -static QString tTspan = "tspan"; -static QString tBreak = "tbreak"; -static QString tImage = "image"; -static QString tFlash = "flash"; -static QString tAudio = "a"; -static QString tVideo = "video"; - -//attribute names definition -static QString aFill = "fill"; -static QString aFillopacity = "fill-opacity"; -static QString aX = "x"; -static QString aY = "y"; -static QString aWidth = "width"; -static QString aHeight = "height"; -static QString aStroke = "stroke"; -static QString aStrokewidth = "stroke-width"; -static QString aCx = "cx"; -static QString aCy = "cy"; -static QString aRx = "rx"; -static QString aRy = "ry"; -static QString aTransform = "transform"; -static QString aViewbox = "viewbox"; -static QString aFontSize = "font-size"; -static QString aFontfamily = "font-family"; -static QString aFontstretch = "font-stretch"; -static QString aFontstyle = "font-style"; -static QString aFontweight = "font-weight"; -static QString aTextalign = "text-align"; -static QString aPoints = "points"; -static QString svgNS = "http://www.w3.org/2000/svg"; -static QString iwbNS = "http://www.imsglobal.org/xsd/iwb_v1p0"; -static QString aId = "id"; -static QString aRef = "ref"; -static QString aHref = "href"; -static QString aBackground = "background"; -static QString aLocked = "locked"; -static QString aEditable = "editable"; - -//attributes part names -static QString apRotate = "rotate"; -static QString apTranslate = "translate"; - -UBCFFSubsetAdaptor::UBCFFSubsetAdaptor() -{} - -bool UBCFFSubsetAdaptor::ConvertCFFFileToUbz(QString &cffSourceFile, std::shared_ptr pDocument) -{ - //TODO - // fill document proxy metadata - // create persistance manager to save data using proxy - // create UBCFFSubsetReader and make it parse cffSourceFolder - QFile file(cffSourceFile); - - if (!file.open(QIODevice::ReadOnly)) - { - qWarning() << "Cannot open file " << cffSourceFile << " for reading ..."; - return false; - } - - UBCFFSubsetReader cffReader(pDocument, &file); - bool result = cffReader.parse(); - file.close(); - - return result; -} -UBCFFSubsetAdaptor::UBCFFSubsetReader::UBCFFSubsetReader(std::shared_ptrproxy, QFile *content) - : mProxy(proxy) - , mGSectionContainer(NULL) -{ - int errorLine, errorColumn; - QString errorStr; - if(!mDOMdoc.setContent(content, true, &errorStr, &errorLine, &errorColumn)){ - qWarning() << "Error:Parseerroratline" << errorLine << "," - << "column" << errorColumn << ":" << errorStr; - } else { - qDebug() << "well parsed to DOM"; - pwdContent = QFileInfo(content->fileName()).dir().absolutePath(); - } - qDebug() << "tmp path is" << pwdContent; -} -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parse() -{ - UBMetadataDcSubsetAdaptor::persist(mProxy); - - mIndent = ""; - if (!getTempFileName() || !createTempFlashPath()) - return false; - - if (mDOMdoc.isNull()) - return false; - - bool result = parseDoc(); - if (result) - result = mProxy->pageCount() != 0; - - if (QFile::exists(mTempFilePath)) - QFile::remove(mTempFilePath); - -// if (mTmpFlashDir.exists()) -// UBFileSystemUtils::deleteDir(mTmpFlashDir.path()); - - return result; -} - -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseGSection(const QDomElement &element) -{ - mGSectionContainer = new UBGraphicsGroupContainerItem(); - - QDomElement currentSvgElement = element.firstChildElement(); - while (!currentSvgElement.isNull()) { - parseSvgElement(currentSvgElement); - currentSvgElement = currentSvgElement.nextSiblingElement(); - } - - if (mGSectionContainer->childItems().count()) - { - mCurrentScene->addGroup(mGSectionContainer); - } - else - { - delete mGSectionContainer; - } - mGSectionContainer = NULL; - - return true; -} -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgSwitchSection(const QDomElement &element) -{ - - QDomElement currentSvgElement = element.firstChildElement(); - while (!currentSvgElement.isNull()) { - if (parseSvgElement(currentSvgElement)) - return true; - } - - return false; -} - -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgRect(const QDomElement &element) -{ - qreal x1 = element.attribute(aX).toDouble(); - qreal y1 = element.attribute(aY).toDouble(); - //rect dimensions - qreal width = element.attribute(aWidth).toDouble(); - qreal height = element.attribute(aHeight).toDouble(); - - QString textFillColor = element.attribute(aFill); - QString textStrokeColor = element.attribute(aStroke); - QString textStrokeWidth = element.attribute(aStrokewidth); - - QColor fillColor = !textFillColor.isNull() ? colorFromString(textFillColor) : QColor(); - QColor strokeColor = !textStrokeColor.isNull() ? colorFromString(textStrokeColor) : QColor(); - int strokeWidth = textStrokeWidth.toInt(); - - x1 -= strokeWidth/2; - y1 -= strokeWidth/2; - width += strokeWidth; - height += strokeWidth; - - //init svg generator with temp file - QSvgGenerator *generator = createSvgGenerator(width, height); - - //init painter to paint to svg - QPainter painter; - - painter.begin(generator); - - //fill rect - if (fillColor.isValid()) { - painter.setBrush(QBrush(fillColor)); - painter.fillRect(0, 0, width, height, fillColor); - } - QPen pen; - if (strokeColor.isValid()) { - pen.setColor(strokeColor); - } - if (strokeWidth) - pen.setWidth(strokeWidth); - painter.setPen(pen); - painter.drawRect(0, 0, width, height); - - painter.end(); - - UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); - - QString uuid = QUuid::createUuid().toString(); - mRefToUuidMap.insert(element.attribute(aId), uuid); - svgItem->setUuid(QUuid(uuid)); - - QTransform transform; - QString textTransform = element.attribute(aTransform); - - svgItem->resetTransform(); - if (!textTransform.isNull()) { - transform = transformFromString(textTransform, svgItem); - } - - repositionSvgItem(svgItem, width, height, x1, y1, transform); - hashSceneItem(element, svgItem); - - if (mGSectionContainer) - { - addItemToGSection(svgItem); - } - - delete generator; - - return true; -} -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgEllipse(const QDomElement &element) -{ - //ellipse horisontal and vertical radius - qreal rx = element.attribute(aRx).toDouble(); - qreal ry = element.attribute(aRy).toDouble(); - QSvgGenerator *generator = createSvgGenerator(rx * 2, ry * 2); - - //fill and stroke color - QColor fillColor = colorFromString(element.attribute(aFill)); - QColor strokeColor = colorFromString(element.attribute(aStroke)); - int strokeWidth = element.attribute(aStrokewidth).toInt(); - - //ellipse center coordinates - qreal cx = element.attribute(aCx).toDouble(); - qreal cy = element.attribute(aCy).toDouble(); - - //init painter to paint to svg - QPainter painter; - painter.begin(generator); - - QPen pen(strokeColor); - pen.setWidth(strokeWidth); - painter.setPen(pen); - painter.setBrush(QBrush(fillColor)); - - painter.drawEllipse(0, 0, rx * 2, ry * 2); - - painter.end(); - - UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); - - QString uuid = QUuid::createUuid().toString(); - mRefToUuidMap.insert(element.attribute(aId), uuid); - svgItem->setUuid(QUuid(uuid)); - - QTransform transform; - QString textTransform = element.attribute(aTransform); - - svgItem->resetTransform(); - if (!textTransform.isNull()) { - transform = transformFromString(textTransform, svgItem); - } - - - repositionSvgItem(svgItem, rx * 2, ry * 2, cx - 2*rx, cy+ry, transform); - hashSceneItem(element, svgItem); - - if (mGSectionContainer) - { - addItemToGSection(svgItem); - } - - delete generator; - - return true; -} -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolygon(const QDomElement &element) -{ - QString svgPoints = element.attribute(aPoints); - QPolygonF polygon; - - if (!svgPoints.isNull()) { - QStringList ts = svgPoints.split(QLatin1Char(' '), UB::SplitBehavior::SkipEmptyParts); - - foreach(const QString sPoint, ts) { - QStringList sCoord = sPoint.split(QLatin1Char(','), UB::SplitBehavior::SkipEmptyParts); - if (sCoord.size() == 2) { - QPointF point; - point.setX(sCoord.at(0).toFloat()); - point.setY(sCoord.at(1).toFloat()); - polygon << point; - } - else if (sCoord.size() == 4){ - //This is the case on system were the "," is used to seperate decimal - QPointF point; - QString x = sCoord.at(0) + "." + sCoord.at(1); - QString y = sCoord.at(2) + "." + sCoord.at(3); - point.setX(x.toFloat()); - point.setY(y.toFloat()); - polygon << point; - } - else { - qWarning() << "cannot make sense of a 'point' value" << sCoord; - } - } - } - - //bounding rect lef top corner coordinates - qreal x1 = polygon.boundingRect().topLeft().x(); - qreal y1 = polygon.boundingRect().topLeft().y(); - //bounding rect dimensions - qreal width = polygon.boundingRect().width(); - qreal height = polygon.boundingRect().height(); - - QString strokeColorText = element.attribute(aStroke); - QString fillColorText = element.attribute(aFill); - QString strokeWidthText = element.attribute(aStrokewidth); - - QColor strokeColor = !strokeColorText.isEmpty() ? colorFromString(strokeColorText) : QColor(); - QColor fillColor = !fillColorText.isEmpty() ? colorFromString(fillColorText) : QColor(); - int strokeWidth = strokeWidthText.toDouble(); - - QPen pen; - pen.setColor(strokeColor); - pen.setWidth(strokeWidth); - - QBrush brush; - brush.setColor(fillColor); - brush.setStyle(Qt::SolidPattern); - - - QUuid itemUuid(element.attribute(aId).right(QUuid().toString().length())); - QUuid itemGroupUuid(element.attribute(aId).left(QUuid().toString().length()-1)); - if (!itemUuid.isNull() && (itemGroupUuid!=itemUuid)) // reimported from UBZ - { - UBGraphicsPolygonItem *graphicsPolygon = mCurrentScene->polygonToPolygonItem(polygon); - - graphicsPolygon->setBrush(brush); - - QTransform transform; - QString textTransform = element.attribute(aTransform); - - graphicsPolygon->resetTransform(); - if (!textTransform.isNull()) { - transform = transformFromString(textTransform, graphicsPolygon); - } - mCurrentScene->addItem(graphicsPolygon); - - graphicsPolygon->setUuid(itemUuid); - mRefToUuidMap.insert(element.attribute(aId), itemUuid.toString()); - - } - else // single CFF - { - QSvgGenerator *generator = createSvgGenerator(width + pen.width(), height + pen.width()); - QPainter painter; - - painter.begin(generator); //drawing to svg tmp file - - painter.translate(pen.widthF() / 2 - x1, pen.widthF() / 2 - y1); - painter.setBrush(brush); - painter.setPen(pen); - painter.drawPolygon(polygon); - - painter.end(); - - //add resulting svg file to scene - UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); - QTransform transform; - QString textTransform = element.attribute(aTransform); - - QUuid uuid = QUuid::createUuid(); - mRefToUuidMap.insert(element.attribute(aId), uuid.toString()); - svgItem->setUuid(uuid); - - svgItem->resetTransform(); - if (!textTransform.isNull()) { - transform = transformFromString(textTransform, svgItem); - } - repositionSvgItem(svgItem, width +strokeWidth, height + strokeWidth, x1 - strokeWidth/2 + transform.m31(), y1 + strokeWidth/2 + transform.m32(), transform); - hashSceneItem(element, svgItem); - - if (mGSectionContainer) - { - addItemToGSection(svgItem); - } - - delete generator; - } - return true; -} -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolyline(const QDomElement &element) -{ - QString svgPoints = element.attribute(aPoints); - QPolygonF polygon; - - if (!svgPoints.isNull()) { - QStringList ts = svgPoints.split(QLatin1Char(' '), - UB::SplitBehavior::SkipEmptyParts); - - foreach(const QString sPoint, ts) { - QStringList sCoord = sPoint.split(QLatin1Char(','), UB::SplitBehavior::SkipEmptyParts); - if (sCoord.size() == 2) { - QPointF point; - point.setX(sCoord.at(0).toFloat()); - point.setY(sCoord.at(1).toFloat()); - polygon << point; - } - else if (sCoord.size() == 4){ - //This is the case on system were the "," is used to seperate decimal - QPointF point; - QString x = sCoord.at(0) + "." + sCoord.at(1); - QString y = sCoord.at(2) + "." + sCoord.at(3); - point.setX(x.toFloat()); - point.setY(y.toFloat()); - polygon << point; - } - else { - qWarning() << "cannot make sense of a 'point' value" << sCoord; - } - } - } - - //bounding rect lef top corner coordinates - qreal x1 = polygon.boundingRect().topLeft().x(); - qreal y1 = polygon.boundingRect().topLeft().y(); - - //bounding rect dimensions - qreal width = polygon.boundingRect().width(); - qreal height = polygon.boundingRect().height(); - - QString strokeColorText = element.attribute(aStroke); - QString strokeWidthText = element.attribute(aStrokewidth); - - QColor strokeColor = !strokeColorText.isEmpty() ? colorFromString(strokeColorText) : QColor(); - int strokeWidth = strokeWidthText.toDouble(); - - width += strokeWidth; - height += strokeWidth; - - QPen pen; - pen.setColor(strokeColor); - pen.setWidth(strokeWidth); - - QBrush brush; - brush.setColor(strokeColor); - brush.setStyle(Qt::SolidPattern); - - QUuid itemUuid(element.attribute(aId).right(QUuid().toString().length())); - QUuid itemGroupUuid(element.attribute(aId).left(QUuid().toString().length()-1)); - if (!itemUuid.isNull() && (itemGroupUuid!=itemUuid)) // reimported from UBZ - { - UBGraphicsPolygonItem *graphicsPolygon = new UBGraphicsPolygonItem(polygon); - - UBGraphicsStroke *stroke = new UBGraphicsStroke(); - graphicsPolygon->setStroke(stroke); - - graphicsPolygon->setBrush(brush); - QTransform transform; - QString textTransform = element.attribute(aTransform); - - graphicsPolygon->resetTransform(); - if (!textTransform.isNull()) { - transform = transformFromString(textTransform, graphicsPolygon); - } - mCurrentScene->addItem(graphicsPolygon); - - graphicsPolygon->setUuid(itemUuid); - mRefToUuidMap.insert(element.attribute(aId), itemUuid.toString()); - - } - else // simple CFF - { - QSvgGenerator *generator = createSvgGenerator(width + pen.width(), height + pen.width()); - QPainter painter; - - painter.begin(generator); //drawing to svg tmp file - - painter.translate(pen.widthF() / 2 - x1, pen.widthF() / 2 - y1); - painter.setBrush(brush); - painter.setPen(pen); - painter.drawPolygon(polygon); - - painter.end(); - - //add resulting svg file to scene - UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); - - QString uuid = QUuid::createUuid().toString(); - mRefToUuidMap.insert(element.attribute(aId), uuid); - svgItem->setUuid(QUuid(uuid)); - - QTransform transform; - QString textTransform = element.attribute(aTransform); - - svgItem->resetTransform(); - if (!textTransform.isNull()) { - transform = transformFromString(textTransform, svgItem); - } - repositionSvgItem(svgItem, width +strokeWidth, height + strokeWidth, x1 - strokeWidth/2 + transform.m31(), y1 + strokeWidth/2 + transform.m32(), transform); - hashSceneItem(element, svgItem); - - if (mGSectionContainer) - { - addItemToGSection(svgItem); - } - - delete generator; - } - - - return true; -} -void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseTextAttributes(const QDomElement &element, - qreal &fontSize, QColor &fontColor, QString &fontFamily, - QString &fontStretch, bool &italic, int &fontWeight, - int &textAlign, QTransform &fontTransform) -{ - //consider inch has 72 lines - //since svg font size is given in pixels, divide it by pixels per line - QString fontSz = element.attribute(aFontSize); - if (!fontSz.isNull()) - fontSize = fontSz.toDouble() * 72. / UBApplication::displayManager->logicalDpi(ScreenRole::Control); - - QString fontColorText = element.attribute(aFill); - if (!fontColorText.isNull()) fontColor = colorFromString(fontColorText); - - QString fontFamilyText = element.attribute(aFontfamily); - if (!fontFamilyText.isNull()) fontFamily = fontFamilyText; - - QString fontStretchText = element.attribute(aFontstretch); - if (!fontStretchText.isNull()) fontStretch = fontStretchText; - - if (!element.attribute(aFontstyle).isNull()) - italic = (element.attribute(aFontstyle) == "italic"); - - QString weight = element.attribute(aFontweight); - if (!weight.isNull()) { - if (weight == "normal") fontWeight = QFont::Normal; - else if (weight == "light") fontWeight = QFont::Light; - else if (weight == "demibold") fontWeight = QFont::DemiBold; - else if (weight == "bold") fontWeight = QFont::Bold; - else if (weight == "black") fontWeight = QFont::Black; - } - QString align = element.attribute(aTextalign); - if (!align.isNull()) { - if (align == "middle" || align == "center") textAlign = Qt::AlignHCenter; - else if (align == "start") textAlign = Qt::AlignLeft; - else if (align == "end") textAlign = Qt::AlignRight; - } - - if (!element.attribute(aTransform).isNull()) - fontTransform = transformFromString(element.attribute(aTransform)); -} -void UBCFFSubsetAdaptor::UBCFFSubsetReader::readTextBlockAttr(const QDomElement &element, QTextBlockFormat &format) -{ - QString fontStretchText = element.attribute(aFontstretch); - if (!fontStretchText.isNull()) format.setAlignment(Qt::AlignJustify); - - QString align = element.attribute(aTextalign); - if (!align.isNull()) { - if (align == "middle" || align == "center") format.setAlignment(Qt::AlignHCenter); - else if (align == "start") format.setAlignment(Qt::AlignLeft); - else if (align == "end") format.setAlignment(Qt::AlignRight); - else if (align == "justify") format.setAlignment(Qt::AlignJustify); - } -} -void UBCFFSubsetAdaptor::UBCFFSubsetReader::readTextCharAttr(const QDomElement &element, QTextCharFormat &format) -{ - QString fontSz = element.attribute(aFontSize); - if (!fontSz.isNull()) { - qreal fontSize = fontSz.remove("pt").toDouble(); - format.setFontPointSize(fontSize); - } - QString fontColorText = element.attribute(aFill); - if (!fontColorText.isNull()) { - QColor fontColor = colorFromString(fontColorText); - if (fontColor.isValid()) format.setForeground(fontColor); - } - QString fontFamilyText = element.attribute(aFontfamily); - if (!fontFamilyText.isNull()) { -#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) - format.setFontFamilies(QStringList(fontFamilyText)); -#else - format.setFontFamily(fontFamilyText); -#endif - } - if (!element.attribute(aFontstyle).isNull()) { - bool italic = (element.attribute(aFontstyle) == "italic"); - format.setFontItalic(italic); - } - QString weight = element.attribute(aFontweight); - if (!weight.isNull()) { - if (weight == "normal") format.setFontWeight(QFont::Normal); - else if (weight == "light") format.setFontWeight(QFont::Light); - else if (weight == "demibold") format.setFontWeight(QFont::DemiBold); - else if (weight == "bold") format.setFontWeight(QFont::Bold); - else if (weight == "black") format.setFontWeight(QFont::Black); - } -} - -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgText(const QDomElement &element) -{ - qreal x = element.attribute(aX).toDouble(); - qreal y = element.attribute(aY).toDouble(); - qreal width = element.attribute(aWidth).toDouble(); - qreal height = element.attribute(aHeight).toDouble(); - - - qreal fontSize = 12; - QColor fontColor(qApp->palette().windowText().color()); - QString fontFamily = "Arial"; - QString fontStretch = "normal"; - bool italic = false; - int fontWeight = QFont::Normal; - int textAlign = Qt::AlignLeft; - QTransform fontTransform; - parseTextAttributes(element, fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform); - - QFont startFont(fontFamily, fontSize, fontWeight, italic); - height = QFontMetrics(startFont).height(); - width = QFontMetrics(startFont).boundingRect(element.text()).width() + 5; - - QSvgGenerator *generator = createSvgGenerator(width, height); - QPainter painter; - painter.begin(generator); - painter.setFont(startFont); - - qreal curY = 0.0; - qreal curX = 0.0; - qreal linespacing = QFontMetricsF(painter.font()).leading(); - -// remember if text area has transform -// QString transformString; - QTransform transform = fontTransform; - - QRectF lastDrawnTextBoundingRect; - //parse text area tags - - //recursive call any tspan in text svg element - parseTSpan(element, painter - , curX, curY, width, height, linespacing, lastDrawnTextBoundingRect - , fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform); - - painter.end(); - - //add resulting svg file to scene - UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); - - QString uuid = QUuid::createUuid().toString(); - mRefToUuidMap.insert(element.attribute(aId), uuid); - svgItem->setUuid(QUuid(uuid)); - - svgItem->resetTransform(); - repositionSvgItem(svgItem, width, height, x + transform.m31(), y + transform.m32(), transform); - hashSceneItem(element, svgItem); - - if (mGSectionContainer) - { - addItemToGSection(svgItem); - } - - delete generator; - return true; -} - -void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseTSpan(const QDomElement &parent, QPainter &painter - , qreal &curX, qreal &curY, qreal &width, qreal &height, qreal &linespacing, QRectF &lastDrawnTextBoundingRect - , qreal &fontSize, QColor &fontColor, QString &fontFamily, QString &fontStretch, bool &italic - , int &fontWeight, int &textAlign, QTransform &fontTransform) -{ - QDomNode curNode = parent.firstChild(); - while (!curNode.isNull()) { - if (curNode.toElement().tagName() == tTspan) { - QDomElement curTSpan = curNode.toElement(); - parseTextAttributes(curTSpan, fontSize, fontColor, fontFamily, fontStretch, italic - , fontWeight, textAlign, fontTransform); - painter.setFont(QFont(fontFamily, fontSize, fontWeight, italic)); - painter.setPen(fontColor); - linespacing = QFontMetricsF(painter.font()).leading(); - parseTSpan(curTSpan, painter - , curX, curY, width, height, linespacing, lastDrawnTextBoundingRect - , fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform); - } else if (curNode.nodeType() == QDomNode::CharacterDataNode - || curNode.nodeType() == QDomNode::CDATASectionNode - || curNode.nodeType() == QDomNode::TextNode) { - - QDomCharacterData textData = curNode.toCharacterData(); - QString text = textData.data().trimmed(); -// width = painter.fontMetrics().width(text); - //get bounding rect to obtain desired text height - lastDrawnTextBoundingRect = painter.boundingRect(QRectF(curX, curY, width, height - curY), textAlign|Qt::TextWordWrap, text); - painter.drawText(curX, curY, width, lastDrawnTextBoundingRect.height(), textAlign|Qt::TextWordWrap, text); - curX += lastDrawnTextBoundingRect.x() + lastDrawnTextBoundingRect.width(); - } else if (curNode.nodeType() == QDomNode::ElementNode - && curNode.toElement().tagName() == tBreak) { - - curY += lastDrawnTextBoundingRect.height() + linespacing; - curX = 0.0; - lastDrawnTextBoundingRect = QRectF(0,0,0,0); - } - curNode = curNode.nextSibling(); - } -} -void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseTSpan(const QDomElement &element, QTextCursor &cursor - , QTextBlockFormat &blockFormat, QTextCharFormat &charFormat) -{ - QDomNode curNode = element.firstChild(); - while (!curNode.isNull()) { - if (curNode.toElement().tagName() == tTspan) { - QDomElement curTspan = curNode.toElement(); - readTextBlockAttr(curTspan, blockFormat); - readTextCharAttr(curTspan, charFormat); - cursor.setBlockFormat(blockFormat); - cursor.setCharFormat(charFormat); - parseTSpan(curTspan, cursor, blockFormat, charFormat); - - } else if (curNode.nodeType() == QDomNode::CharacterDataNode - || curNode.nodeType() == QDomNode::CDATASectionNode - || curNode.nodeType() == QDomNode::TextNode) { - - QDomCharacterData textData = curNode.toCharacterData(); - QString text = textData.data().trimmed(); - cursor.insertText(text, charFormat); - - } else if (curNode.nodeType() == QDomNode::ElementNode - && curNode.toElement().tagName() == tBreak) { - cursor.insertBlock(); - } - curNode = curNode.nextSibling(); - } -} - -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgTextarea(const QDomElement &element) -{ - qreal x = element.attribute(aX).toDouble(); - qreal y = element.attribute(aY).toDouble(); - qreal width = element.attribute(aWidth).toDouble(); - qreal height = element.attribute(aHeight).toDouble(); - - QTextBlockFormat blockFormat; - blockFormat.setAlignment(Qt::AlignLeft); - - QTextCharFormat textFormat; - // default values - textFormat.setFontPointSize(12); - textFormat.setForeground(qApp->palette().windowText().color()); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) - textFormat.setFontFamilies(QStringList("Arial")); -#else - textFormat.setFontFamily("Arial"); -#endif - textFormat.setFontItalic(false); - textFormat.setFontWeight(QFont::Normal); - - // readed values - readTextBlockAttr(element, blockFormat); - readTextCharAttr(element, textFormat); - - QTextDocument doc; - doc.setPlainText(""); - QTextCursor tCursor(&doc); - tCursor.setBlockFormat(blockFormat); - tCursor.setCharFormat(textFormat); - - parseTSpan(element, tCursor, blockFormat, textFormat); - - UBGraphicsTextItem *svgItem = mCurrentScene->addTextHtml(doc.toHtml()); - svgItem->resize(width, height); - - QString uuid = QUuid::createUuid().toString(); - mRefToUuidMap.insert(element.attribute(aId), uuid); - svgItem->setUuid(QUuid(uuid)); - - QTransform transform; - QString textTransform = element.attribute(aTransform); - - svgItem->resetTransform(); - if (!textTransform.isNull()) { - transform = transformFromString(textTransform, svgItem); - } - - //by default all the textAreas are not editable - UBGraphicsTextItemDelegate *curDelegate = dynamic_cast(svgItem->Delegate()); - if (curDelegate) { - curDelegate->setEditable(false); - } - - repositionSvgItem(svgItem, width, height, x + transform.m31(), y + transform.m32(), transform); - hashSceneItem(element, svgItem); - - if (mGSectionContainer) - { - addItemToGSection(svgItem); - } - - return true; -} -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgImage(const QDomElement &element) -{ - qreal x = element.attribute(aX).toDouble(); - qreal y = element.attribute(aY).toDouble(); - qreal width = element.attribute(aWidth).toDouble(); - qreal height = element.attribute(aHeight).toDouble(); - - QString itemRefPath = element.attribute(aHref); - - QPixmap pix; - if (!itemRefPath.isNull()) { - QString imagePath = pwdContent + "/" + itemRefPath; - if (!QFile::exists(imagePath)) { - qDebug() << "can't load file" << pwdContent + "/" + itemRefPath << "maybe file corrupted"; - return false; - } else { -// qDebug() << "size of file" << itemRefPath << QFileInfo(itemRefPath).size(); - } - pix.load(imagePath); - if (pix.isNull()) { - qDebug() << "can't create pixmap for file" << pwdContent + "/" + itemRefPath << "maybe format does not supported"; - } - } - - UBGraphicsPixmapItem *pixItem = mCurrentScene->addPixmap(pix, NULL); - - QString uuid = QUuid::createUuid().toString(); - mRefToUuidMap.insert(element.attribute(aId), uuid); - pixItem->setUuid(QUuid(uuid)); - - QTransform transform; - QString textTransform = element.attribute(aTransform); - - pixItem->resetTransform(); - if (!textTransform.isNull()) { - transform = transformFromString(textTransform, pixItem); - } - repositionSvgItem(pixItem, width, height, x + transform.m31(), y + transform.m32(), transform); - hashSceneItem(element, pixItem); - - if (mGSectionContainer) - { - addItemToGSection(pixItem); - } - - return true; -} -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgFlash(const QDomElement &element) -{ - QString itemRefPath = element.attribute(aHref); - - qreal x = element.attribute(aX).toDouble(); - qreal y = element.attribute(aY).toDouble(); - qreal width = element.attribute(aWidth).toDouble(); - qreal height = element.attribute(aHeight).toDouble(); - - QUrl urlPath; - QString flashPath; - if (!itemRefPath.isNull()) { - flashPath = pwdContent + "/" + itemRefPath; - if (!QFile::exists(flashPath)) { - qDebug() << "can't load file" << pwdContent + "/" + itemRefPath << "maybe file corrupted"; - return false; - } - urlPath = QUrl::fromLocalFile(flashPath); - } - QDir tmpFlashDir(mTmpFlashDir); - if (!tmpFlashDir.exists()) { - qDebug() << "Can't create temporary directory to put flash"; - return false; - } - - QString flashUrl = UBGraphicsW3CWidgetItem::createNPAPIWrapperInDir(flashPath, tmpFlashDir, "application/x-shockwave-flash" - ,QSize(mCurrentSceneRect.width(), mCurrentSceneRect.height())); - UBGraphicsWidgetItem *flashItem = mCurrentScene->addW3CWidget(QUrl::fromLocalFile(flashUrl)); - flashItem->setSourceUrl(urlPath); - - QString uuid = QUuid::createUuid().toString(); - mRefToUuidMap.insert(element.attribute(aId), uuid); - flashItem->setUuid(QUuid(uuid)); - - QTransform transform; - QString textTransform = element.attribute(aTransform); - - flashItem->resetTransform(); - if (!textTransform.isNull()) { - transform = transformFromString(textTransform, flashItem); - } - repositionSvgItem(flashItem, width, height, x + transform.m31(), y + transform.m32(), transform); - hashSceneItem(element, flashItem); - - if (mGSectionContainer) - { - addItemToGSection(flashItem); - } - - return true; -} - -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgAudio(const QDomElement &element) -{ - QDomElement parentOfAudio = element.firstChild().toElement(); - - qreal x = parentOfAudio.attribute(aX).toDouble(); - qreal y = parentOfAudio.attribute(aY).toDouble(); - - QString itemRefPath = element.attribute(aHref); - - QUrl concreteUrl; - if (!itemRefPath.isNull()) { - QString audioPath = pwdContent + "/" + itemRefPath; - if (!QFile::exists(audioPath)) { - qDebug() << "can't load file" << pwdContent + "/" + itemRefPath << "maybe file corrupted"; - return false; - } - concreteUrl = QUrl::fromLocalFile(audioPath); - } - - QString uuid = QUuid::createUuid().toString(); - mRefToUuidMap.insert(element.attribute(aId), uuid); - - QString destFile; - bool b = UBPersistenceManager::persistenceManager()->addFileToDocument( - mCurrentScene->document(), - concreteUrl.toLocalFile(), - UBPersistenceManager::audioDirectory, - QUuid(uuid), - destFile); - if (!b) - { - return false; - } - concreteUrl = QUrl::fromLocalFile(destFile); - - UBGraphicsMediaItem *audioItem = mCurrentScene->addAudio(concreteUrl, false); - - QTransform transform; - QString textTransform = parentOfAudio.attribute(aTransform); - - audioItem->resetTransform(); - if (!textTransform.isNull()) { - transform = transformFromString(textTransform, audioItem); - } - repositionSvgItem(audioItem, audioItem->boundingRect().width(), audioItem->boundingRect().height(), x + transform.m31(), y + transform.m32(), transform); - hashSceneItem(element, audioItem); - - if (mGSectionContainer) - { - addItemToGSection(audioItem); - } - - return true; -} -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgVideo(const QDomElement &element) -{ - QString itemRefPath = element.attribute(aHref); - if (itemRefPath.startsWith(tFlash + "/") && itemRefPath.endsWith(".swf")) { - if (parseSvgFlash(element)) return true; - else return false; - } - qreal x = element.attribute(aX).toDouble(); - qreal y = element.attribute(aY).toDouble(); - - QUrl concreteUrl; - if (!itemRefPath.isNull()) { - QString videoPath = pwdContent + "/" + itemRefPath; - if (!QFile::exists(videoPath)) { - qDebug() << "can't load file" << pwdContent + "/" + itemRefPath << "maybe file corrupted"; - return false; - } - concreteUrl = QUrl::fromLocalFile(videoPath); - } - - QString uuid = QUuid::createUuid().toString(); - mRefToUuidMap.insert(element.attribute(aId), uuid); - - QString destFile; - bool b = UBPersistenceManager::persistenceManager()->addFileToDocument( - mCurrentScene->document(), - concreteUrl.toLocalFile(), - UBPersistenceManager::videoDirectory, - QUuid(uuid), - destFile); - if (!b) - { - return false; - } - concreteUrl = QUrl::fromLocalFile(destFile); - - UBGraphicsMediaItem *videoItem = mCurrentScene->addVideo(concreteUrl, false); - - QTransform transform; - QString textTransform = element.attribute(aTransform); - - videoItem->resetTransform(); - if (!textTransform.isNull()) { - transform = transformFromString(textTransform, videoItem); - } - repositionSvgItem(videoItem, videoItem->boundingRect().width(), videoItem->boundingRect().height(), x + transform.m31(), y + transform.m32(), transform); - hashSceneItem(element, videoItem); - - if (mGSectionContainer) - { - addItemToGSection(videoItem); - } - - return true; -} - -void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgSectionAttr(const QDomElement &svgSection) -{ - getViewBoxDimenstions(svgSection.attribute(aViewbox)); - mSize = QSize(svgSection.attribute(aWidth).toInt(), - svgSection.attribute(aHeight).toInt()); -} - -void UBCFFSubsetAdaptor::UBCFFSubsetReader::addItemToGSection(QGraphicsItem *item) -{ - mGSectionContainer->addToGroup(item); -} - -void UBCFFSubsetAdaptor::UBCFFSubsetReader::hashSceneItem(const QDomElement &element, UBGraphicsItem *item) -{ -// adding element pointer to hash to refer if needed - QString key = element.attribute(aId); - if (!key.isNull()) { - persistedItems.insert(key, item); - } -} - -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgElement(const QDomElement &parent) -{ - QString tagName = parent.tagName(); - if (parent.namespaceURI() != svgNS) { - qWarning() << "Incorrect namespace, error at content file, line number" << parent.lineNumber(); - //return false; - } - - if (tagName == tG && !parseGSection(parent)) return false; - else if (tagName == tSwitch && !parseSvgSwitchSection(parent)) return false; - else if (tagName == tRect && !parseSvgRect(parent)) return false; - else if (tagName == tEllipse && !parseSvgEllipse(parent)) return false; - else if (tagName == tPolygon && !parseSvgPolygon(parent)) return false; - else if (tagName == tPolyline && !parseSvgPolyline(parent)) return false; - else if (tagName == tText && !parseSvgText(parent)) return false; - else if (tagName == tTextarea && !parseSvgTextarea(parent)) return false; - else if (tagName == tImage && !parseSvgImage(parent)) return false; - else if (tagName == tFlash && !parseSvgFlash(parent)) return false; - else if (tagName == tAudio && !parseSvgAudio(parent)) return false; - else if (tagName == tVideo && !parseSvgVideo(parent)) return false; - - return true; -} - -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPage(const QDomElement &parent) -{ - createNewScene(); - QDomElement currentSvgElement = parent.firstChildElement(); - while (!currentSvgElement.isNull()) { - if (!parseSvgElement(currentSvgElement)) - return false; - - currentSvgElement = currentSvgElement.nextSiblingElement(); - } - - return true; -} -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPageset(const QDomElement &parent) -{ - QDomElement currentPage = parent.firstChildElement(tPage); - while (!currentPage.isNull()) { - if (!parseSvgPage(currentPage)) - return false; - currentPage = currentPage.nextSiblingElement(tPage); - } - return true; -} - -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseIwbMeta(const QDomElement &element) -{ - if (element.namespaceURI() != iwbNS) { - qWarning() << "incorrect meta namespace, incorrect document"; - //return false; - } - - return true; -} -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvg(const QDomElement &svgSection) -{ - if (svgSection.namespaceURI() != svgNS) { - qWarning() << "incorrect svg namespace, incorrect document"; - // return false; - } - - parseSvgSectionAttr(svgSection); - QDomElement currentSvg = svgSection.firstChildElement(); - - if (currentSvg.tagName() != tPageset) { - parseSvgPage(svgSection); - } else if (currentSvg.tagName() == tPageset){ - parseSvgPageset(currentSvg); - } - - return true; -} - -UBGraphicsGroupContainerItem *UBCFFSubsetAdaptor::UBCFFSubsetReader::parseIwbGroup(QDomElement &parent) -{ - //TODO. Create groups from elements parsed by parseIwbElement() function - if (parent.namespaceURI() != iwbNS) { - qWarning() << "incorrect iwb group namespace, incorrect document"; - // return false; - } - - UBGraphicsGroupContainerItem *group = new UBGraphicsGroupContainerItem(); - QMultiMap strokesGroupsContainer; - QList groupContainer; - QString currentStrokeIdentifier; - - QDomElement currentStrokeElement = parent.firstChildElement(); - while (!currentStrokeElement.isNull()) - { - if (tGroup == currentStrokeElement.tagName()) - group->addToGroup(parseIwbGroup(currentStrokeElement)); - else - { - - QString ref = currentStrokeElement.attribute(aRef); - QString uuid = mRefToUuidMap[ref]; - if (!uuid.isEmpty()) - { - if (ref.size() > QUuid().toString().length()) // create stroke group - { - currentStrokeIdentifier = ref.left(QUuid().toString().length()-1); - UBGraphicsPolygonItem *strokeByUuid = qgraphicsitem_cast(mCurrentScene->itemForUuid(QUuid(ref.right(QUuid().toString().length())))); - - if (strokeByUuid) - strokesGroupsContainer.insert(currentStrokeIdentifier, strokeByUuid); - } - else // single elements in group - groupContainer.append(mCurrentScene->itemForUuid(QUuid(uuid))); - } - } - currentStrokeElement = currentStrokeElement.nextSiblingElement(); - } - - - - const auto keys = strokesGroupsContainer.keys(); - for (const QString &key : keys) - { - UBGraphicsStrokesGroup* pStrokesGroup = new UBGraphicsStrokesGroup(); - UBGraphicsStroke *currentStroke = new UBGraphicsStroke(); - foreach(UBGraphicsPolygonItem* poly, strokesGroupsContainer.values(key)) - { - if (poly) - { - mCurrentScene->removeItem(poly); - mCurrentScene->removeItemFromDeletion(poly); - poly->setStrokesGroup(pStrokesGroup); - poly->setStroke(currentStroke); - pStrokesGroup->addToGroup(poly); - } - } - if (currentStroke->polygons().empty()) - delete currentStroke; - - if (pStrokesGroup->childItems().count()) - mCurrentScene->addItem(pStrokesGroup); - else - { - delete pStrokesGroup; - pStrokesGroup = nullptr; - } - - if (pStrokesGroup) - { - QGraphicsItem *strokeGroup = qgraphicsitem_cast(pStrokesGroup); - groupContainer.append(strokeGroup); - } - } - - foreach(QGraphicsItem* item, groupContainer) - group->addToGroup(item); - - if (group->childItems().count()) - { - mCurrentScene->addItem(group); - - if (1 == group->childItems().count()) - { - group->destroy(false); - } - } - - return group; -} - -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::strToBool(QString str) -{ - return str == "true"; -} - -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseIwbElement(QDomElement &element) -{ - if (element.namespaceURI() != iwbNS) { - qWarning() << "incorrect iwb element namespace, incorrect document"; - // return false; - } - - bool locked = false; - bool isEditableItem = false; - bool isEditable = false; //Text items to convert to UBGraphicsTextItem only - - QString IDRef = element.attribute(aRef); - if (!IDRef.isNull()) { - element.hasAttribute(aBackground) ? strToBool(element.attribute(aBackground)) : false; - locked = element.hasAttribute(aBackground) ? strToBool(element.attribute(aBackground)) : false; - isEditableItem = element.hasAttribute(aEditable); - if (isEditableItem) - isEditable = strToBool(element.attribute(aEditable)); - - UBGraphicsItem *referedItem(0); - QHash::iterator iReferedItem; - iReferedItem = persistedItems.find(IDRef); - if (iReferedItem != persistedItems.end()) { - referedItem = *iReferedItem; - referedItem->Delegate()->lock(locked); - } - if (isEditableItem) { - UBGraphicsTextItemDelegate *textDelegate = dynamic_cast(referedItem->Delegate()); - if (textDelegate) { - textDelegate->setEditable(isEditable); - } - } - } - - return true; -} -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseDoc() -{ - QDomElement currentTopElement = mDOMdoc.documentElement().firstChildElement(); - while (!currentTopElement.isNull()) { - QString tagName = currentTopElement.tagName(); - if (tagName == tMeta && !parseIwbMeta(currentTopElement)) return false; - else if (tagName == tSvg && !parseSvg(currentTopElement)) return false; - else if (tagName == tGroup && !parseIwbGroup(currentTopElement)) return false; - else if (tagName == tElement && !parseIwbElement(currentTopElement)) return false; - - currentTopElement = currentTopElement.nextSiblingElement(); - } - if (!persistScenes()) return false; - - return true; -} - -void UBCFFSubsetAdaptor::UBCFFSubsetReader::repositionSvgItem(QGraphicsItem *item, qreal width, qreal height, - qreal x, qreal y, - QTransform &transform) -{ - //First using viebox coordinates, then translate them to scene coordinates - - QRectF itemBounds = item->boundingRect(); - - qreal xScale = width / itemBounds.width(); - qreal yScale = height / itemBounds.height(); - - qreal fullScaleX = mVBTransFactor * xScale; - qreal fullScaleY = mVBTransFactor * yScale; - - QPointF oldVector((x - transform.dx()), (y - transform.dy())); - QTransform rTransform; - QPointF newVector = rTransform.map(oldVector); - - QTransform tr = item->sceneTransform(); - item->setTransform(rTransform.scale(fullScaleX, fullScaleY), true); - tr = item->sceneTransform(); - QPoint pos; - if (UBGraphicsTextItem::Type == item->type()) - pos = QPoint((int)((x + mShiftVector.x() + (newVector - oldVector).x())), (int)((y +mShiftVector.y() + (newVector - oldVector).y()) * mVBTransFactor)); - else - pos = QPoint((int)((x + mShiftVector.x() + (newVector - oldVector).x()) * mVBTransFactor), (int)((y +mShiftVector.y() + (newVector - oldVector).y()) * mVBTransFactor)); - - - item->setPos(pos); -} - -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::createNewScene() -{ - mCurrentScene = UBPersistenceManager::persistenceManager()->createDocumentSceneAt(mProxy, mProxy->pageCount(), false); - mCurrentScene->setSceneRect(mViewBox); - if ((mCurrentScene->sceneRect().topLeft().x() >= 0) || (mCurrentScene->sceneRect().topLeft().y() >= 0)) { - mShiftVector = -mViewBox.center(); - } - mCurrentSceneRect = mViewBox; - mVBTransFactor = qMin(mCurrentScene->normalizedSceneRect().width() / mViewPort.width(), - mCurrentScene->normalizedSceneRect().height() / mViewPort.height()); - return true; -} - -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::persistCurrentScene() -{ - if (mCurrentScene != 0 && mCurrentScene->isModified()) - { - UBThumbnailAdaptor::persistScene(mProxy, mCurrentScene, mProxy->pageCount() - 1); - UBSvgSubsetAdaptor::persistScene(mProxy, mCurrentScene, mProxy->pageCount() - 1); - - mCurrentScene->setModified(false); - mCurrentScene = 0; - } - return true; -} -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::persistScenes() -{ - if (!mProxy->pageCount()) { - qDebug() << "No pages created"; - return false; - } - for (int i = 0; i < mProxy->pageCount(); i++) { - mCurrentScene = UBPersistenceManager::persistenceManager()->getDocumentScene(mProxy, i); - if (!mCurrentScene) { - qDebug() << "can't allocate scene, loading failed"; - return false; - } - - UBSvgSubsetAdaptor::persistScene(mProxy, mCurrentScene, i); - std::shared_ptr tmpScene = UBSvgSubsetAdaptor::loadScene(mProxy, i); - tmpScene->setModified(true); - UBThumbnailAdaptor::persistScene(mProxy, tmpScene, i); - mCurrentScene->setModified(false); - } - - return true; -} - -QColor UBCFFSubsetAdaptor::UBCFFSubsetReader::colorFromString(const QString& clrString) -{ - //init regexp with pattern - //pattern corresponds to strings like 'rgb(1,2,3) or rgb(10%,20%,30%)' - static const QRegularExpression regexp(QRegularExpression::anchoredPattern("rgb\\(([0-9]+%{0,1}),([0-9]+%{0,1}),([0-9]+%{0,1})\\)")); - QRegularExpressionMatch match = regexp.match(clrString); - if (match.hasMatch()) - { - if (match.lastCapturedIndex() == 3 && match.capturedTexts().at(0).length() == clrString.length()) - { - int r = match.capturedTexts().at(1).toInt(); - if (match.capturedTexts().at(1).indexOf("%") != -1) - r = r * 255 / 100; - int g = match.capturedTexts().at(2).toInt(); - if (match.capturedTexts().at(2).indexOf("%") != -1) - g = g * 255 / 100; - int b = match.capturedTexts().at(3).toInt(); - if (match.capturedTexts().at(3).indexOf("%") != -1) - b = b * 255 / 100; - return QColor(r, g, b); - } - else - return QColor(); - } - else - return QColor(clrString); -} - -QTransform UBCFFSubsetAdaptor::UBCFFSubsetReader::transformFromString(const QString trString, QGraphicsItem *item) -{ - qreal dxr = 0.0; - qreal dyr = 0.0; - qreal dx = 0.0; - qreal dy = 0.0; - qreal angle = 0.0; - QTransform tr; - - foreach(QString trStr, trString.split(" ", UB::SplitBehavior::SkipEmptyParts)) - { - //check pattern for strings like 'rotate(10)' - static const QRegularExpression rotate1(QRegularExpression::anchoredPattern("rotate\\( *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *\\)")); - QRegularExpressionMatch match = rotate1.match(trStr); - if (match.hasMatch()) { - angle = match.capturedTexts().at(1).toDouble(); - if (item) - { - item->setTransformOriginPoint(QPointF(0, 0)); - item->setRotation(angle); - } - continue; - }; - - //check pattern for strings like 'rotate(10,20,20)' or 'rotate(10.1,10.2,34.2)' - static const QRegularExpression rotate3(QRegularExpression::anchoredPattern("rotate\\( *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *, *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *, *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *\\)")); - match = rotate3.match(trStr); - if (match.hasMatch()) { - angle = match.capturedTexts().at(1).toDouble(); - dxr = match.capturedTexts().at(2).toDouble(); - dyr = match.capturedTexts().at(3).toDouble(); - if (item) - { - item->setTransformOriginPoint(QPointF(dxr, dyr)-item->pos()); - item->setRotation(angle); - } - continue; - } - - //check pattern for strings like 'translate(11.0, 12.34)' - static const QRegularExpression translate2(QRegularExpression::anchoredPattern("translate\\( *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *,*([-+]{0,1}[0-9]*\\.{0,1}[0-9]*)*\\)")); - match = translate2.match(trStr); - if (match.hasMatch()) { - dx = match.capturedTexts().at(1).toDouble(); - dy = match.capturedTexts().at(2).toDouble(); - tr.translate(dx,dy); - continue; - } - } - return tr; -} - -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::getViewBoxDimenstions(const QString& viewBox) -{ - QStringList capturedTexts = viewBox.split(" ", UB::SplitBehavior::SkipEmptyParts); - if (capturedTexts.count()) - { - if (4 == capturedTexts.count()) - { - mViewBox = QRectF(capturedTexts.at(0).toDouble(), capturedTexts.at(1).toDouble(), capturedTexts.at(2).toDouble(), capturedTexts.at(3).toDouble()); - mViewPort = mViewBox; - mViewPort.translate(- mViewPort.center()); - mViewBoxCenter.setX(mViewBox.width() / 2); - mViewBoxCenter.setY(mViewBox.height() / 2); - - return true; - } - } - - mViewBox = QRectF(0, 0, 1000, 1000); - mViewBoxCenter = QPointF(500, 500); - return false; -} - -QSvgGenerator* UBCFFSubsetAdaptor::UBCFFSubsetReader::createSvgGenerator(qreal width, qreal height) -{ - QSvgGenerator* generator = new QSvgGenerator(); -// qWarning() << QString("Making generator with file %1, size (%2, %3) and viewbox (%4 %5 %6 %7)").arg(mTempFilePath) -// .arg(width).arg(height).arg(0.0).arg(0.0).arg(width).arg(width); - generator->setResolution(UBApplication::displayManager->logicalDpi(ScreenRole::Control)); - generator->setFileName(mTempFilePath); - generator->setSize(QSize(width, height)); - generator->setViewBox(QRectF(0, 0, width, height)); - - return generator; -} - -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::getTempFileName() -{ - int tmpNumber = 0; - QDir rootDir; - while (true) - { - mTempFilePath = QString("%1/sanksvg%2.%3") - .arg(rootDir.tempPath()) - .arg(QDateTime::currentDateTime().toString("dd_MM_yyyy_HH-mm")) - .arg(tmpNumber); - if (!QFile::exists(mTempFilePath)) - return true; - tmpNumber++; - if (tmpNumber == 100000) - { - qWarning() << "Import failed. Failed to create temporary file for svg objects"; - return false; - } - } -} -bool UBCFFSubsetAdaptor::UBCFFSubsetReader::createTempFlashPath() -{ - int tmpNumber = 0; - QDir systemTmp = QDir::temp(); - - while (true) { - QString dirName = QString("SankTmpFlash%1.%2") - .arg(QDateTime::currentDateTime().toString("dd_MM_yyyy_HH-mm")) - .arg(tmpNumber++); - if (!systemTmp.exists(dirName)) { - if (systemTmp.mkdir(dirName)) { - mTmpFlashDir = QDir(systemTmp.absolutePath() + "/" + dirName); - return true; - } else { - qDebug() << "Can't create temporary dir maybe due to permissions"; - return false; - } - } else if (tmpNumber == 1000) { - qWarning() << "Import failed. Failed to create temporary file for svg objects"; - return false; - } - } - - return true; -} -UBCFFSubsetAdaptor::UBCFFSubsetReader::~UBCFFSubsetReader() -{ -// QList pages; -// for (int i = 0; i < mProxy->pageCount(); i++) { -// pages << i; -// } -// UBPersistenceManager::persistenceManager()->deleteDocumentScenes(mProxy, pages); -} diff --git a/src/adaptors/UBCFFSubsetAdaptor.h b/src/adaptors/UBCFFSubsetAdaptor.h deleted file mode 100644 index dc268e5cd..000000000 --- a/src/adaptors/UBCFFSubsetAdaptor.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) - * - * Copyright (C) 2013 Open Education Foundation - * - * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour - * l'Education Numérique en Afrique (GIP ENA) - * - * This file is part of OpenBoard. - * - * OpenBoard is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License, - * with a specific linking exception for the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the - * same license as the "OpenSSL" library). - * - * OpenBoard is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with OpenBoard. If not, see . - */ - - - -#ifndef UBCFFSUBSETADAPTOR_H -#define UBCFFSUBSETADAPTOR_H - -#include -#include -#include -#include -#include - -class UBDocumentProxy; -class UBGraphicsScene; -class QSvgGenerator; -class UBGraphicsSvgItem; -class UBGraphicsPixmapItem; -class UBGraphicsItemDelegate; -class QTransform; -class QPainter; -class UBGraphicsItem; -class QGraphicsItem; -class QTextBlockFormat; -class QTextCharFormat; -class QTextCursor; -class UBGraphicsStrokesGroup; - - -class UBCFFSubsetAdaptor -{ -public: - UBCFFSubsetAdaptor(); - static bool ConvertCFFFileToUbz(QString &cffSourceFile, std::shared_ptr pDocument); - -private: - class UBCFFSubsetReader - { - public: - UBCFFSubsetReader(std::shared_ptrproxy, QFile *content); - ~UBCFFSubsetReader(); - - std::shared_ptrmProxy; - QString pwdContent; - - bool parse(); - - private: - QString mTempFilePath; - std::shared_ptr mCurrentScene; - QRectF mCurrentSceneRect; - QString mIndent; - QRectF mViewBox; - QRectF mViewPort; - qreal mVBTransFactor; - QPointF mViewBoxCenter; - QSize mSize; - QPointF mShiftVector; - bool mSvgGSectionIsOpened; - UBGraphicsGroupContainerItem *mGSectionContainer; - - private: - QDomDocument mDOMdoc; - QDomNode mCurrentDOMElement; - QHash persistedItems; - QMap mRefToUuidMap; - QDir mTmpFlashDir; - - void addItemToGSection(QGraphicsItem *item); - bool hashElements(); - void addExtentionsToHash(QDomElement *parent, QDomElement *topGroup); - - void hashSvg(QDomNode *parent, QString prefix = ""); - void hashSiblingIwbElements(QDomElement *parent, QDomElement *topGroup = 0); - - inline void parseSvgSectionAttr(const QDomElement &); - bool parseSvgPage(const QDomElement &parent); - bool parseSvgPageset(const QDomElement &parent); - bool parseSvgElement(const QDomElement &parent); - bool parseIwbMeta(const QDomElement &element); - bool parseSvg(const QDomElement &svgSection); - - inline bool parseGSection(const QDomElement &element); - inline bool parseSvgSwitchSection(const QDomElement &element); - inline bool parseSvgRect(const QDomElement &element); - inline bool parseSvgEllipse(const QDomElement &element); - inline bool parseSvgPolygon(const QDomElement &element); - inline bool parseSvgPolyline(const QDomElement &element); - inline bool parseSvgText(const QDomElement &element); - inline bool parseSvgTextarea(const QDomElement &element); - inline bool parseSvgImage(const QDomElement &element); - inline bool parseSvgFlash(const QDomElement &element); - inline bool parseSvgAudio(const QDomElement &element); - inline bool parseSvgVideo(const QDomElement &element); - inline UBGraphicsGroupContainerItem *parseIwbGroup(QDomElement &parent); - inline bool parseIwbElement(QDomElement &element); - inline void parseTSpan(const QDomElement &parent, QPainter &painter - , qreal &curX, qreal &curY, qreal &width, qreal &height, qreal &linespacing, QRectF &lastDrawnTextBoundingRect - , qreal &fontSize, QColor &fontColor, QString &fontFamily, QString &fontStretch, bool &italic - , int &fontWeight, int &textAlign, QTransform &fontTransform); - inline void parseTSpan(const QDomElement &element, QTextCursor &cursor - , QTextBlockFormat &blockFormat, QTextCharFormat &charFormat); - inline void hashSceneItem(const QDomElement &element, UBGraphicsItem *item); - - // to kill - inline void parseTextAttributes(const QDomElement &element, qreal &fontSize, QColor &fontColor, - QString &fontFamily, QString &fontStretch, bool &italic, - int &fontWeight, int &textAlign, QTransform &fontTransform); - inline void parseTextAttributes(const QDomElement &element, QFont &font, QColor); - inline void readTextBlockAttr(const QDomElement &element, QTextBlockFormat &format); - inline void readTextCharAttr(const QDomElement &element, QTextCharFormat &format); - - //elements parsing methods - bool parseDoc(); - - bool createNewScene(); - bool persistCurrentScene(); - bool persistScenes(); - -// helper methods - void repositionSvgItem(QGraphicsItem *item, qreal width, qreal height, - qreal x, qreal y, - QTransform &transform); - QColor colorFromString(const QString& clrString); - QTransform transformFromString(const QString trString, QGraphicsItem *item = 0); - bool getViewBoxDimenstions(const QString& viewBox); - QSvgGenerator* createSvgGenerator(qreal width, qreal height); - bool getTempFileName(); - inline bool strToBool(QString); - bool createTempFlashPath(); - }; -}; - -#endif // UBCFFSUBSETADAPTOR_H diff --git a/src/adaptors/UBExportCFF.cpp b/src/adaptors/UBExportCFF.cpp deleted file mode 100644 index 65016fff2..000000000 --- a/src/adaptors/UBExportCFF.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) - * - * Copyright (C) 2013 Open Education Foundation - * - * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour - * l'Education Numérique en Afrique (GIP ENA) - * - * This file is part of OpenBoard. - * - * OpenBoard is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License, - * with a specific linking exception for the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the - * same license as the "OpenSSL" library). - * - * OpenBoard is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with OpenBoard. If not, see . - */ - - - -#include "UBExportCFF.h" -#include "UBCFFAdaptor.h" -#include "document/UBDocumentProxy.h" -#include "core/UBDocumentManager.h" -#include "core/UBApplication.h" -#include "core/memcheck.h" -#include "document/UBDocumentController.h" - -#include -#include - - -UBExportCFF::UBExportCFF(QObject *parent) -: UBExportAdaptor(parent) -{ - -} - -UBExportCFF::~UBExportCFF() -{ - -} -QString UBExportCFF::exportName() -{ - return tr("Export to IWB"); -} - -QString UBExportCFF::exportExtention() -{ - return QString(".iwb"); -} - -void UBExportCFF::persist(std::shared_ptr pDocument) -{ - QString src = pDocument->persistencePath(); - - if (!pDocument) - return; - - QString filename = askForFileName(pDocument, tr("Export as IWB File")); - - if (filename.length() > 0) - { - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - - if (mIsVerbose) - UBApplication::showMessage(tr("Exporting document...")); - - UBCFFAdaptor toIWBExporter; - if (toIWBExporter.convertUBZToIWB(src, filename)) - { - if (mIsVerbose) - UBApplication::showMessage(tr("Export successful.")); - } - else - if (mIsVerbose) - UBApplication::showMessage(tr("Export failed.")); - - showErrorsList(toIWBExporter.getConversionMessages()); - - QApplication::restoreOverrideCursor(); - - } - - -} - -bool UBExportCFF::associatedActionactionAvailableFor(const QModelIndex &selectedIndex) -{ - const UBDocumentTreeModel *docModel = qobject_cast(selectedIndex.model()); - if (!selectedIndex.isValid() || docModel->isCatalog(selectedIndex)) { - return false; - } - - return true; -} diff --git a/src/adaptors/UBExportCFF.h b/src/adaptors/UBExportCFF.h deleted file mode 100644 index dc79a2a9a..000000000 --- a/src/adaptors/UBExportCFF.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) - * - * Copyright (C) 2013 Open Education Foundation - * - * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour - * l'Education Numérique en Afrique (GIP ENA) - * - * This file is part of OpenBoard. - * - * OpenBoard is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License, - * with a specific linking exception for the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the - * same license as the "OpenSSL" library). - * - * OpenBoard is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with OpenBoard. If not, see . - */ - - -#ifndef UBExportCFF_H_ -#define UBExportCFF_H_ - -#include - -#include "UBExportAdaptor.h" - -#include "frameworks/UBFileSystemUtils.h" - -class UBDocumentProxy; - -class UBExportCFF : public UBExportAdaptor -{ - Q_OBJECT - -public: - UBExportCFF(QObject *parent = 0); - virtual ~UBExportCFF(); - - virtual QString exportName(); - virtual QString exportExtention(); - virtual void persist(std::shared_ptr pDocument); - virtual bool associatedActionactionAvailableFor(const QModelIndex &selectedIndex); -}; - -#endif /* UBExportCFF_H_ */ diff --git a/src/adaptors/UBImportCFF.cpp b/src/adaptors/UBImportCFF.cpp deleted file mode 100644 index 1af076f39..000000000 --- a/src/adaptors/UBImportCFF.cpp +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) - * - * Copyright (C) 2013 Open Education Foundation - * - * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour - * l'Education Numérique en Afrique (GIP ENA) - * - * This file is part of OpenBoard. - * - * OpenBoard is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License, - * with a specific linking exception for the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the - * same license as the "OpenSSL" library). - * - * OpenBoard is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with OpenBoard. If not, see . - */ - - - -#include -#include - -#include "core/UBApplication.h" -#include "core/UBPersistenceManager.h" -#include "core/UBDocumentManager.h" -#include "core/UBPersistenceManager.h" -#include "document/UBDocumentProxy.h" -#include "domain/UBGraphicsPDFItem.h" -#include "frameworks/UBFileSystemUtils.h" -#include "pdf/PDFRenderer.h" - -#include "UBCFFSubsetAdaptor.h" -#include "UBImportCFF.h" - -#include "globals/UBGlobals.h" - -//THIRD_PARTY_WARNINGS_DISABLE -#ifdef Q_OS_OSX - #include - #include - #include -#else - #include "quazip.h" - #include "quazipfile.h" - #include "quazipfileinfo.h" -#endif -//THIRD_PARTY_WARNINGS_ENABLE - -#include "core/memcheck.h" - -UBImportCFF::UBImportCFF(QObject *parent) - : UBDocumentBasedImportAdaptor(parent) -{ - // NOOP -} - - -UBImportCFF::~UBImportCFF() -{ - // NOOP -} - - -QStringList UBImportCFF::supportedExtentions() -{ - return QStringList("iwb"); -} - - -QString UBImportCFF::importFileFilter() -{ - QString filter = tr("Common File Format ("); - QStringList formats = supportedExtentions(); - bool isFirst = true; - - foreach(QString format, formats) - { - if(isFirst) - isFirst = false; - else - filter.append(" "); - - filter.append("*."+format); - } - - filter.append(")"); - - return filter; -} - -bool UBImportCFF::addFileToDocument(std::shared_ptr pDocument, const QFile& pFile) -{ - QFileInfo fi(pFile); - UBApplication::showMessage(tr("Importing file %1...").arg(fi.baseName()), true); - - // first unzip the file to the correct place - //TODO create temporary path for iwb file content - QString path = QDir::tempPath(); - - QString documentRootFolder = expandFileToDir(pFile, path); - QString contentFile; - if (documentRootFolder.isEmpty()) //if file has failed to unzip it is probably just xml file - contentFile = pFile.fileName(); - else //get path to content xml (according to iwbcff specification) - contentFile = documentRootFolder.append("/content.xml"); - - if(!contentFile.length()){ - UBApplication::showMessage(tr("Import of file %1 failed.").arg(fi.baseName())); - return false; - } - else{ - //TODO convert expanded CFF file content to the destination document - //create destination document proxy - //fill metadata and save - std::shared_ptr destDocument = std::make_shared(UBPersistenceManager::persistenceManager()->generateUniqueDocumentPath()); - QDir dir; - dir.mkdir(destDocument->persistencePath()); - - //try to import cff to document - if (UBCFFSubsetAdaptor::ConvertCFFFileToUbz(contentFile, destDocument)) - { - UBPersistenceManager::persistenceManager()->addDirectoryContentToDocument(destDocument->persistencePath(), pDocument); - UBFileSystemUtils::deleteDir(destDocument->persistencePath()); - UBApplication::showMessage(tr("Import successful.")); - return true; - } - else - { - UBFileSystemUtils::deleteDir(destDocument->persistencePath()); - UBApplication::showMessage(tr("Import failed.")); - return false; - } - } -} - -QString UBImportCFF::expandFileToDir(const QFile& pZipFile, const QString& pDir) -{ - QuaZip zip(pZipFile.fileName()); - - if(!zip.open(QuaZip::mdUnzip)) { - qWarning() << "Import failed. Cause zip.open(): " << zip.getZipError(); - return ""; - } - - zip.setFileNameCodec("UTF-8"); - QuaZipFileInfo info; - QuaZipFile file(&zip); - - //create unique cff document root fodler - //use current date/time and temp number for folder name - QString documentRootFolder; - int tmpNumber = 0; - QDir rootDir; - while (true) { - QString tempPath = QString("%1/sank%2.%3") - .arg(pDir) - .arg(QDateTime::currentDateTime().toString("dd_MM_yyyy_HH-mm")) - .arg(tmpNumber); - if (!rootDir.exists(tempPath)) { - documentRootFolder = tempPath; - break; - } - tmpNumber++; - if (tmpNumber == 100000) { - qWarning() << "Import failed. Failed to create temporary directory for iwb file"; - return ""; - } - } - if (!rootDir.mkdir(documentRootFolder)) { - qWarning() << "Import failed. Couse: failed to create temp folder for cff package"; - } - - QFile out; - char c; - for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { - if(!zip.getCurrentFileInfo(&info)) { - //TOD UB 4.3 O display error to user or use crash reporter - qWarning() << "Import failed. Cause: getCurrentFileInfo(): " << zip.getZipError(); - return ""; - } -// if(!file.open(QIODevice::ReadOnly)) { -// qWarning() << "Import failed. Cause: file.open(): " << zip.getZipError(); -// return ""; -// } - file.open(QIODevice::ReadOnly); - if(file.getZipError()!= UNZ_OK) { - qWarning() << "Import failed. Cause: file.getFileName(): " << zip.getZipError(); - return ""; - } - - QString newFileName = documentRootFolder + "/" + file.getActualFileName(); - - QFileInfo newFileInfo(newFileName); - rootDir.mkpath(newFileInfo.absolutePath()); - - out.setFileName(newFileName); - out.open(QIODevice::WriteOnly); - - while(file.getChar(&c)) - out.putChar(c); - - out.close(); - - if(file.getZipError()!=UNZ_OK) { - qWarning() << "Import failed. Cause: " << zip.getZipError(); - return ""; - } - if(!file.atEnd()) { - qWarning() << "Import failed. Cause: read all but not EOF"; - return ""; - } - - file.close(); - - if(file.getZipError()!=UNZ_OK) { - qWarning() << "Import failed. Cause: file.close(): " << file.getZipError(); - return ""; - } - } - - zip.close(); - - if(zip.getZipError()!=UNZ_OK) { - qWarning() << "Import failed. Cause: zip.close(): " << zip.getZipError(); - return ""; - } - - return documentRootFolder; -} - - -std::shared_ptr UBImportCFF::importFile(const QFile& pFile, const QString& pGroup) -{ - Q_UNUSED(pGroup); // group is defined in the imported file - - QFileInfo fi(pFile); - UBApplication::showMessage(tr("Importing file %1...").arg(fi.baseName()), true); - - // first unzip the file to the correct place - //TODO create temporary path for iwb file content - QString path = QDir::tempPath(); - - QString documentRootFolder = expandFileToDir(pFile, path); - QString contentFile; - if (documentRootFolder.isEmpty()) - //if file has failed to umzip it is probably just xml file - contentFile = pFile.fileName(); - else - //get path to content xml - contentFile = QString("%1/content.xml").arg(documentRootFolder); - - if(!contentFile.length()){ - UBApplication::showMessage(tr("Import of file %1 failed.").arg(fi.baseName())); - return 0; - } - else{ - //create destination document proxy - //fill metadata and save - std::shared_ptr destDocument = std::make_shared(UBPersistenceManager::persistenceManager()->generateUniqueDocumentPath()); - QDir dir; - dir.mkdir(destDocument->persistencePath()); - if (pGroup.length() > 0) - destDocument->setMetaData(UBSettings::documentGroupName, pGroup); - if (!fi.baseName().isEmpty()) - destDocument->setMetaData(UBSettings::documentName, fi.baseName()); - - destDocument->setMetaData(UBSettings::documentVersion, UBSettings::currentFileVersion); - destDocument->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime())); - - std::shared_ptr newDocument = nullptr; - //try to import cff to document - if (UBCFFSubsetAdaptor::ConvertCFFFileToUbz(contentFile, destDocument)) - { - newDocument = UBPersistenceManager::persistenceManager()->createDocumentFromDir(destDocument->persistencePath() - ,"" - ,"" - ,false - ,false - ,true); - - UBApplication::showMessage(tr("Import successful.")); - } - else - { - UBFileSystemUtils::deleteDir(destDocument->persistencePath()); - UBApplication::showMessage(tr("Import failed.")); - } - - if (documentRootFolder.length() != 0) - UBFileSystemUtils::deleteDir(documentRootFolder); - return newDocument; - } -} diff --git a/src/adaptors/UBImportCFF.h b/src/adaptors/UBImportCFF.h deleted file mode 100644 index a8c058832..000000000 --- a/src/adaptors/UBImportCFF.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) - * - * Copyright (C) 2013 Open Education Foundation - * - * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour - * l'Education Numérique en Afrique (GIP ENA) - * - * This file is part of OpenBoard. - * - * OpenBoard is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License, - * with a specific linking exception for the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the - * same license as the "OpenSSL" library). - * - * OpenBoard is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with OpenBoard. If not, see . - */ - - - -#ifndef UBIMPORTCFF_H -#define UBIMPORTCFF_H - -#include -#include "UBImportAdaptor.h" - -class UBDocumentProxy; - -class UBImportCFF : public UBDocumentBasedImportAdaptor -{ - Q_OBJECT; - - public: - UBImportCFF(QObject *parent = 0); - virtual ~UBImportCFF(); - - virtual QStringList supportedExtentions(); - virtual QString importFileFilter(); - - virtual bool addFileToDocument(std::shared_ptr pDocument, const QFile& pFile); - virtual std::shared_ptr importFile(const QFile& pFile, const QString& pGroup); - - private: - QString expandFileToDir(const QFile& pZipFile, const QString& pDir); -}; - -#endif // UBIMPORTCFF_H diff --git a/src/adaptors/adaptors.pri b/src/adaptors/adaptors.pri index eb63272bb..d8cc98ab0 100644 --- a/src/adaptors/adaptors.pri +++ b/src/adaptors/adaptors.pri @@ -13,10 +13,7 @@ HEADERS += src/adaptors/UBExportAdaptor.h\ src/adaptors/UBImportImage.h \ src/adaptors/UBExportWeb.h \ $$PWD/UBExportDocumentSetAdaptor.h \ - $$PWD/UBImportDocumentSetAdaptor.h \ - $$PWD/UBExportCFF.h \ - $$PWD/UBImportCFF.h \ - $$PWD/UBCFFSubsetAdaptor.h + $$PWD/UBImportDocumentSetAdaptor.h SOURCES += src/adaptors/UBExportAdaptor.cpp\ @@ -33,7 +30,4 @@ SOURCES += src/adaptors/UBExportAdaptor.cpp\ src/adaptors/UBImportImage.cpp \ src/adaptors/UBExportWeb.cpp \ $$PWD/UBExportDocumentSetAdaptor.cpp \ - $$PWD/UBImportDocumentSetAdaptor.cpp \ - $$PWD/UBExportCFF.cpp \ - $$PWD/UBImportCFF.cpp \ - $$PWD/UBCFFSubsetAdaptor.cpp + $$PWD/UBImportDocumentSetAdaptor.cpp diff --git a/src/core/UBDocumentManager.cpp b/src/core/UBDocumentManager.cpp index 4597f103a..c56774d27 100644 --- a/src/core/UBDocumentManager.cpp +++ b/src/core/UBDocumentManager.cpp @@ -33,12 +33,10 @@ #include "adaptors/UBExportFullPDF.h" #include "adaptors/UBExportDocument.h" #include "adaptors/UBExportWeb.h" -#include "adaptors/UBExportCFF.h" #include "adaptors/UBExportDocumentSetAdaptor.h" #include "adaptors/UBImportDocument.h" #include "adaptors/UBImportPDF.h" #include "adaptors/UBImportImage.h" -#include "adaptors/UBImportCFF.h" #include "adaptors/UBImportDocumentSetAdaptor.h" #include "board/UBBoardController.h" @@ -80,7 +78,6 @@ UBDocumentManager::UBDocumentManager(QObject *parent) QString dummyObjects = tr("objects"); QString dummyWidgets = tr("widgets"); - //UBExportCFF* cffExporter = new UBExportCFF(this); UBExportFullPDF* exportFullPdf = new UBExportFullPDF(this); UBExportDocument* exportDocument = new UBExportDocument(this); @@ -89,7 +86,6 @@ UBDocumentManager::UBDocumentManager(QObject *parent) mExportAdaptors.append(exportDocumentSet); //mExportAdaptors.append(webPublished); mExportAdaptors.append(exportFullPdf); - //mExportAdaptors.append(cffExporter); // UBExportWeb* exportWeb = new UBExportWeb(this); // mExportAdaptors.append(exportWeb); @@ -102,8 +98,6 @@ UBDocumentManager::UBDocumentManager(QObject *parent) mImportAdaptors.append(pdfImport); UBImportImage* imageImport = new UBImportImage(this); mImportAdaptors.append(imageImport); - UBImportCFF* cffImport = new UBImportCFF(this); - mImportAdaptors.append(cffImport); } From b568c27cd916818a0080e44077760de00e8f7f06 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sat, 12 Apr 2025 11:33:54 +0200 Subject: [PATCH 012/133] feat: add table-of-content (TOC) - add UBToc holding a table-of-content - add UBTocSerializer for loading and saving the TOC as JSON - create a default TOC for a UBDocument if no TOC exists - add functions to create the page and thumbnail file names from an integer id - add functions to get the file name by index based on TOC content - add scanner to create or update a TOC for documents created or processed by previous versions of OpenBoard - update document version to 4.9.0 - use TOC to translate page index to page id everywhere Signed-off-by: letsfindaway --- src/adaptors/UBExportFullPDF.cpp | 14 +- src/adaptors/UBExportPDF.cpp | 10 +- src/adaptors/UBMetadataDcSubsetAdaptor.cpp | 8 +- src/adaptors/UBSvgSubsetAdaptor.cpp | 148 +------- src/adaptors/UBSvgSubsetAdaptor.h | 23 +- src/adaptors/UBThumbnailAdaptor.cpp | 69 ++-- src/adaptors/UBThumbnailAdaptor.h | 12 +- src/api/UBWidgetUniboardAPI.cpp | 8 +- src/board/UBBoardController.cpp | 5 +- src/core/UBApplicationController.cpp | 14 +- src/core/UBPersistenceManager.cpp | 386 ++++++--------------- src/core/UBPersistenceManager.h | 29 +- src/core/UBSceneCache.cpp | 42 +-- src/core/UBSceneCache.h | 36 +- src/core/UBSettings.cpp | 2 +- src/document/CMakeLists.txt | 4 + src/document/UBDocument.cpp | 203 +++++++++-- src/document/UBDocument.h | 17 +- src/document/UBDocumentController.cpp | 2 +- src/document/UBToc.cpp | 186 ++++++++++ src/document/UBToc.h | 74 ++++ src/document/UBTocSerializer.cpp | 134 +++++++ src/document/UBTocSerializer.h | 53 +++ src/document/document.pri | 9 +- src/gui/UBBoardThumbnailsView.cpp | 2 +- src/gui/UBThumbnailScene.cpp | 26 +- 26 files changed, 904 insertions(+), 612 deletions(-) create mode 100644 src/document/UBToc.cpp create mode 100644 src/document/UBToc.h create mode 100644 src/document/UBTocSerializer.cpp create mode 100644 src/document/UBTocSerializer.h diff --git a/src/adaptors/UBExportFullPDF.cpp b/src/adaptors/UBExportFullPDF.cpp index 71d22b52c..56027280c 100644 --- a/src/adaptors/UBExportFullPDF.cpp +++ b/src/adaptors/UBExportFullPDF.cpp @@ -40,14 +40,12 @@ #include "core/UBPersistenceManager.h" #include "domain/UBGraphicsScene.h" -#include "domain/UBGraphicsSvgItem.h" #include "domain/UBGraphicsPDFItem.h" +#include "document/UBDocument.h" #include "document/UBDocumentProxy.h" #include "document/UBDocumentController.h" -#include "pdf/GraphicsPDFItem.h" - #include "UBExportPDF.h" #include @@ -104,10 +102,11 @@ void UBExportFullPDF::saveOverlayPdf(std::shared_ptr pDocumentP pdfPrinter.setFullPage(true); QPainter* pdfPainter = 0; + auto document = UBDocument::getDocument(pDocumentProxy); - for(int pageIndex = 0 ; pageIndex < pDocumentProxy->pageCount(); pageIndex++) + for(int pageIndex = 0 ; pageIndex < document->pageCount(); pageIndex++) { - std::shared_ptr scene = UBPersistenceManager::persistenceManager()->loadDocumentScene(pDocumentProxy, pageIndex); + std::shared_ptr scene = document->loadScene(pageIndex); // set background according to PDF export settings bool isDark = scene->isDarkBackground(); UBPageBackground pageBackground = scene->pageBackground(); @@ -219,11 +218,12 @@ bool UBExportFullPDF::persistsDocument(std::shared_ptr pDocumen // factor between scene coordinates and PDF coordinates double dpiScale = 72. / pDocumentProxy->pageDpi(); - int existingPageCount = pDocumentProxy->pageCount(); + auto document = UBDocument::getDocument(pDocumentProxy); + int existingPageCount = document->pageCount(); for(int pageIndex = 0 ; pageIndex < existingPageCount; pageIndex++) { - std::shared_ptr scene = UBPersistenceManager::persistenceManager()->loadDocumentScene(pDocumentProxy, pageIndex); + std::shared_ptr scene = document->loadScene(pageIndex); UBGraphicsPDFItem *pdfItem = qgraphicsitem_cast(scene->backgroundObject()); if (pdfItem) diff --git a/src/adaptors/UBExportPDF.cpp b/src/adaptors/UBExportPDF.cpp index 3c5155429..d05797ee8 100644 --- a/src/adaptors/UBExportPDF.cpp +++ b/src/adaptors/UBExportPDF.cpp @@ -41,14 +41,11 @@ #include "core/UBPersistenceManager.h" #include "domain/UBGraphicsScene.h" -#include "domain/UBGraphicsSvgItem.h" -#include "domain/UBGraphicsPDFItem.h" +#include "document/UBDocument.h" #include "document/UBDocumentProxy.h" #include "document/UBDocumentController.h" -#include "pdf/GraphicsPDFItem.h" - #include "core/memcheck.h" UBExportPDF::UBExportPDF(QObject *parent) @@ -97,11 +94,12 @@ bool UBExportPDF::persistsDocument(std::shared_ptr pDocumentPro QPainter pdfPainter; bool painterNeedsBegin = true; - int existingPageCount = pDocumentProxy->pageCount(); + auto document = UBDocument::getDocument(pDocumentProxy); + int existingPageCount = document->pageCount(); for(int pageIndex = 0 ; pageIndex < existingPageCount; pageIndex++) { - std::shared_ptr scene = UBPersistenceManager::persistenceManager()->loadDocumentScene(pDocumentProxy, pageIndex); + std::shared_ptr scene = document->loadScene(pageIndex); UBApplication::showMessage(tr("Exporting page %1 of %2").arg(pageIndex + 1).arg(existingPageCount)); // set background to white, no crossing for PDF output diff --git a/src/adaptors/UBMetadataDcSubsetAdaptor.cpp b/src/adaptors/UBMetadataDcSubsetAdaptor.cpp index 7fe4ae0f1..236b4a002 100644 --- a/src/adaptors/UBMetadataDcSubsetAdaptor.cpp +++ b/src/adaptors/UBMetadataDcSubsetAdaptor.cpp @@ -117,7 +117,6 @@ void UBMetadataDcSubsetAdaptor::persist(std::shared_ptr proxy) // introduced in UB 4.2 xmlWriter.writeTextElement(nsDc, "identifier", proxy->metaData(UBSettings::documentIdentifer).toString()); - xmlWriter.writeTextElement(UBSettings::uniboardDocumentNamespaceUri, "version", UBSettings::currentFileVersion); QString width = QString::number(proxy->defaultDocumentSize().width()); QString height = QString::number(proxy->defaultDocumentSize().height()); xmlWriter.writeTextElement(UBSettings::uniboardDocumentNamespaceUri, "size", QString("%1x%2").arg(width).arg(height)); @@ -125,6 +124,9 @@ void UBMetadataDcSubsetAdaptor::persist(std::shared_ptr proxy) // introduced in UB 4.4 xmlWriter.writeTextElement(UBSettings::uniboardDocumentNamespaceUri, "updated-at", UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTimeUtc())); + // write as last element to cope with parsing problem + xmlWriter.writeTextElement(UBSettings::uniboardDocumentNamespaceUri, "version", UBSettings::currentFileVersion); + xmlWriter.writeEndElement(); //dc:Description xmlWriter.writeEndElement(); //RDF @@ -157,6 +159,7 @@ QMap UBMetadataDcSubsetAdaptor::load(QString pPath) } QXmlStreamReader xml(&file); + QString docVersion = "4.1"; // untagged doc version 4.1 while (!xml.atEnd()) { @@ -164,7 +167,6 @@ QMap UBMetadataDcSubsetAdaptor::load(QString pPath) if (xml.isStartElement()) { - QString docVersion = "4.1"; // untagged doc version 4.1 QString name = xml.name().toString(); if (name == "title") @@ -225,7 +227,6 @@ QMap UBMetadataDcSubsetAdaptor::load(QString pPath) metadata.insert(UBSettings::documentUpdatedAt, xml.readElementText()); updatedAtFound = true; } - metadata.insert(UBSettings::documentVersion, docVersion); } if (xml.hasError()) @@ -234,6 +235,7 @@ QMap UBMetadataDcSubsetAdaptor::load(QString pPath) } } + metadata.insert(UBSettings::documentVersion, docVersion); file.close(); } diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index 56319efc3..603f79912 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -145,26 +145,9 @@ static bool itemZIndexComp(const QGraphicsItem* item1, } -void UBSvgSubsetAdaptor::upgradeScene(std::shared_ptr proxy, const int pageIndex) +QDomDocument UBSvgSubsetAdaptor::loadSceneDocument(std::shared_ptr proxy, const int pageId) { - //4.2 - QDomDocument doc = loadSceneDocument(proxy, pageIndex); - QDomElement elSvg = doc.documentElement(); // SVG tag - QString ubVersion = elSvg.attributeNS(UBSettings::uniboardDocumentNamespaceUri, "version", "4.1"); // default to 4.1 - - if (ubVersion.startsWith("4.1") || ubVersion.startsWith("4.2") || ubVersion.startsWith("4.3")) - { - // migrate to 4.2.1 (or latter) - std::shared_ptr scene = loadScene(proxy, pageIndex); - scene->setModified(true); - persistScene(proxy, scene, pageIndex); - } -} - - -QDomDocument UBSvgSubsetAdaptor::loadSceneDocument(std::shared_ptr proxy, const int pPageIndex) -{ - QString fileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg",pPageIndex); + QString fileName = proxy->persistencePath() + UBPersistenceManager::persistenceManager()->sceneFilenameForId(pageId); QFile file(fileName); QDomDocument doc("page"); @@ -185,9 +168,9 @@ QDomDocument UBSvgSubsetAdaptor::loadSceneDocument(std::shared_ptr proxy, const int pageIndex, QUuid pUuid) +void UBSvgSubsetAdaptor::setSceneUuid(std::shared_ptr proxy, const int pageId, QUuid pUuid) { - const QString path = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", pageIndex); + const QString path = proxy->persistencePath() + UBPersistenceManager::persistenceManager()->sceneFilenameForId(pageId); replicateScene(path, path, pUuid); } @@ -251,35 +234,9 @@ QString UBSvgSubsetAdaptor::uniboardDocumentNamespaceUriFromVersion(int mFileVer } -std::shared_ptr UBSvgSubsetAdaptor::loadScene(std::shared_ptr proxy, const int pageIndex) +QByteArray UBSvgSubsetAdaptor::loadSceneAsText(std::shared_ptr proxy, const int pageId) { - UBApplication::showMessage(QObject::tr("Loading scene (%1/%2)").arg(pageIndex+1).arg(proxy->pageCount())); - QString fileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", pageIndex); - qInfo() << "loading scene. Filename is : " << fileName; - QFile file(fileName); - - if (file.exists()) - { - if (!file.open(QIODevice::ReadOnly)) - { - qWarning() << "Cannot open file " << fileName << " for reading ..."; - return 0; - } - - std::shared_ptr scene = loadScene(proxy, file.readAll()); - - file.close(); - - return scene; - } - - return 0; -} - - -QByteArray UBSvgSubsetAdaptor::loadSceneAsText(std::shared_ptr proxy, const int pageIndex) -{ - QString fileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", pageIndex); + QString fileName = proxy->persistencePath() + UBPersistenceManager::persistenceManager()->sceneFilenameForId(pageId); qDebug() << fileName; QFile file(fileName); @@ -300,9 +257,9 @@ QByteArray UBSvgSubsetAdaptor::loadSceneAsText(std::shared_ptr } -QUuid UBSvgSubsetAdaptor::sceneUuid(std::shared_ptr proxy, const int pageIndex) +QUuid UBSvgSubsetAdaptor::sceneUuid(std::shared_ptr proxy, const int pageId) { - QString fileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", pageIndex); + QString fileName = proxy->persistencePath() + UBPersistenceManager::persistenceManager()->sceneFilenameForId(pageId); QFile file(fileName); @@ -353,9 +310,9 @@ std::shared_ptr UBSvgSubsetAdaptor::loadScene(std::shared_ptr UBSvgSubsetAdaptor::prepareLoadingScene(std::shared_ptr proxy, const int pageIndex) +std::shared_ptr UBSvgSubsetAdaptor::prepareLoadingScene(std::shared_ptr proxy, const int pageId) { - const auto fileContent = loadSceneAsText(proxy, pageIndex); + const auto fileContent = loadSceneAsText(proxy, pageId); auto context = std::make_shared(proxy, fileContent); return context; } @@ -1186,17 +1143,17 @@ QGraphicsItem *UBSvgSubsetAdaptor::UBSvgSubsetReader::readElementFromGroup() return result; } -void UBSvgSubsetAdaptor::persistScene(std::shared_ptr proxy, std::shared_ptr pScene, const int pageIndex) +void UBSvgSubsetAdaptor::persistScene(std::shared_ptr proxy, std::shared_ptr pScene, const int pageId) { - UBSvgSubsetWriter writer(proxy, pScene, pageIndex); - writer.persistScene(proxy, pageIndex); + UBSvgSubsetWriter writer(proxy, pScene, pageId); + writer.persistScene(proxy, pageId); } -UBSvgSubsetAdaptor::UBSvgSubsetWriter::UBSvgSubsetWriter(std::shared_ptr proxy, std::shared_ptr pScene, const int pageIndex) +UBSvgSubsetAdaptor::UBSvgSubsetWriter::UBSvgSubsetWriter(std::shared_ptr proxy, std::shared_ptr pScene, const int pageId) : mScene(pScene) , mDocumentPath(proxy->persistencePath()) - , mPageIndex(pageIndex) + , mPageId(pageId) { // NOOP @@ -1257,9 +1214,9 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::writeSvgElement(std::shared_ptr proxy, int pageIndex) +bool UBSvgSubsetAdaptor::UBSvgSubsetWriter::persistScene(std::shared_ptr proxy, int pageId) { - Q_UNUSED(pageIndex); + Q_UNUSED(pageId); //Creating dom structure to store information QDomDocument groupDomDocument; @@ -1559,7 +1516,7 @@ bool UBSvgSubsetAdaptor::UBSvgSubsetWriter::persistScene(std::shared_ptrsceneFilenameForId(mPageId); QFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) @@ -3445,75 +3402,6 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::cacheToSvg(UBGraphicsCache* item) mXmlWriter.writeEndElement(); } -void UBSvgSubsetAdaptor::convertPDFObjectsToImages(std::shared_ptr proxy) -{ - for (int i = 0; i < proxy->pageCount(); i++) - { - std::shared_ptr scene = loadScene(proxy, i); - - if (scene) - { - bool foundPDFItem = false; - - foreach(QGraphicsItem* item, scene->items()) - { - UBGraphicsPDFItem *pdfItem = dynamic_cast(item); - - if (pdfItem) - { - foundPDFItem = true; - UBGraphicsPixmapItem* pixmapItem = pdfItem->toPixmapItem(); - - scene->removeItem(pdfItem); - scene->addItem(pixmapItem); - - } - } - - if (foundPDFItem) - { - scene->setModified(true); - persistScene(proxy, scene, i); - } - } - - } -} - - -void UBSvgSubsetAdaptor::convertSvgImagesToImages(std::shared_ptr proxy) -{ - for (int i = 0; i < proxy->pageCount(); i++) - { - std::shared_ptr scene = loadScene(proxy, i); - - if (scene) - { - bool foundSvgItem = false; - - foreach(QGraphicsItem* item, scene->items()) - { - UBGraphicsSvgItem *svgItem = dynamic_cast(item); - - if (svgItem) - { - foundSvgItem = true; - UBGraphicsPixmapItem* pixmapItem = svgItem->toPixmapItem(); - - scene->removeItem(svgItem); - scene->addItem(pixmapItem); - } - } - - if (foundSvgItem) - { - scene->setModified(true); - persistScene(proxy, scene, i); - } - } - } -} - UBSvgSubsetAdaptor::UBSvgReaderContext::UBSvgReaderContext(std::shared_ptr proxy, const QByteArray& pXmlData) { reader = new UBSvgSubsetReader(proxy, pXmlData); diff --git a/src/adaptors/UBSvgSubsetAdaptor.h b/src/adaptors/UBSvgSubsetAdaptor.h index e3a3cfe94..9b89417dc 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.h +++ b/src/adaptors/UBSvgSubsetAdaptor.h @@ -83,21 +83,16 @@ class UBSvgSubsetAdaptor UBSvgSubsetReader* reader = nullptr; }; - static std::shared_ptr loadScene(std::shared_ptr proxy, const int pageIndex); - static QByteArray loadSceneAsText(std::shared_ptr proxy, const int pageIndex); + static QByteArray loadSceneAsText(std::shared_ptr proxy, const int pageId); static std::shared_ptr loadScene(std::shared_ptr proxy, const QByteArray& pArray); - static std::shared_ptr prepareLoadingScene(std::shared_ptr proxy, const int pageIndex); + static std::shared_ptr prepareLoadingScene(std::shared_ptr proxy, const int pageId); - static void persistScene(std::shared_ptr proxy, std::shared_ptr pScene, const int pageIndex); - static void upgradeScene(std::shared_ptr proxy, const int pageIndex); + static void persistScene(std::shared_ptr proxy, std::shared_ptr pScene, const int pageId); - static QUuid sceneUuid(std::shared_ptr proxy, const int pageIndex); - static void setSceneUuid(std::shared_ptr proxy, const int pageIndex, QUuid pUuid); + static QUuid sceneUuid(std::shared_ptr proxy, const int pageId); + static void setSceneUuid(std::shared_ptr proxy, const int pageId, QUuid pUuid); static void replicateScene(const QString& sourcePath, const QString& targetPath, QUuid uuid); - static void convertPDFObjectsToImages(std::shared_ptr proxy); - static void convertSvgImagesToImages(std::shared_ptr proxy); - static const QString nsSvg; static const QString nsXLink; static const QString nsXHtml; @@ -112,7 +107,7 @@ class UBSvgSubsetAdaptor private: - static QDomDocument loadSceneDocument(std::shared_ptr proxy, const int pPageIndex); + static QDomDocument loadSceneDocument(std::shared_ptr proxy, const int pageId); static QString uniboardDocumentNamespaceUriFromVersion(int fileVersion); @@ -210,9 +205,9 @@ class UBSvgSubsetAdaptor { public: - UBSvgSubsetWriter(std::shared_ptr proxy, std::shared_ptr pScene, const int pageIndex); + UBSvgSubsetWriter(std::shared_ptr proxy, std::shared_ptr pScene, const int pageId); - bool persistScene(std::shared_ptr proxy, int pageIndex); + bool persistScene(std::shared_ptr proxy, int pageId); virtual ~UBSvgSubsetWriter(){} @@ -289,7 +284,7 @@ class UBSvgSubsetAdaptor std::shared_ptr mScene; QXmlStreamWriter mXmlWriter; QString mDocumentPath; - int mPageIndex; + int mPageId; }; }; diff --git a/src/adaptors/UBThumbnailAdaptor.cpp b/src/adaptors/UBThumbnailAdaptor.cpp index 3e7c44c28..4ea8fdc2c 100644 --- a/src/adaptors/UBThumbnailAdaptor.cpp +++ b/src/adaptors/UBThumbnailAdaptor.cpp @@ -29,42 +29,30 @@ #include "UBThumbnailAdaptor.h" -#include - -#include "frameworks/UBFileSystemUtils.h" - -#include "core/UBPersistenceManager.h" #include "core/UBApplication.h" #include "core/UBSettings.h" -#include "board/UBBoardController.h" -#include "board/UBBoardPaletteManager.h" - -#include "document/UBDocumentProxy.h" +#include "document/UBDocument.h" #include "domain/UBGraphicsScene.h" -#include "UBSvgSubsetAdaptor.h" - #include "core/memcheck.h" -void UBThumbnailAdaptor::generateMissingThumbnails(std::shared_ptr proxy) +void UBThumbnailAdaptor::generateMissingThumbnails(UBDocument* document) { - int existingPageCount = proxy->pageCount(); + int existingPageCount = document->pageCount(); for (int iPageNo = 0; iPageNo < existingPageCount; ++iPageNo) { - QString thumbFileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", iPageNo); + QString thumbFileName = document->thumbnailFile(iPageNo); - QFile thumbFile(thumbFileName); - - if (!thumbFile.exists()) + if (!QFile::exists(thumbFileName)) { bool displayMessage = (existingPageCount > 5); int thumbCount = 0; - std::shared_ptr scene = UBSvgSubsetAdaptor::loadScene(proxy, iPageNo); + std::shared_ptr scene = document->loadScene(iPageNo); if (scene) { @@ -73,7 +61,7 @@ void UBThumbnailAdaptor::generateMissingThumbnails(std::shared_ptr 0) @@ -83,19 +71,17 @@ void UBThumbnailAdaptor::generateMissingThumbnails(std::shared_ptr proxy, int pageIndex) +QPixmap UBThumbnailAdaptor::generateMissingThumbnail(UBDocument* document, int pageIndex) { - QString thumbFileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", pageIndex); - - QFile thumbFile(thumbFileName); + QString thumbFileName = document->thumbnailFile(pageIndex); - if (!thumbFile.exists()) + if (!QFile::exists(thumbFileName)) { - std::shared_ptr scene = UBSvgSubsetAdaptor::loadScene(proxy, pageIndex); + std::shared_ptr scene = document->loadScene(pageIndex); if (scene) { - persistScene(proxy, scene, pageIndex); + persistScene(document, scene, pageIndex); } } @@ -104,41 +90,32 @@ QPixmap UBThumbnailAdaptor::generateMissingThumbnail(std::shared_ptr proxy, int pageIndex) +QPixmap UBThumbnailAdaptor::get(UBDocument* document, int pageIndex) { - QString fileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", pageIndex); + QString fileName = document->thumbnailFile(pageIndex); QFile file(fileName); + if (!file.exists()) { - generateMissingThumbnails(proxy); + generateMissingThumbnails(document); } QPixmap pix; + if (file.exists()) { pix.load(fileName, 0, Qt::AutoColor); } - return pix; -} -void UBThumbnailAdaptor::load(std::shared_ptr proxy, QList>& list) -{ - list.clear(); - UBApplication::showMessage(tr("Loading thumbnails (%1 pages)").arg(proxy->pageCount())); - for(int i=0; ipageCount(); i++) - { - list.append(std::make_shared(get(proxy, i))); - } + return pix; } -void UBThumbnailAdaptor::persistScene(std::shared_ptr proxy, std::shared_ptr pScene, int pageIndex, bool overrideModified) +void UBThumbnailAdaptor::persistScene(UBDocument* document, std::shared_ptr pScene, int pageIndex, bool overrideModified) { - QString fileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", pageIndex); - - QFile thumbFile(fileName); + QString fileName = document->thumbnailFile(pageIndex); - if (pScene->isModified() || overrideModified || !thumbFile.exists()) + if (pScene->isModified() || overrideModified || !QFile::exists(fileName)) { qreal nominalWidth = pScene->nominalSize().width(); qreal nominalHeight = pScene->nominalSize().height(); @@ -178,9 +155,9 @@ void UBThumbnailAdaptor::persistScene(std::shared_ptr proxy, st } -QUrl UBThumbnailAdaptor::thumbnailUrl(std::shared_ptr proxy, int pageIndex) +QUrl UBThumbnailAdaptor::thumbnailUrl(UBDocument* document, int pageIndex) { - QString fileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", pageIndex); + QString fileName = document->thumbnailFile(pageIndex); return QUrl::fromLocalFile(fileName); } diff --git a/src/adaptors/UBThumbnailAdaptor.h b/src/adaptors/UBThumbnailAdaptor.h index 767c7a2ac..fbee4bf61 100644 --- a/src/adaptors/UBThumbnailAdaptor.h +++ b/src/adaptors/UBThumbnailAdaptor.h @@ -33,7 +33,6 @@ #include class UBDocument; -class UBDocumentProxy; class UBGraphicsScene; class UBThumbnailAdaptor //static class @@ -41,16 +40,15 @@ class UBThumbnailAdaptor //static class Q_DECLARE_TR_FUNCTIONS(UBThumbnailAdaptor) public: - static QUrl thumbnailUrl(std::shared_ptr proxy, int pageIndex); + static QUrl thumbnailUrl(UBDocument* document, int pageIndex); - static void persistScene(std::shared_ptr proxy, std::shared_ptr pScene, int pageIndex, bool overrideModified = false); + static void persistScene(UBDocument* document, std::shared_ptr pScene, int pageIndex, bool overrideModified = false); - static QPixmap get(std::shared_ptr proxy, int index); - static void load(std::shared_ptr proxy, QList>& list); - static QPixmap generateMissingThumbnail(std::shared_ptr proxy, int pageIndex); + static QPixmap get(UBDocument* document, int index); + static QPixmap generateMissingThumbnail(UBDocument* document, int pageIndex); private: - static void generateMissingThumbnails(std::shared_ptr proxy); + static void generateMissingThumbnails(UBDocument* document); UBThumbnailAdaptor() {} }; diff --git a/src/api/UBWidgetUniboardAPI.cpp b/src/api/UBWidgetUniboardAPI.cpp index 6dbbde6b8..6ad579099 100644 --- a/src/api/UBWidgetUniboardAPI.cpp +++ b/src/api/UBWidgetUniboardAPI.cpp @@ -36,6 +36,7 @@ #include "core/UBApplication.h" #include "core/UBSettings.h" +#include "document/UBDocument.h" #include "document/UBDocumentProxy.h" #include "board/UBBoardController.h" @@ -394,14 +395,15 @@ QString UBWidgetUniboardAPI::pageThumbnail(const int pageNumber) return ""; std::shared_ptr doc = UBApplication::boardController->selectedDocument(); + auto document = UBDocument::getDocument(doc); - if (!doc) + if (!document) return ""; - if (pageNumber > doc->pageCount()) + if (pageNumber > document->pageCount()) return ""; - QUrl url = UBThumbnailAdaptor::thumbnailUrl(doc, pageNumber - 1); + QUrl url = UBThumbnailAdaptor::thumbnailUrl(document.get(), pageNumber - 1); return url.toString(); diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index 0b5eee26c..c701d2025 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -1652,12 +1652,13 @@ std::shared_ptr UBBoardController::setActiveDocumentScene(std:: bool documentChange = selectedDocument() != pDocumentProxy; + auto document = UBDocument::getDocument(pDocumentProxy); int index = pSceneIndex; - int sceneCount = pDocumentProxy->pageCount(); + int sceneCount = document->pageCount(); if (index >= sceneCount && sceneCount > 0) index = sceneCount - 1; - std::shared_ptr targetScene = UBPersistenceManager::persistenceManager()->loadDocumentScene(pDocumentProxy, index); + std::shared_ptr targetScene = document->loadScene(index); bool sceneChange = targetScene != mActiveScene; diff --git a/src/core/UBApplicationController.cpp b/src/core/UBApplicationController.cpp index 316ab6e34..782e81f4c 100644 --- a/src/core/UBApplicationController.cpp +++ b/src/core/UBApplicationController.cpp @@ -44,30 +44,21 @@ #include "board/UBBoardPaletteManager.h" #include "board/UBDrawingController.h" - +#include "document/UBDocument.h" #include "document/UBDocumentProxy.h" #include "document/UBDocumentController.h" #include "domain/UBGraphicsWidgetItem.h" -#include "desktop/UBDesktopPalette.h" #include "desktop/UBDesktopAnnotationController.h" #include "web/UBWebController.h" #include "gui/UBScreenMirror.h" #include "gui/UBMainWindow.h" -#include "gui/UBStartupHintsPalette.h" - -#include "domain/UBGraphicsPixmapItem.h" #include "podcast/UBPodcastController.h" -#include "network/UBNetworkAccessManager.h" - -#include "ui_mainWindow.h" - - #ifdef Q_OS_MAC #include @@ -259,6 +250,7 @@ void UBApplicationController::adjustDisplayView() void UBApplicationController::adjustPreviousViews(int pActiveSceneIndex, std::shared_ptr pActiveDocument) { int viewIndex = pActiveSceneIndex; + auto document = UBDocument::getDocument(pActiveDocument); foreach(UBBoardView* previousView, mPreviousViews) { @@ -266,7 +258,7 @@ void UBApplicationController::adjustPreviousViews(int pActiveSceneIndex, std::sh { viewIndex--; - std::shared_ptr scene = UBPersistenceManager::persistenceManager()->loadDocumentScene(pActiveDocument, viewIndex); + std::shared_ptr scene = document->loadScene(viewIndex); if (scene) { diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index 3fcbedf59..b511667ad 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -36,29 +36,22 @@ #include #include -#include "frameworks/UBPlatformUtils.h" -#include "frameworks/UBFileSystemUtils.h" - -#include "core/UBApplication.h" -#include "core/UBSettings.h" -#include "core/UBSetting.h" - -#include "document/UBDocumentProxy.h" - -#include "adaptors/UBExportPDF.h" #include "adaptors/UBSvgSubsetAdaptor.h" #include "adaptors/UBThumbnailAdaptor.h" #include "adaptors/UBMetadataDcSubsetAdaptor.h" -#include "domain/UBGraphicsMediaItem.h" -#include "domain/UBGraphicsWidgetItem.h" -#include "domain/UBGraphicsPixmapItem.h" -#include "domain/UBGraphicsSvgItem.h" - #include "board/UBBoardController.h" -#include "board/UBBoardPaletteManager.h" +#include "core/UBApplication.h" +#include "core/UBSettings.h" +#include "core/UBSetting.h" + +#include "document/UBDocument.h" #include "document/UBDocumentController.h" +#include "document/UBDocumentProxy.h" +#include "document/UBToc.h" + +#include "frameworks/UBFileSystemUtils.h" #include "core/memcheck.h" @@ -423,6 +416,25 @@ QDialog::DialogCode UBPersistenceManager::processInteractiveReplacementDialog(st return result; } +/** + * @brief Create a list of all SVG page files ordered by number + * @param documentFolder Document folder + * @return Ordered list of page files + */ +QStringList UBPersistenceManager::pageFiles(const QString& documentFolder) +{ + // create list of SVG files + QDir dir{documentFolder}; + auto svgFiles = dir.entryList({ "page*.svg"}, QDir::Files); + + // sort list by page number + std::sort(svgFiles.begin(), svgFiles.end(), [](QString& left, QString& right){ + return left.mid(4, left.length() - 8).toInt() < right.mid(4, right.length() - 8).toInt(); + }); + + return svgFiles; +} + QString UBPersistenceManager::adjustDocumentVirtualPath(const QString &str) { QStringList pathList = str.split("/", UB::SplitBehavior::SkipEmptyParts); @@ -463,11 +475,6 @@ void UBPersistenceManager::closing() } } -bool UBPersistenceManager::isSceneInCached(std::shared_ptr proxy, int index) const -{ - return mSceneCache.contains(proxy, index); -} - QStringList UBPersistenceManager::allShapes() { QString shapeLibraryPath = UBSettings::settings()->applicationShapeLibraryDirectory(); @@ -595,18 +602,20 @@ std::shared_ptr UBPersistenceManager::createDocument(const QStr doc->setMetaData(UBSettings::documentUpdatedAt,currentDate); doc->setMetaData(UBSettings::documentDate,currentDate); - if (withEmptyPage) + generatePathIfNeeded(doc); + QDir dir(doc->persistencePath()); + if (!dir.mkpath(doc->persistencePath())) { - createDocumentSceneAt(doc, 0); + return nullptr; // if we can't create the path, abort function. } - else + + UBToc toc{doc->persistencePath()}; + + if (withEmptyPage) { - generatePathIfNeeded(doc); - QDir dir(doc->persistencePath()); - if (!dir.mkpath(doc->persistencePath())) - { - return nullptr; // if we can't create the path, abort function. - } + const auto pageId = toc.insert(0); + const auto scene = createDocumentSceneAt(doc, pageId); + toc.setUuid(0, scene->uuid()); } bool documentAdded = false; @@ -623,6 +632,7 @@ std::shared_ptr UBPersistenceManager::createDocument(const QStr if (documentAdded) { persistDocumentMetadata(doc); + toc.save(); } else { @@ -685,12 +695,15 @@ std::shared_ptr UBPersistenceManager::createDocumentFromDir(con doc->setUuid(QUuid::createUuid()); doc->setPageCount(sceneCount(doc)); + auto document = UBDocument::getDocument(doc); for(int i = 0; i < doc->pageCount(); i++) { UBSvgSubsetAdaptor::setSceneUuid(doc, i, QUuid::createUuid()); + UBThumbnailAdaptor::generateMissingThumbnail(document.get(), i); } + //work around the bool addDoc = false; if (!promptDialogIfExists) { @@ -759,51 +772,36 @@ std::shared_ptr UBPersistenceManager::duplicateDocument(std::sh } -void UBPersistenceManager::deleteDocumentScenes(std::shared_ptr proxy, const QList& indexes) +void UBPersistenceManager::deleteDocumentScenes(std::shared_ptr proxy, const QList& pageIds) { checkIfDocumentRepositoryExists(); int pageCount = proxy->pageCount(); - if (indexes.size() == pageCount) + if (pageIds.size() == pageCount) { deleteDocument(proxy); return; } - if (indexes.size() == 0) + if (pageIds.size() == 0) { return; } - for (auto index : indexes) + for (auto pageId : pageIds) { - QString svgFileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", index); + QString svgFileName = proxy->persistencePath() + sceneFilenameForId(pageId); QFile::remove(svgFileName); - QString thumbFileName = proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", index); + QString thumbFileName = proxy->persistencePath() + thumbnailFilenameForId(pageId); QFile::remove(thumbFileName); - mSceneCache.removeScene(proxy, index); + mSceneCache.removeScene(proxy, pageId); proxy->decPageCount(); } - int offset = 1; - - for (int i = indexes.at(0) + 1; i < pageCount; i++) - { - if (indexes.contains(i)) - { - offset++; - } - else - { - renamePage(proxy, i , i - offset); - mSceneCache.moveScene(proxy, i, i - offset); - } - } - // update metadata QDateTime now = QDateTime::currentDateTime(); proxy->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(now)); @@ -811,8 +809,8 @@ void UBPersistenceManager::deleteDocumentScenes(std::shared_ptr } -void UBPersistenceManager::copyDocumentScene(std::shared_ptr from, int fromIndex, - std::shared_ptr to, int toIndex, QList dependencies) +QUuid UBPersistenceManager::copyDocumentScene(std::shared_ptr from, int fromPageId, + std::shared_ptr to, int toPageId, QList dependencies) { checkIfDocumentRepositoryExists(); @@ -825,21 +823,8 @@ void UBPersistenceManager::copyDocumentScene(std::shared_ptr fr persistDocumentScene(from, scene, page, false, true); } - // make room - for (int i = to->pageCount(); i > toIndex; i--) - { - renamePage(to, i - 1, i); - mSceneCache.moveScene(to, i - 1, i); - } - - // adjust from index if necessary - if (from == to && toIndex <= fromIndex) - { - ++fromIndex; - } - // copy SVG and thumbnail - copyPage(from, fromIndex, to, toIndex); + const QUuid uuid = copyPage(from, fromPageId, to, toPageId); // copy dependencies, don't overwrite for (const auto relativeFile : dependencies) @@ -855,21 +840,14 @@ void UBPersistenceManager::copyDocumentScene(std::shared_ptr fr QDateTime now = QDateTime::currentDateTime(); to->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(now)); persistDocumentMetadata(to); + + return uuid; } -std::shared_ptr UBPersistenceManager::createDocumentSceneAt(std::shared_ptr proxy, int index, bool useUndoRedoStack) +std::shared_ptr UBPersistenceManager::createDocumentSceneAt(std::shared_ptr proxy, int pageId, bool useUndoRedoStack) { - int count = proxy->pageCount(); - - for(int i = count - 1; i >= index; i--) - { - renamePage(proxy, i , i + 1); - } - - mSceneCache.shiftUpScenes(proxy, index, count -1); - - std::shared_ptr newScene = mSceneCache.createScene(proxy, index, useUndoRedoStack); + std::shared_ptr newScene = mSceneCache.createScene(proxy, pageId, useUndoRedoStack); newScene->setBackground(UBSettings::settings()->isDarkBackground(), UBSettings::settings()->UBSettings::pageBackground()); @@ -878,107 +856,28 @@ std::shared_ptr UBPersistenceManager::createDocumentSceneAt(std proxy->incPageCount(); - persistDocumentScene(proxy, newScene, index); + persistDocumentScene(proxy, newScene, pageId); return newScene; } - -void UBPersistenceManager::insertDocumentSceneAt(std::shared_ptr proxy, std::shared_ptr scene, int index, bool persist, bool deleting) +std::shared_ptr UBPersistenceManager::loadDocumentScene(std::shared_ptr proxy, int pageId) { - scene->setDocument(proxy); - - int count = proxy->pageCount(); - - for(int i = count - 1; i >= index; i--) - { - renamePage(proxy, i , i + 1); - } - - mSceneCache.shiftUpScenes(proxy, index, count -1); - - mSceneCache.insert(proxy, index, scene); - - proxy->incPageCount(); - - if (persist) - { - persistDocumentScene(proxy, scene, index); - } -} - - -void UBPersistenceManager::moveSceneToIndex(std::shared_ptr proxy, int source, int target) -{ - checkIfDocumentRepositoryExists(); - - if (source == target) - return; - - auto scene = UBApplication::boardController->activeScene(); - - // save modified scene of the same document - if (scene && scene->document() == proxy && scene->isModified()) - { - auto page = UBApplication::boardController->activeSceneIndex(); - persistDocumentScene(proxy, scene, page, false, true); - } - - QFile svgTmp(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", source)); - svgTmp.rename(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.tmp", target)); - - QFile thumbTmp(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", source)); - thumbTmp.rename(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.tmp", target)); - - if (source < target) - { - for (int i = source + 1; i <= target; i++) - { - renamePage(proxy, i , i - 1); - } - } - else - { - for (int i = source - 1; i >= target; i--) - { - renamePage(proxy, i , i + 1); - } - } - - QFile svg(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.tmp", target)); - svg.rename(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", target)); - - QFile thumb(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.tmp", target)); - thumb.rename(proxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", target)); - - mSceneCache.moveScene(proxy, source, target); + mSceneCache.prepareLoading(proxy, pageId); + return mSceneCache.value(proxy, pageId); } - -std::shared_ptr UBPersistenceManager::loadDocumentScene(std::shared_ptr proxy, int sceneIndex, bool cacheNeighboringScenes) +void UBPersistenceManager::prepareSceneLoading(std::shared_ptr proxy, int pageId) { - mSceneCache.prepareLoading(proxy, sceneIndex); - auto scene = mSceneCache.value(proxy, sceneIndex); - qDebug() << "loadDocumentScene: got result from cache"; - - if (cacheNeighboringScenes) + if (!mSceneCache.contains(proxy, pageId)) { - if(sceneIndex + 1 < proxy->pageCount() && !mSceneCache.contains(proxy, sceneIndex + 1)) - mSceneCache.prepareLoading(proxy,sceneIndex+1); - - if(sceneIndex + 2 < proxy->pageCount() && !mSceneCache.contains(proxy, sceneIndex + 2)) - mSceneCache.prepareLoading(proxy,sceneIndex+2); - - if(sceneIndex - 1 >= 0 && !mSceneCache.contains(proxy, sceneIndex - 1)) - mSceneCache.prepareLoading(proxy,sceneIndex-1); + mSceneCache.prepareLoading(proxy, pageId); } - - return scene; } -std::shared_ptr UBPersistenceManager::getDocumentScene(std::shared_ptr pDocumentProxy, int sceneIndex) +std::shared_ptr UBPersistenceManager::getDocumentScene(std::shared_ptr pDocumentProxy, int pageId) { - return mSceneCache.value(pDocumentProxy, sceneIndex); + return mSceneCache.value(pDocumentProxy, pageId); } void UBPersistenceManager::reassignDocProxy(std::shared_ptr newDocument, std::shared_ptr oldDocument) @@ -986,7 +885,7 @@ void UBPersistenceManager::reassignDocProxy(std::shared_ptr new return mSceneCache.reassignDocProxy(newDocument, oldDocument); } -void UBPersistenceManager::persistDocumentScene(std::shared_ptr pDocumentProxy, std::shared_ptr pScene, const int pSceneIndex, bool isAnAutomaticBackup, bool forceImmediateSaving) +void UBPersistenceManager::persistDocumentScene(std::shared_ptr pDocumentProxy, std::shared_ptr pScene, int pageId, bool isAnAutomaticBackup, bool forceImmediateSaving) { checkIfDocumentRepositoryExists(); @@ -1000,21 +899,20 @@ void UBPersistenceManager::persistDocumentScene(std::shared_ptr if(forceImmediateSaving) { - UBSvgSubsetAdaptor::persistScene(pDocumentProxy, pScene, pSceneIndex); + UBSvgSubsetAdaptor::persistScene(pDocumentProxy, pScene, pageId); } else { std::shared_ptr copiedScene = pScene->sceneDeepCopy(); - mWorker->saveScene(pDocumentProxy, copiedScene.get(), pSceneIndex); + mWorker->saveScene(pDocumentProxy, copiedScene.get(), pageId); // keep copiedScene alive until saving is finished mScenesToSave.append(copiedScene); } - UBThumbnailAdaptor::persistScene(pDocumentProxy, pScene, pSceneIndex); pScene->setModified(false); - mSceneCache.insert(pDocumentProxy, pSceneIndex, pScene); + mSceneCache.insert(pDocumentProxy, pageId, pScene); } @@ -1040,22 +938,25 @@ std::shared_ptr UBPersistenceManager::persistDocumentMetadata(s void UBPersistenceManager::renamePage(std::shared_ptr pDocumentProxy, const int sourceIndex, const int targetIndex) { UBApplication::showMessage(tr("Renaming pages (%1/%2)").arg(sourceIndex).arg(pDocumentProxy->pageCount())); - QFile svg(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", sourceIndex)); - svg.rename(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", targetIndex)); + QFile svg(pDocumentProxy->persistencePath() + sceneFilenameForId(sourceIndex)); + svg.rename(pDocumentProxy->persistencePath() + sceneFilenameForId(targetIndex)); - QFile thumb(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", sourceIndex)); - thumb.rename(pDocumentProxy->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", targetIndex)); + QFile thumb(pDocumentProxy->persistencePath() + thumbnailFilenameForId(sourceIndex)); + thumb.rename(pDocumentProxy->persistencePath() + thumbnailFilenameForId(targetIndex)); } -void UBPersistenceManager::copyPage(std::shared_ptr source, const int sourceIndex, std::shared_ptr target, const int targetIndex) +QUuid UBPersistenceManager::copyPage(std::shared_ptr source, const int sourceIndex, std::shared_ptr target, const int targetIndex) { - const QString sourcePath = source->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", sourceIndex); - const QString targetPath = target->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", targetIndex); - UBSvgSubsetAdaptor::replicateScene(sourcePath, targetPath, QUuid::createUuid()); + QFile thumb(source->persistencePath() + thumbnailFilenameForId(sourceIndex)); + thumb.copy(target->persistencePath() + thumbnailFilenameForId(targetIndex)); - QFile thumb(source->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", sourceIndex)); - thumb.copy(target->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", targetIndex)); + const QString sourcePath = source->persistencePath() + sceneFilenameForId(sourceIndex); + const QString targetPath = target->persistencePath() + sceneFilenameForId(targetIndex); + + const QUuid uuid{QUuid::createUuid()}; + UBSvgSubsetAdaptor::replicateScene(sourcePath, targetPath, uuid); + return uuid; } @@ -1069,7 +970,7 @@ int UBPersistenceManager::sceneCount(const std::shared_ptr prox while (moreToProcess) { - QString fileName = pPath + UBFileSystemUtils::digitFileFormat("/page%1.svg", pageIndex); + QString fileName = pPath + sceneFilenameForId(pageIndex); QFile file(fileName); @@ -1092,12 +993,6 @@ int UBPersistenceManager::sceneCount(const std::shared_ptr prox return pageIndex; } -QStringList UBPersistenceManager::getSceneFileNames(const QString& folder) -{ - QDir dir(folder, "page???.svg", QDir::Name, QDir::Files); - return dir.entryList(); -} - QString UBPersistenceManager::generateUniqueDocumentPath(const QString& baseFolder) { QDateTime now = QDateTime::currentDateTime(); @@ -1111,6 +1006,15 @@ QString UBPersistenceManager::generateUniqueDocumentPath() return generateUniqueDocumentPath(UBSettings::userDocumentDirectory()); } +QString UBPersistenceManager::sceneFilenameForId(int id) +{ + return UBFileSystemUtils::digitFileFormat("/page%1.svg", id); +} + +QString UBPersistenceManager::thumbnailFilenameForId(int id) +{ + return UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", id); +} void UBPersistenceManager::generatePathIfNeeded(std::shared_ptr pDocumentProxy) { @@ -1123,7 +1027,7 @@ void UBPersistenceManager::generatePathIfNeeded(std::shared_ptr bool UBPersistenceManager::addDirectoryContentToDocument(const QString& documentRootFolder, std::shared_ptr pDocument) { - QStringList sourceScenes = getSceneFileNames(documentRootFolder); + QStringList sourceScenes = pageFiles(documentRootFolder); if (sourceScenes.empty()) return false; @@ -1134,14 +1038,14 @@ bool UBPersistenceManager::addDirectoryContentToDocument(const QString& document int targetIndex = targetPageCount + sourceIndex; QFile svg(documentRootFolder + "/" + sourceScenes[sourceIndex]); - if (!svg.copy(pDocument->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.svg", targetIndex))) + if (!svg.copy(pDocument->persistencePath() + sceneFilenameForId(targetIndex))) return false; UBSvgSubsetAdaptor::setSceneUuid(pDocument, targetIndex, QUuid::createUuid()); - QFile thumb(documentRootFolder + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", sourceIndex)); + QFile thumb(documentRootFolder + thumbnailFilenameForId(sourceIndex)); // We can ignore error in this case, thumbnail will be genarated - thumb.copy(pDocument->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", targetIndex)); + thumb.copy(pDocument->persistencePath() + thumbnailFilenameForId(targetIndex)); } foreach(QString dir, mDocumentSubDirectories) @@ -1161,30 +1065,6 @@ bool UBPersistenceManager::addDirectoryContentToDocument(const QString& document } -bool UBPersistenceManager::isEmpty(std::shared_ptr pDocumentProxy) -{ - if(!pDocumentProxy) - return true; - - if (pDocumentProxy->pageCount() > 1) - return false; - - std::shared_ptr theSoleScene = UBSvgSubsetAdaptor::loadScene(pDocumentProxy, 0); - - bool empty = false; - - if (theSoleScene) - { - empty = theSoleScene->isEmpty(); - } - else - { - empty = true; - } - - return empty; -} - bool UBPersistenceManager::addFileToDocument(std::shared_ptr pDocumentProxy, QString path, const QString& subdir, @@ -1328,78 +1208,6 @@ void UBPersistenceManager::loadFolderTreeFromXml(const QString &path, const QDom } } -void UBPersistenceManager::cleanupDocument(std::shared_ptr pDocumentProxy) const -{ - static QRegularExpression uuidPattern("{[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}}"); - - if (!pDocumentProxy->testAndResetCleanupNeeded()) - { - return; - } - - // scan pages and collect possible UUID references - const QString path = pDocumentProxy->persistencePath() + "/"; - const QStringList pages = getSceneFileNames(path); - - if (pages.length() > 0) - { - QSet references; - - for (const QString& page : pages) - { - QFile svgFile(path + page); - - if (svgFile.open(QFile::ReadOnly)) - { - const QString content = svgFile.readAll(); - auto matches = uuidPattern.globalMatch(content); - - while (matches.hasNext()) - { - QRegularExpressionMatch match = matches.next(); - references << match.captured(); - } - } - } - - // scan folders and remove unreferenced files and directories - static const QStringList folders = { ".", "audios", "videos", "objects" }; - - for (const QString& folder : folders) - { - QFileInfoList entries = QDir(path + folder).entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); - - for (const QFileInfo& entry : entries) - { - QRegularExpressionMatch match = uuidPattern.match(entry.fileName()); - - if (match.hasMatch() && !references.contains(match.captured())) - { - const QString filename = folder + "/" + entry.fileName(); - const QString absoluteFilePath = entry.absoluteFilePath(); - - // unreferenced file or directory - if (entry.isDir()) - { - qWarning() << "Deleting unreferenced directory" << filename; - UBFileSystemUtils::deleteDir(absoluteFilePath); - } - else - { - qWarning() << "Deleting unreferenced file" << filename; - UBFileSystemUtils::deleteFile(absoluteFilePath); - } - } - } - } - } - else - { - //in a network-storage context, can happen on a newly created document, depending on the client and the cache mode you're using - qWarning() << "could not find any pages for the document " << pDocumentProxy->persistencePath(); - } -} - bool UBPersistenceManager::mayHaveVideo(std::shared_ptr pDocumentProxy) { QDir videoDir(pDocumentProxy->persistencePath() + "/" + UBPersistenceManager::videoDirectory); diff --git a/src/core/UBPersistenceManager.h b/src/core/UBPersistenceManager.h index 403222691..b943618e9 100644 --- a/src/core/UBPersistenceManager.h +++ b/src/core/UBPersistenceManager.h @@ -98,20 +98,17 @@ class UBPersistenceManager : public QObject virtual void deleteDocument(std::shared_ptr pDocumentProxy); - virtual void deleteDocumentScenes(std::shared_ptr pDocumentProxy, const QList& indexes); + virtual void deleteDocumentScenes(std::shared_ptr pDocumentProxy, const QList& pageIds); - virtual void copyDocumentScene(std::shared_ptrfrom, int fromIndex, std::shared_ptrto, int toIndex, QList dependencies); + virtual QUuid copyDocumentScene(std::shared_ptrfrom, int fromPageId, std::shared_ptrto, int toPageId, QList dependencies); - virtual void persistDocumentScene(std::shared_ptr pDocumentProxy, std::shared_ptr pScene, const int pSceneIndex, bool isAnAutomaticBackup = false, bool forceImmediateSaving = false); + virtual void persistDocumentScene(std::shared_ptr pDocumentProxy, std::shared_ptr pScene, int pageId, bool isAnAutomaticBackup = false, bool forceImmediateSaving = false); - virtual std::shared_ptr createDocumentSceneAt(std::shared_ptr pDocumentProxy, int index, bool useUndoRedoStack = true); + virtual std::shared_ptr createDocumentSceneAt(std::shared_ptr pDocumentProxy, int pageId, bool useUndoRedoStack = true); - virtual void insertDocumentSceneAt(std::shared_ptr pDocumentProxy, std::shared_ptr scene, int index, bool persist = true, bool deleting = false); - - virtual void moveSceneToIndex(std::shared_ptr pDocumentProxy, int source, int target); - - virtual std::shared_ptr loadDocumentScene(std::shared_ptr pDocumentProxy, int sceneIndex, bool cacheNeighboringScenes = true); - std::shared_ptr getDocumentScene(std::shared_ptr pDocumentProxy, int sceneIndex); + virtual std::shared_ptr loadDocumentScene(std::shared_ptr pDocumentProxy, int pageId); + void prepareSceneLoading(std::shared_ptr proxy, int pageId); + std::shared_ptr getDocumentScene(std::shared_ptr pDocumentProxy, int pageId); void reassignDocProxy(std::shared_ptr newDocument, std::shared_ptr oldDocument); // QList > documentProxies; @@ -126,6 +123,8 @@ class UBPersistenceManager : public QObject QString generateUniqueDocumentPath(); QString generateUniqueDocumentPath(const QString& baseFolder); + static QString sceneFilenameForId(int id); + static QString thumbnailFilenameForId(int id); bool addDirectoryContentToDocument(const QString& documentRootFolder, std::shared_ptr pDocument); @@ -134,13 +133,13 @@ class UBPersistenceManager : public QObject static std::shared_ptr createDocumentProxyStructure(const QFileInfo &contentInfo); QDialog::DialogCode processInteractiveReplacementDialog(std::shared_ptr pProxy, bool multipleFiles = false); + QStringList pageFiles(const QString& documentFolder); + QStringList documentSubDirectories() { return mDocumentSubDirectories; } - virtual bool isEmpty(std::shared_ptr pDocumentProxy); - bool addGraphicsWidgetToDocument(std::shared_ptr mDocumentProxy, QString path, QUuid objectUuid, QString& destinationPath); bool addFileToDocument(std::shared_ptr pDocumentProxy, QString path, const QString& subdir, QUuid objectUuid, QString& destinationPath, QByteArray* data = NULL); @@ -153,7 +152,6 @@ class UBPersistenceManager : public QObject QString adjustDocumentVirtualPath(const QString &str); void closing(); - bool isSceneInCached(std::shared_ptrproxy, int index) const; signals: void documentCreated(std::shared_ptr pDocumentProxy); @@ -166,10 +164,9 @@ class UBPersistenceManager : public QObject private: static int sceneCount(const std::shared_ptr pDocumentProxy); - static QStringList getSceneFileNames(const QString& folder); void renamePage(std::shared_ptr pDocumentProxy, const int sourceIndex, const int targetIndex); - void copyPage(std::shared_ptr source, const int sourceIndex, + QUuid copyPage(std::shared_ptr source, const int sourceIndex, std::shared_ptr target, const int targetIndex); void generatePathIfNeeded(std::shared_ptr pDocumentProxy); void checkIfDocumentRepositoryExists(); @@ -177,8 +174,6 @@ class UBPersistenceManager : public QObject void saveFoldersTreeToXml(QXmlStreamWriter &writer, const QModelIndex &parentIndex); void loadFolderTreeFromXml(const QString &path, const QDomElement &element); - void cleanupDocument(std::shared_ptr pDocumentProxy) const; - QString xmlFolderStructureFilename; UBSceneCache mSceneCache; diff --git a/src/core/UBSceneCache.cpp b/src/core/UBSceneCache.cpp index fb5896d3a..4616564ef 100644 --- a/src/core/UBSceneCache.cpp +++ b/src/core/UBSceneCache.cpp @@ -52,33 +52,33 @@ UBSceneCache::~UBSceneCache() } -std::shared_ptr UBSceneCache::createScene(std::shared_ptr proxy, int pageIndex, bool useUndoRedoStack) +std::shared_ptr UBSceneCache::createScene(std::shared_ptr proxy, int pageId, bool useUndoRedoStack) { auto newScene = std::make_shared(proxy, useUndoRedoStack); - insert(proxy, pageIndex, newScene); + insert(proxy, pageId, newScene); return newScene; } -std::shared_ptr UBSceneCache::prepareLoading(std::shared_ptr proxy, int pageIndex) +std::shared_ptr UBSceneCache::prepareLoading(std::shared_ptr proxy, int pageId) { - if (mSceneCache.contains({proxy, pageIndex})) + if (mSceneCache.contains({proxy, pageId})) { - return value(proxy, pageIndex); + return value(proxy, pageId); } // no entry in cache; create a cache entry to load scene - qDebug() << "Preparing to load scene" << pageIndex; - auto cacheEntry = std::make_shared(proxy, pageIndex); + qDebug() << "Preparing to load scene" << pageId; + auto cacheEntry = std::make_shared(proxy, pageId); - insertEntry({proxy, pageIndex}, cacheEntry); + insertEntry({proxy, pageId}, cacheEntry); cacheEntry->startLoading(); return nullptr; } -void UBSceneCache::insert (std::shared_ptr proxy, int pageIndex, std::shared_ptr scene) +void UBSceneCache::insert (std::shared_ptr proxy, int pageId, std::shared_ptr scene) { // remove all entries pointing to this scene const auto keylist = mSceneCache.keys(); @@ -94,7 +94,7 @@ void UBSceneCache::insert (std::shared_ptr proxy, int pageIndex } } - UBSceneCacheID key{proxy, pageIndex}; + UBSceneCacheID key{proxy, pageId}; insertEntry(key, std::make_shared(scene)); // restore view state @@ -105,15 +105,15 @@ void UBSceneCache::insert (std::shared_ptr proxy, int pageIndex } -bool UBSceneCache::contains(std::shared_ptr proxy, int pageIndex) const +bool UBSceneCache::contains(std::shared_ptr proxy, int pageId) const { - return mSceneCache.contains({proxy, pageIndex}); + return mSceneCache.contains({proxy, pageId}); } -std::shared_ptr UBSceneCache::value(std::shared_ptr proxy, int pageIndex) +std::shared_ptr UBSceneCache::value(std::shared_ptr proxy, int pageId) { - UBSceneCacheID key{proxy, pageIndex}; + UBSceneCacheID key{proxy, pageId}; if (mSceneCache.contains(key)) { @@ -131,9 +131,9 @@ std::shared_ptr UBSceneCache::value(std::shared_ptr proxy, int pageIndex) +void UBSceneCache::removeScene(std::shared_ptr proxy, int pageId) { - UBSceneCacheID key{proxy, pageIndex}; + UBSceneCacheID key{proxy, pageId}; if (!mSceneCache.contains(key)) { @@ -291,18 +291,18 @@ void UBSceneCache::insertEntry(UBSceneCacheID key, std::shared_ptrisSceneAvailable() && !entry->scene()->isActive()) || !entry->isSceneAvailable()) { - qDebug() << "removing page" << key.pageIndex << "of" << key.documentProxy->documentFolderName(); - removeScene(key.documentProxy, key.pageIndex); + qDebug() << "removing page" << key.mPageId << "of" << key.mDocumentProxy->documentFolderName(); + removeScene(key.mDocumentProxy, key.mPageId); entry = nullptr; - qDebug() << "removed page" << key.pageIndex << "of" << key.documentProxy->documentFolderName(); + qDebug() << "removed page" << key.mPageId << "of" << key.mDocumentProxy->documentFolderName(); break; } } } -UBSceneCache::SceneCacheEntry::SceneCacheEntry(std::shared_ptr proxy, int pageIndex) +UBSceneCache::SceneCacheEntry::SceneCacheEntry(std::shared_ptr proxy, int pageId) { - mContext = UBSvgSubsetAdaptor::prepareLoadingScene(proxy, pageIndex); + mContext = UBSvgSubsetAdaptor::prepareLoadingScene(proxy, pageId); } UBSceneCache::SceneCacheEntry::SceneCacheEntry(std::shared_ptr scene) diff --git a/src/core/UBSceneCache.h b/src/core/UBSceneCache.h index 52e38adec..5c4b8ed22 100644 --- a/src/core/UBSceneCache.h +++ b/src/core/UBSceneCache.h @@ -32,8 +32,6 @@ #include -#include - #include "adaptors/UBSvgSubsetAdaptor.h" #include "domain/UBGraphicsScene.h" @@ -46,31 +44,31 @@ class UBSceneCacheID public: UBSceneCacheID() - : documentProxy(0) - , pageIndex(-1) + : mDocumentProxy(0) + , mPageId(-1) { // NOOP } - UBSceneCacheID(std::shared_ptr pDocumentProxy, int pPageIndex) + UBSceneCacheID(std::shared_ptr pDocumentProxy, int pageId) { - documentProxy = pDocumentProxy; - pageIndex = pPageIndex; + mDocumentProxy = pDocumentProxy; + mPageId = pageId; } - std::shared_ptr documentProxy; - int pageIndex; + std::shared_ptr mDocumentProxy; + int mPageId; }; inline bool operator==(const UBSceneCacheID &id1, const UBSceneCacheID &id2) { - return id1.documentProxy == id2.documentProxy - && id1.pageIndex == id2.pageIndex; + return id1.mDocumentProxy == id2.mDocumentProxy + && id1.mPageId == id2.mPageId; } inline uint qHash(const UBSceneCacheID &id) { - return qHash(id.pageIndex); + return qHash(id.mPageId); } @@ -80,17 +78,17 @@ class UBSceneCache UBSceneCache(); virtual ~UBSceneCache(); - std::shared_ptr createScene(std::shared_ptr proxy, int pageIndex, bool useUndoRedoStack); + std::shared_ptr createScene(std::shared_ptr proxy, int pageId, bool useUndoRedoStack); - std::shared_ptr prepareLoading(std::shared_ptr proxy, int pageIndex); + std::shared_ptr prepareLoading(std::shared_ptr proxy, int pageId); - void insert (std::shared_ptr proxy, int pageIndex, std::shared_ptr scene); + void insert (std::shared_ptr proxy, int pageId, std::shared_ptr scene); - bool contains(std::shared_ptr proxy, int pageIndex) const; + bool contains(std::shared_ptr proxy, int pageId) const; - std::shared_ptr value(std::shared_ptr proxy, int pageIndex); + std::shared_ptr value(std::shared_ptr proxy, int pageId); - void removeScene(std::shared_ptr proxy, int pageIndex); + void removeScene(std::shared_ptr proxy, int pageId); void removeAllScenes(std::shared_ptr proxy); @@ -105,7 +103,7 @@ class UBSceneCache class SceneCacheEntry { public: - SceneCacheEntry(std::shared_ptr proxy, int pageIndex); + SceneCacheEntry(std::shared_ptr proxy, int pageId); SceneCacheEntry(std::shared_ptr scene); ~SceneCacheEntry(); void startLoading(); diff --git a/src/core/UBSettings.cpp b/src/core/UBSettings.cpp index 645063e53..a6ebbdceb 100644 --- a/src/core/UBSettings.cpp +++ b/src/core/UBSettings.cpp @@ -74,7 +74,7 @@ const int UBSettings::sDefaultFontPixelSize = 36; const char *UBSettings::sDefaultFontFamily = "Arial"; const char *UBSettings::sDefaultFontStyleName = "Regular"; -QString UBSettings::currentFileVersion = "4.8.0"; +QString UBSettings::currentFileVersion = "4.9.0"; QBrush UBSettings::eraserBrushDarkBackground = QBrush(QColor(127, 127, 127, 80)); QBrush UBSettings::eraserBrushLightBackground = QBrush(QColor(127, 127, 127, 80)); diff --git a/src/document/CMakeLists.txt b/src/document/CMakeLists.txt index 73b1982fd..47aca1022 100644 --- a/src/document/CMakeLists.txt +++ b/src/document/CMakeLists.txt @@ -9,4 +9,8 @@ target_sources(${PROJECT_NAME} PRIVATE UBDocumentProxy.h UBSortFilterProxyModel.cpp UBSortFilterProxyModel.h + UBToc.cpp + UBToc.h + UBTocSerializer.cpp + UBTocSerializer.h ) diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index d95413228..dca1622b5 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -26,6 +26,7 @@ #include "core/UBApplication.h" #include "core/UBPersistenceManager.h" #include "document/UBDocumentController.h" +#include "document/UBToc.h" #include "gui/UBMainWindow.h" #include "gui/UBThumbnailScene.h" @@ -36,6 +37,7 @@ UBDocument::UBDocument(std::shared_ptr proxy) : mProxy(proxy) , mThumbnailScene(new UBThumbnailScene(this)) { + toc(); mThumbnailScene->createThumbnails(); } @@ -82,6 +84,7 @@ void UBDocument::deletePages(QList indexes) return; } + // sort list, remove duplicates std::sort(indexes.begin(), indexes.end()); indexes.erase(std::unique(indexes.begin(), indexes.end()), indexes.end()); @@ -90,57 +93,55 @@ void UBDocument::deletePages(QList indexes) auto trashDocProxy = UBPersistenceManager::persistenceManager()->createDocument(UBSettings::trashedDocumentGroupNamePrefix, sourceName, false); auto trashDocument = UBDocument::getDocument(trashDocProxy); int trashIndex = 0; + QList pageIds; for (auto index : indexes) { copyPage(index, trashDocument, trashIndex++); + pageIds << mToc->pageId(index); } // delete the scenes - UBPersistenceManager::persistenceManager()->deleteDocumentScenes(mProxy, indexes); + UBPersistenceManager::persistenceManager()->deleteDocumentScenes(mProxy, pageIds); for (int i = indexes.size() - 1; i >= 0; --i) { mThumbnailScene->deleteThumbnail(indexes.at(i), false); + mToc->remove(indexes.at(i)); emit UBPersistenceManager::persistenceManager()->documentSceneDeleted(mProxy, indexes.at(i)); } mThumbnailScene->renumberThumbnails(indexes.first()); mThumbnailScene->arrangeThumbnails(indexes.first()); + mToc->save(); } void UBDocument::duplicatePage(int index) { - const auto dependencies = pageRelativeDependencies(index); - UBPersistenceManager::persistenceManager()->copyDocumentScene(mProxy, index, mProxy, index + 1, dependencies); - mThumbnailScene->insertThumbnail(index + 1); + copyPage(index, this, index + 1); emit UBPersistenceManager::persistenceManager()->documentSceneDuplicated(mProxy, index + 1); } void UBDocument::movePage(int fromIndex, int toIndex) { - UBPersistenceManager::persistenceManager()->moveSceneToIndex(mProxy, fromIndex, toIndex); mThumbnailScene->moveThumbnail(fromIndex, toIndex); + mToc->move(fromIndex, toIndex); + mToc->save(); emit UBPersistenceManager::persistenceManager()->documentSceneMoved(mProxy, fromIndex, toIndex); } void UBDocument::copyPage(int fromIndex, std::shared_ptr to, int toIndex) { - const auto dependencies = pageRelativeDependencies(fromIndex); - UBPersistenceManager::persistenceManager()->copyDocumentScene(mProxy, fromIndex, to->proxy(), toIndex, dependencies); - to->mThumbnailScene->insertThumbnail(toIndex); -} - -void UBDocument::insertPage(std::shared_ptr scene, int index, bool persist, bool deleting) -{ - UBPersistenceManager::persistenceManager()->insertDocumentSceneAt(mProxy, scene, index, persist, deleting); - - mThumbnailScene->insertThumbnail(index); + copyPage(fromIndex, to.get(), toIndex); } std::shared_ptr UBDocument::createPage(int index, bool useUndoRedoStack) { - auto scene = UBPersistenceManager::persistenceManager()->createDocumentSceneAt(mProxy, index, useUndoRedoStack); + // create a new TOC entry for the page + auto pageId = mToc->insert(index); + auto scene = UBPersistenceManager::persistenceManager()->createDocumentSceneAt(mProxy, pageId, useUndoRedoStack); + mToc->setUuid(index, scene->uuid()); + mToc->save(); mThumbnailScene->insertThumbnail(index, scene); @@ -150,15 +151,55 @@ std::shared_ptr UBDocument::createPage(int index, bool useUndoR void UBDocument::persistPage(std::shared_ptr scene, int index, bool isAutomaticBackup, bool forceImmediateSaving) { - UBPersistenceManager::persistenceManager()->persistDocumentScene(mProxy, scene, index, isAutomaticBackup, + const auto pageId = mToc->pageId(index); + UBThumbnailAdaptor::persistScene(this, scene, index); + UBPersistenceManager::persistenceManager()->persistDocumentScene(mProxy, scene, pageId, isAutomaticBackup, forceImmediateSaving); + + const auto assets = scene->relativeDependencies(); + + if (assets != mToc->assets(index)) + { + mToc->setAssets(index, assets); + mToc->save(); + } + mThumbnailScene->reloadThumbnail(index); } -QList UBDocument::pageRelativeDependencies(int index) const +std::shared_ptr UBDocument::loadScene(int index, bool cacheNeighboringScenes) { - // TODO use TOC when available - auto scene = UBPersistenceManager::persistenceManager()->loadDocumentScene(mProxy, index, false); + if (cacheNeighboringScenes) + { + auto persistenceManager = UBPersistenceManager::persistenceManager(); + + if(index + 1 < pageCount()) + { + persistenceManager->prepareSceneLoading(mProxy, mToc->pageId(index + 1)); + } + + if(index + 2 < pageCount()) + { + persistenceManager->prepareSceneLoading(mProxy, mToc->pageId(index + 2)); + } + + if(index - 1 >= 0) + { + persistenceManager->prepareSceneLoading(mProxy, mToc->pageId(index - 1)); + } + } + + return UBPersistenceManager::persistenceManager()->loadDocumentScene(mProxy, toc()->pageId(index)); +} + +std::shared_ptr UBDocument::getScene(int index) +{ + return UBPersistenceManager::persistenceManager()->getDocumentScene(mProxy, toc()->pageId(index)); +} + +QList UBDocument::pageRelativeDependencies(int index) +{ + auto scene = loadScene(index, false); if (scene) { @@ -173,6 +214,51 @@ UBThumbnailScene* UBDocument::thumbnailScene() const return mThumbnailScene; } +UBToc* UBDocument::toc() +{ + if (!mToc) + { + mToc = new UBToc{mProxy->persistencePath()}; + + if (!mToc->load() || QVersionNumber::fromString(mProxy->metaData(UBSettings::documentVersion).toString()) < QVersionNumber(4, 9, 0)) + { + scan(); + mToc->save(); + } + } + + return mToc; +} + +int UBDocument::pageCount() +{ + return toc()->pageCount(); +} + +QString UBDocument::sceneFile(int index) +{ + if (index >= pageCount()) + { + qWarning() << "Index " << index << "above ToC size " << pageCount(); + return ""; + } + + const auto filename = UBPersistenceManager::persistenceManager()->sceneFilenameForId(mToc->pageId(index)); + return mProxy->persistencePath() + filename; +} + +QString UBDocument::thumbnailFile(int index) +{ + if (index >= pageCount()) + { + qWarning() << "Index " << index << "above ToC size " << pageCount(); + return ""; + } + + const auto filename = UBPersistenceManager::persistenceManager()->thumbnailFilenameForId(mToc->pageId(index)); + return mProxy->persistencePath() + filename; +} + /** * @brief Get document for proxy. * @@ -206,6 +292,83 @@ std::shared_ptr UBDocument::getDocument(std::shared_ptr tocSceneUuids; + + for (int i = 0; i < pageCount(); ++i) + { + tocSceneUuids.insert(mToc->uuid(i)); + } + + // Scan through the pages starting from the smallest number and counting up. + QStringList pages = UBPersistenceManager::persistenceManager()->pageFiles(mProxy->persistencePath()); + + // Load the scenes and check the media assets. + int pageProcessed = -1; + + for (const auto page : pages) + { + int pageId = page.mid(4, page.length() - 8).toInt(); + auto scene = UBPersistenceManager::persistenceManager()->loadDocumentScene(mProxy, pageId); + // Check the media asset UUIDs. + // TODO Really?? Convert it to a SHA-1 based UUIDv5 if needed. Copy the asset file in this case. + + // Check whether the tocSceneUuids already contains this scene. + // If yes, locate and update the TOC entry + if (tocSceneUuids.contains(scene->uuid())) + { + const int index = mToc->findUuid(scene->uuid()); + + if (index >= 0) + { + mToc->setAssets(index, scene->relativeDependencies()); + pageProcessed = index; + tocSceneUuids.remove(scene->uuid()); + } + } + else + { + // add the file name, thumbnail file name and asset list to the TOC after the last processed TOC entry + qDebug() << "scan: insert scene" << pageId << "at offset" << pageProcessed; + ++pageProcessed; + mToc->insert(pageProcessed); + mToc->setUuid(pageProcessed, scene->uuid()); + mToc->setPageId(pageProcessed, pageId); + mToc->setAssets(pageProcessed, scene->relativeDependencies()); + } + } + + // When finished, remove all scenes still in tocSceneUuids from the TOC. + // Those scenes might have been deleted using a previous version of OpenBoard. + for (const auto uuid : tocSceneUuids) + { + qDebug() << "scan: removing scene from TOC" << uuid; + mToc->remove(mToc->findUuid(uuid)); + } + + // TODO cleanup possibly later Go through the TOC and create a set of all referenced media assets. + // Delete all unreferenced media asset files. +} + +void UBDocument::copyPage(int fromIndex, UBDocument* to, int toIndex) +{ + const auto dependencies = pageRelativeDependencies(fromIndex); + + // copy scene + const auto pageId = to->mToc->insert(toIndex); + const auto uuid = UBPersistenceManager::persistenceManager()->copyDocumentScene(mProxy, mToc->pageId(fromIndex), to->proxy(), pageId, dependencies); + + // add thumbnail + to->mThumbnailScene->insertThumbnail(toIndex); + + // update target TOC + to->mToc->setUuid(toIndex, uuid); + to->mToc->setAssets(toIndex, dependencies); + to->mToc->save(); +} + std::shared_ptr UBDocument::findDocument(std::shared_ptr proxy) { if (!proxy) diff --git a/src/document/UBDocument.h b/src/document/UBDocument.h index 6cad5c620..5ebf78deb 100644 --- a/src/document/UBDocument.h +++ b/src/document/UBDocument.h @@ -31,6 +31,7 @@ class UBDocumentProxy; class UBGraphicsScene; class UBThumbnailScene; +class UBToc; /** @@ -58,22 +59,32 @@ class UBDocument void duplicatePage(int index); void movePage(int fromIndex, int toIndex); void copyPage(int fromIndex, std::shared_ptr to, int toIndex); - // FIXME invocations of insertPage are finally also just a copy - void insertPage(std::shared_ptr scene, int index, bool persist = true, bool deleting = false); std::shared_ptr createPage(int index, bool useUndoRedoStack = true); void persistPage(std::shared_ptr scene, int index, bool isAutomaticBackup = false, bool forceImmediateSaving = false); - QList pageRelativeDependencies(int index) const; + std::shared_ptr loadScene(int index, bool cacheNeighboringScenes = true); + std::shared_ptr getScene(int index); + QList pageRelativeDependencies(int index); UBThumbnailScene* thumbnailScene() const; + UBToc* toc(); + + int pageCount(); + + QString sceneFile(int index); + QString thumbnailFile(int index); static std::shared_ptr getDocument(std::shared_ptr proxy); private: + void scan(); + void copyPage(int fromIndex, UBDocument* to, int toIndex); + static std::shared_ptr findDocument(std::shared_ptr proxy); private: std::shared_ptr mProxy{nullptr}; UBThumbnailScene* mThumbnailScene{nullptr}; + UBToc* mToc{nullptr}; static QList> sDocuments; }; diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index bceb780be..d501c848b 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -3396,7 +3396,7 @@ bool UBDocumentController::isOKToOpenDocument(std::shared_ptr p if (docVersion.isEmpty() || docVersion.startsWith("4.1") || docVersion.startsWith("4.2") || docVersion.startsWith("4.3") || docVersion.startsWith("4.4") || docVersion.startsWith("4.5") - || docVersion.startsWith("4.6") || docVersion.startsWith("4.8")) // TODO UB 4.7 update if necessary + || docVersion.startsWith("4.6") || docVersion.startsWith("4.8") || docVersion.startsWith("4.9")) { // Invoke widget upgrader widgetUpgradeAdaptor.upgradeWidgets(proxy); diff --git a/src/document/UBToc.cpp b/src/document/UBToc.cpp new file mode 100644 index 000000000..12ee9c8b1 --- /dev/null +++ b/src/document/UBToc.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + +#include "UBToc.h" + +#include + +#include "document/UBTocSerializer.h" + +static const QString UUID{"uuid"}; +static const QString PAGE_ID{"id"}; +static const QString ASSETS("assets"); + +UBToc::UBToc(QString documentPath) + : mDocumentPath{documentPath} +{ +} + +QVersionNumber UBToc::version() const +{ + return mVersion; +} + +int UBToc::pageCount() const +{ + return mToc.count(); +} + +int UBToc::insert(int index) +{ + if (index >= 0 && index <= mToc.count()) + { + int pageId = nextAvailablePageId(); + mToc.insert(index, {{PAGE_ID, pageId}}); + return pageId; + } + + return -1; +} + +void UBToc::move(int fromIndex, int toIndex) +{ + if (fromIndex < 0 || fromIndex >= mToc.count() || toIndex < 0 || toIndex >= mToc.count()) + { + return; + } + + auto entry = mToc.at(fromIndex); + mToc.removeAt(fromIndex); + mToc.insert(toIndex, entry); +} + +void UBToc::remove(int index) +{ + if (index >= 0 && index < mToc.count()) + { + mToc.remove(index); + } +} + +QUuid UBToc::uuid(int index) const +{ + if (index < 0 || index >= mToc.count()) + { + return {}; + } + + return mToc.at(index).value(UUID).toUuid(); +} + +void UBToc::setUuid(int index, const QUuid& uuid) +{ + if (index < 0) + { + return; + } + + assureSize(index); + mToc[index][UUID] = uuid; +} + +int UBToc::findUuid(const QUuid& sceneUuid) +{ + for (int i = 0; i < mToc.size(); ++i) + { + if (uuid(i) == sceneUuid) + { + return i; + } + } + + return -1; +} + +int UBToc::pageId(int index) const +{ + if (index < 0 || index >= mToc.count()) + { + return -1; + } + + return mToc.at(index).value(PAGE_ID).toInt(); +} + +void UBToc::setPageId(int index, int pageId) +{ + if (index < 0) + { + return; + } + + assureSize(index); + mToc[index][PAGE_ID] = pageId; +} + +QStringList UBToc::assets(int index) const +{ + if (index < 0 || index >= mToc.count()) + { + return {}; + } + + return mToc.at(index).value(ASSETS).toStringList(); +} + +void UBToc::setAssets(int index, const QStringList& assets) +{ + if (index < 0) + { + return; + } + + assureSize(index); + mToc[index][ASSETS] = assets; +} + +bool UBToc::load() +{ + UBTocJsonSerializer serializer(mDocumentPath); + const auto ok = serializer.load(mVersion, mToc); + + for (const auto& entry : mToc) + { + mNextAvailablePageId = std::max(mNextAvailablePageId, entry[PAGE_ID].toInt() + 1); + } + + return ok; +} + +void UBToc::save() const +{ + UBTocJsonSerializer serializer(mDocumentPath); + serializer.save(mVersion, mToc); +} + +int UBToc::nextAvailablePageId() +{ + return mNextAvailablePageId++; +} + +void UBToc::assureSize(int index) +{ + if (index >= mToc.count()) + { + mToc.resize(index + 1); + } +} diff --git a/src/document/UBToc.h b/src/document/UBToc.h new file mode 100644 index 000000000..e59872995 --- /dev/null +++ b/src/document/UBToc.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015-2025API of Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + +#pragma once + +#include +#include +#include +#include + + +static const QVersionNumber TOC_VERSION{1, 0}; + +class UBToc +{ +public: + UBToc(QString documentPath); + + QVersionNumber version() const; + + // size + int pageCount() const; + + // insert, move and remove + int insert(int index); + void move(int fromIndex, int toIndex); + void remove(int index); + + // access values + QUuid uuid(int index) const; + void setUuid(int index, const QUuid& uuid); + int findUuid(const QUuid& sceneUuid); + + int pageId(int index) const; + void setPageId(int index, int pageId); + + QStringList assets(int index) const; + void setAssets(int index, const QStringList& assets); + + // load and save + bool load(); + void save() const; + + // next available pageId + int nextAvailablePageId(); + +private: + void assureSize(int index); + +private: + QString mDocumentPath; + QVersionNumber mVersion{TOC_VERSION}; + QVector mToc; + int mNextAvailablePageId{0}; +}; diff --git a/src/document/UBTocSerializer.cpp b/src/document/UBTocSerializer.cpp new file mode 100644 index 000000000..0de392e0c --- /dev/null +++ b/src/document/UBTocSerializer.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2015-2025API of Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + +#include "UBTocSerializer.h" + +#include +#include +#include +#include + +static const QString VERSION{"version"}; +static const QString PAGES("pages"); + +UBTocSerializer::UBTocSerializer(QString path) + : mPath{path} +{ +} + +UBTocJsonSerializer::UBTocJsonSerializer(QString filename) + : UBTocSerializer{filename} +{ +} + +bool UBTocJsonSerializer::load(QVersionNumber& version, QVector& toc) +{ + if (!toc.isEmpty()) + { + qWarning() << "Refused to load non-empty TOC"; + return false; + } + + QFile file{mPath + "/toc.json"}; + + if (!file.open(QFile::ReadOnly)) + { + qDebug() << "Cannot load TOC: Cannot open file" << file.fileName(); + return false; + } + + const auto json = file.readAll(); + file.close(); + QJsonParseError error; + const auto jsonDoc = QJsonDocument::fromJson(json, &error); + + if (error.error != QJsonParseError::NoError) + { + qWarning() << "Parse error reading TOC:" << error.errorString() << "at" << error.offset; + return false; + } + + if (!jsonDoc.isObject()) + { + qWarning() << "Error reading TOC: JSON document is not an object"; + return false; + } + + version = QVersionNumber::fromString(jsonDoc.object().value(VERSION).toString()); + + const auto pages = jsonDoc.object().value(PAGES); + + if (!pages.isArray()) + { + qWarning() << "Error reading TOC: pages is not an array"; + return false; + } + + int index = 0; + + toc.resize(pages.toArray().size()); + + for (const auto entry : pages.toArray()) + { + if (!entry.isObject()) + { + qWarning() << "Error reading TOC: JSON entry is not an object"; + return false; + } + + toc[index++] = entry.toObject().toVariantMap(); + } + + return true; +} + +bool UBTocJsonSerializer::save(const QVersionNumber& version, const QVector& toc) +{ + QJsonArray list; + + for (const auto entry : toc) + { + list.append(QJsonObject::fromVariantMap(entry)); + } + + QJsonObject document; + document[VERSION] = version.toString(); + document[PAGES] = list; + + QJsonDocument doc{document}; + auto json = doc.toJson(QJsonDocument::Indented); + + // reduce indentation to one space + json.replace(" ", " "); + + QFile file{mPath + "/toc.json"}; + + if (!file.open(QFile::WriteOnly)) + { + qWarning() << "Cannot save TOC: Cannot open file" << file.fileName(); + return false; + } + + file.write(json); + file.close(); + return true; +} diff --git a/src/document/UBTocSerializer.h b/src/document/UBTocSerializer.h new file mode 100644 index 000000000..87764d667 --- /dev/null +++ b/src/document/UBTocSerializer.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015-2025API of Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + +#pragma once + +#include +#include +#include +#include + + +class UBTocSerializer +{ +public: + UBTocSerializer(QString path); + virtual ~UBTocSerializer() = default; + + virtual bool load(QVersionNumber& version, QVector& toc) = 0; + virtual bool save(const QVersionNumber& version, const QVector& toc) = 0; + +protected: + QString mPath; +}; + + +class UBTocJsonSerializer : public UBTocSerializer +{ +public: + UBTocJsonSerializer(QString filename); + virtual ~UBTocJsonSerializer() = default; + + virtual bool load(QVersionNumber& version, QVector& toc) override; + virtual bool save(const QVersionNumber& version, const QVector& toc) override; +}; diff --git a/src/document/document.pri b/src/document/document.pri index 5815df9f3..1cb581c87 100644 --- a/src/document/document.pri +++ b/src/document/document.pri @@ -3,11 +3,14 @@ HEADERS += \ src/document/UBDocumentContainer.h \ src/document/UBDocumentController.h \ src/document/UBDocumentProxy.h \ - src/document/UBSortFilterProxyModel.h + src/document/UBSortFilterProxyModel.h \ + src/document/UBToc.h \ + src/document/UBTocSerializer.h SOURCES += \ src/document/UBDocument.cpp \ src/document/UBDocumentContainer.cpp \ src/document/UBDocumentController.cpp \ src/document/UBDocumentProxy.cpp \ - src/document/UBSortFilterProxyModel.cpp - + src/document/UBSortFilterProxyModel.cpp \ + src/document/UBToc.cpp \ + src/document/UBTocSerializer.cpp diff --git a/src/gui/UBBoardThumbnailsView.cpp b/src/gui/UBBoardThumbnailsView.cpp index a2d0acfd6..876bce6fd 100644 --- a/src/gui/UBBoardThumbnailsView.cpp +++ b/src/gui/UBBoardThumbnailsView.cpp @@ -150,7 +150,7 @@ void UBBoardThumbnailsView::ensureVisibleThumbnail(int index) if (currentThumbnail) { - std::shared_ptr pageScene = UBPersistenceManager::persistenceManager()->getDocumentScene(mDocument->proxy(), index); + std::shared_ptr pageScene = mDocument->getScene(index); currentThumbnail->setPageScene(pageScene); ensureVisible(currentThumbnail); } diff --git a/src/gui/UBThumbnailScene.cpp b/src/gui/UBThumbnailScene.cpp index bd2e1403d..8b5bf0eb1 100644 --- a/src/gui/UBThumbnailScene.cpp +++ b/src/gui/UBThumbnailScene.cpp @@ -33,7 +33,7 @@ UBThumbnailScene::UBThumbnailScene(UBDocument* document) : mDocument{document} - , mThumbnailItems{document->proxy()->pageCount()} + , mThumbnailItems{} { } @@ -156,7 +156,7 @@ UBThumbnail* UBThumbnailScene::thumbnailAt(int index) // create the missing thumbnail auto thumbnailItem = new UBThumbnail; - thumbnailItem->setPixmap(UBThumbnailAdaptor::get(mDocument->proxy(), index)); + thumbnailItem->setPixmap(UBThumbnailAdaptor::get(mDocument, index)); thumbnailItem->setSceneIndex(index); mThumbnailItems[index] = thumbnailItem; @@ -190,6 +190,9 @@ UBThumbnail* UBThumbnailScene::lastSelectedThumbnail() const */ void UBThumbnailScene::createThumbnails(int startIndex) { + // adjust number of thumbnail items + mThumbnailItems.resize(mDocument->pageCount()); + // skip already loaded thumbnails while (startIndex < mThumbnailItems.count() && mThumbnailItems.at(startIndex)) { @@ -199,9 +202,16 @@ void UBThumbnailScene::createThumbnails(int startIndex) // create the list of all thumbnail paths QList> paths; - for (int index = startIndex; index < mDocument->proxy()->pageCount(); ++index) + for (int index = startIndex; index < mDocument->pageCount(); ++index) { - paths << std::pair{index, UBThumbnailAdaptor::thumbnailUrl(mDocument->proxy(), index).toLocalFile()}; + const auto thumbnailPath = UBThumbnailAdaptor::thumbnailUrl(mDocument, index).toLocalFile(); + + if (!QFile::exists(thumbnailPath)) + { + UBThumbnailAdaptor::generateMissingThumbnail(mDocument, index); + } + + paths << std::pair{index, thumbnailPath}; } // start background loading of files @@ -240,7 +250,7 @@ void UBThumbnailScene::insertThumbnail(int pageIndex, std::shared_ptrproxy(), pageScene, pageIndex); + UBThumbnailAdaptor::persistScene(mDocument, pageScene, pageIndex); } if (pageIndex <= mThumbnailItems.size()) @@ -252,7 +262,7 @@ void UBThumbnailScene::insertThumbnail(int pageIndex, std::shared_ptrsetPixmap(UBThumbnailAdaptor::get(mDocument->proxy(), pageIndex)); + thumbnailItem->setPixmap(UBThumbnailAdaptor::get(mDocument, pageIndex)); thumbnailItem->setSceneIndex(pageIndex); mThumbnailItems.insert(pageIndex, thumbnailItem); @@ -339,7 +349,7 @@ void UBThumbnailScene::reloadThumbnail(int pageIndex) if (thumbnail) { - thumbnail->setPixmap(UBThumbnailAdaptor::get(mDocument->proxy(), pageIndex)); + thumbnail->setPixmap(UBThumbnailAdaptor::get(mDocument, pageIndex)); arrangeThumbnails(pageIndex, pageIndex + 1); } } @@ -408,7 +418,7 @@ void UBThumbnailScene::loadNextThumbnail() if (result.second.isEmpty()) { - pixmap = UBThumbnailAdaptor::generateMissingThumbnail(mDocument->proxy(), index); + pixmap = UBThumbnailAdaptor::generateMissingThumbnail(mDocument, index); } else { From ca7d7f449afc9f701fde856ecf73fdb771ce5d40 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sat, 26 Apr 2025 15:18:52 +0200 Subject: [PATCH 013/133] refactor: switch pageCount to UBDocument - use UBDocument::pageCount() instead of UBDocumentProxy::pageCount() - use UBDocument in signals sent to UBBoardController to ease this transition - use UBDocument when importing UBZ - use QMap for UBSceneCache so that all entries for one document are grouped - add a variable containint the active UBDocument to UBDocumentContainer - remove pageCount from UBDocumentProxy no longer used, replaced by UBDocument::pageCount - also remove UBPersistenceManager::sceneCount, obsoleted by UBDocument::scan Signed-off-by: letsfindaway --- src/adaptors/UBExportFullPDF.cpp | 5 +- src/api/UBWidgetUniboardAPI.cpp | 2 +- src/board/UBBoardController.cpp | 33 +++---- src/board/UBBoardController.h | 6 +- src/board/UBBoardPaletteManager.cpp | 4 +- src/core/UBDocumentManager.cpp | 4 +- src/core/UBPersistenceManager.cpp | 119 +++----------------------- src/core/UBPersistenceManager.h | 10 +-- src/core/UBSceneCache.cpp | 44 +++------- src/core/UBSceneCache.h | 21 ++--- src/document/UBDocument.cpp | 19 +++- src/document/UBDocumentContainer.cpp | 21 +++-- src/document/UBDocumentContainer.h | 8 +- src/document/UBDocumentController.cpp | 23 +++-- src/document/UBDocumentProxy.cpp | 48 +---------- src/document/UBDocumentProxy.h | 9 -- 16 files changed, 115 insertions(+), 261 deletions(-) diff --git a/src/adaptors/UBExportFullPDF.cpp b/src/adaptors/UBExportFullPDF.cpp index 56027280c..c2188b4fa 100644 --- a/src/adaptors/UBExportFullPDF.cpp +++ b/src/adaptors/UBExportFullPDF.cpp @@ -77,7 +77,9 @@ UBExportFullPDF::~UBExportFullPDF() void UBExportFullPDF::saveOverlayPdf(std::shared_ptr pDocumentProxy, const QString& filename) { - if (!pDocumentProxy || filename.length() == 0 || pDocumentProxy->pageCount() == 0) + auto document = UBDocument::getDocument(pDocumentProxy); + + if (!document || filename.length() == 0 || document->pageCount() == 0) return; /* @@ -102,7 +104,6 @@ void UBExportFullPDF::saveOverlayPdf(std::shared_ptr pDocumentP pdfPrinter.setFullPage(true); QPainter* pdfPainter = 0; - auto document = UBDocument::getDocument(pDocumentProxy); for(int pageIndex = 0 ; pageIndex < document->pageCount(); pageIndex++) { diff --git a/src/api/UBWidgetUniboardAPI.cpp b/src/api/UBWidgetUniboardAPI.cpp index 6ad579099..fade7ce31 100644 --- a/src/api/UBWidgetUniboardAPI.cpp +++ b/src/api/UBWidgetUniboardAPI.cpp @@ -354,7 +354,7 @@ int UBWidgetUniboardAPI::pageCount() const auto scene = mScene.lock(); if (scene && scene->document()) - return scene->document()->pageCount(); + return UBDocument::getDocument(scene->document())->pageCount(); else return -1; } diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index c701d2025..21c1bd660 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -493,10 +493,10 @@ void UBBoardController::saveData(SaveFlags fls) } } -void UBBoardController::documentSceneDuplicated(std::shared_ptr proxy, int index) +void UBBoardController::documentSceneDuplicated(UBDocument* document, int index) { // index is duplicated page - if (selectedDocument() == proxy) + if (selectedDocument() == document->proxy()) { if (UBApplication::applicationController->displayMode() == UBApplicationController::Board) { @@ -511,9 +511,9 @@ void UBBoardController::documentSceneDuplicated(std::shared_ptr } } -void UBBoardController::documentSceneMoved(std::shared_ptr proxy, int fromIndex, int toIndex) +void UBBoardController::documentSceneMoved(UBDocument* document, int fromIndex, int toIndex) { - if (selectedDocument() == proxy) + if (selectedDocument() == document->proxy()) { int nextSceneIndex = mActiveSceneIndex; @@ -549,13 +549,13 @@ void UBBoardController::documentSceneMoved(std::shared_ptr prox } } -void UBBoardController::documentSceneDeleted(std::shared_ptr proxy, int index) +void UBBoardController::documentSceneDeleted(UBDocument* document, int index) { - if (selectedDocument() == proxy) + if (selectedDocument() == document->proxy()) { int nextSceneIndex = mActiveSceneIndex; - if (index < mActiveSceneIndex || (index == mActiveSceneIndex && index == proxy->pageCount() && index > 0)) + if (index < mActiveSceneIndex || (index == mActiveSceneIndex && index == document->pageCount() && index > 0)) { --nextSceneIndex; } @@ -869,22 +869,23 @@ UBGraphicsItem *UBBoardController::duplicateItem(UBItem *item) void UBBoardController::deleteScene(int nIndex) { - if (selectedDocument()->pageCount()>=2) + auto document = UBDocument::getDocument(selectedDocument()); + + if (document->pageCount() >= 2) { mDeletingSceneIndex = nIndex; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); persistCurrentScene(); UBApplication::showMessage(tr("Deleting page %1").arg(nIndex+1), true); - auto document = UBDocument::getDocument(selectedDocument()); document->deletePages({nIndex}); QDateTime now = QDateTime::currentDateTime(); selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(now)); UBMetadataDcSubsetAdaptor::persist(selectedDocument()); - if (nIndex >= pageCount()) - nIndex = pageCount()-1; + if (nIndex >= document->pageCount()) + nIndex = document->pageCount()-1; setActiveDocumentScene(nIndex); UBApplication::showMessage(tr("Page %1 deleted").arg(nIndex+1)); QApplication::restoreOverrideCursor(); @@ -1139,7 +1140,7 @@ void UBBoardController::previousScene() void UBBoardController::nextScene() { - if (mActiveSceneIndex < selectedDocument()->pageCount() - 1) + if (mActiveSceneIndex < activeDocument()->pageCount() - 1) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); setActiveDocumentScene(mActiveSceneIndex + 1); @@ -1165,10 +1166,10 @@ void UBBoardController::firstScene() void UBBoardController::lastScene() { - if (mActiveSceneIndex < selectedDocument()->pageCount() - 1) + if (mActiveSceneIndex < activeDocument()->pageCount() - 1) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - setActiveDocumentScene(selectedDocument()->pageCount() - 1); + setActiveDocumentScene(activeDocument()->pageCount() - 1); QApplication::restoreOverrideCursor(); } @@ -1954,7 +1955,7 @@ void UBBoardController::undoRedoStateChange(bool canUndo) void UBBoardController::updateActionStates() { mMainWindow->actionBack->setEnabled(selectedDocument() && (mActiveSceneIndex > 0)); - mMainWindow->actionForward->setEnabled(selectedDocument() && (mActiveSceneIndex < selectedDocument()->pageCount() - 1)); + mMainWindow->actionForward->setEnabled(selectedDocument() && (mActiveSceneIndex < activeDocument()->pageCount() - 1)); mMainWindow->actionErase->setEnabled(mActiveScene && !mActiveScene->isEmpty()); } @@ -2748,7 +2749,7 @@ void UBBoardController::addItem() void UBBoardController::importPage() { - int pageCount = selectedDocument()->pageCount(); + int pageCount = activeDocument()->pageCount(); if (UBApplication::documentController->addFileToDocument(selectedDocument())) { setActiveDocumentScene(selectedDocument(), pageCount, true); diff --git a/src/board/UBBoardController.h b/src/board/UBBoardController.h index 605e56034..258b48a59 100644 --- a/src/board/UBBoardController.h +++ b/src/board/UBBoardController.h @@ -253,9 +253,9 @@ class UBBoardController : public UBDocumentContainer void saveData(SaveFlags fls = sf_none); - void documentSceneDuplicated(std::shared_ptr proxy, int index); - void documentSceneMoved(std::shared_ptr proxy, int fromIndex, int toIndex); - void documentSceneDeleted(std::shared_ptr proxy, int index); + void documentSceneDuplicated(UBDocument* document, int index); + void documentSceneMoved(UBDocument* document, int fromIndex, int toIndex); + void documentSceneDeleted(UBDocument* document, int index); signals: void newPageAdded(); diff --git a/src/board/UBBoardPaletteManager.cpp b/src/board/UBBoardPaletteManager.cpp index 71b895837..852281ac4 100644 --- a/src/board/UBBoardPaletteManager.cpp +++ b/src/board/UBBoardPaletteManager.cpp @@ -38,6 +38,8 @@ #include "core/UBSetting.h" #include "core/UBDisplayManager.h" +#include "document/UBDocument.h" + #include "gui/UBMainWindow.h" #include "gui/UBStylusPalette.h" #include "gui/UBKeyboardPalette.h" @@ -577,7 +579,7 @@ void UBBoardPaletteManager::activeSceneChanged() if (mpPageNavigWidget) { - mpPageNavigWidget->setPageNumber(UBDocumentContainer::pageFromSceneIndex(pageIndex), activeScene->document()->pageCount()); + mpPageNavigWidget->setPageNumber(UBDocumentContainer::pageFromSceneIndex(pageIndex), UBApplication::boardController->activeDocument()->pageCount()); } if (mZoomPalette) diff --git a/src/core/UBDocumentManager.cpp b/src/core/UBDocumentManager.cpp index c56774d27..fcfb20f76 100644 --- a/src/core/UBDocumentManager.cpp +++ b/src/core/UBDocumentManager.cpp @@ -243,7 +243,7 @@ int UBDocumentManager::addFilesToDocument(std::shared_ptr docum { int nImportedDocuments = 0; auto doc = UBDocument::getDocument(document); - const auto currentNumberOfPages = document->pageCount(); + const auto currentNumberOfPages = doc->pageCount(); foreach(const QString& fileName, fileNames) { @@ -299,7 +299,7 @@ int UBDocumentManager::addFilesToDocument(std::shared_ptr docum foreach(UBGraphicsItem* page, pages) { UBApplication::showMessage(tr("Inserting page %1 of %2").arg(++nPage).arg(pages.size()), true); - int pageIndex = document->pageCount(); + int pageIndex = doc->pageCount(); std::shared_ptr scene = doc->createPage(pageIndex); importAdaptor->placeImportedItemToScene(scene, page); doc->persistPage(scene, pageIndex); diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index b511667ad..eb2512370 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -264,14 +264,6 @@ std::shared_ptr UBPersistenceManager::createDocumentProxyStruct docProxy->setMetaData(key, metadatas.value(key)); } - docProxy->setPageCount(sceneCount(docProxy)); - - if (docProxy->pageCount() == 0) - { - qWarning() << "No pages found - " << fullPath; - docProxy->setMetaData(UBSettings::documentName, tr("Broken - %1").arg(contentInfo.baseName())); - } - return docProxy; }; @@ -580,7 +572,6 @@ std::shared_ptr UBPersistenceManager::createDocument(const QStr if(directory.length() != 0 ) { doc = std::make_shared(directory); - doc->setPageCount(pageCount); } else{ checkIfDocumentRepositoryExists(); @@ -694,10 +685,9 @@ std::shared_ptr UBPersistenceManager::createDocumentFromDir(con } doc->setUuid(QUuid::createUuid()); - doc->setPageCount(sceneCount(doc)); auto document = UBDocument::getDocument(doc); - for(int i = 0; i < doc->pageCount(); i++) + for(int i = 0; i < document->pageCount(); i++) { UBSvgSubsetAdaptor::setSceneUuid(doc, i, QUuid::createUuid()); UBThumbnailAdaptor::generateMissingThumbnail(document.get(), i); @@ -745,12 +735,6 @@ std::shared_ptr UBPersistenceManager::duplicateDocument(std::sh UBFileSystemUtils::copyDir(pDocumentProxy->persistencePath(), copy->persistencePath()); - // regenerate scenes UUIDs - for(int i = 0; i < pDocumentProxy->pageCount(); i++) - { - UBSvgSubsetAdaptor::setSceneUuid(pDocumentProxy, i, QUuid::createUuid()); - } - foreach(QString key, pDocumentProxy->metaDatas().keys()) { copy->setMetaData(key, pDocumentProxy->metaDatas().value(key)); @@ -763,8 +747,6 @@ std::shared_ptr UBPersistenceManager::duplicateDocument(std::sh persistDocumentMetadata(copy); - copy->setPageCount(copy->pageCount()); - emit documentCreated(copy); return copy; @@ -776,14 +758,6 @@ void UBPersistenceManager::deleteDocumentScenes(std::shared_ptr { checkIfDocumentRepositoryExists(); - int pageCount = proxy->pageCount(); - - if (pageIds.size() == pageCount) - { - deleteDocument(proxy); - return; - } - if (pageIds.size() == 0) { return; @@ -798,8 +772,6 @@ void UBPersistenceManager::deleteDocumentScenes(std::shared_ptr QFile::remove(thumbFileName); mSceneCache.removeScene(proxy, pageId); - - proxy->decPageCount(); } // update metadata @@ -834,8 +806,6 @@ QUuid UBPersistenceManager::copyDocumentScene(std::shared_ptr f UBFileSystemUtils::copy(source, target, false); } - to->incPageCount(); - // update metadata QDateTime now = QDateTime::currentDateTime(); to->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(now)); @@ -854,8 +824,6 @@ std::shared_ptr UBPersistenceManager::createDocumentSceneAt(std newScene->setBackgroundGridSize(UBSettings::settings()->crossSize); - proxy->incPageCount(); - persistDocumentScene(proxy, newScene, pageId); return newScene; @@ -880,11 +848,6 @@ std::shared_ptr UBPersistenceManager::getDocumentScene(std::sha return mSceneCache.value(pDocumentProxy, pageId); } -void UBPersistenceManager::reassignDocProxy(std::shared_ptr newDocument, std::shared_ptr oldDocument) -{ - return mSceneCache.reassignDocProxy(newDocument, oldDocument); -} - void UBPersistenceManager::persistDocumentScene(std::shared_ptr pDocumentProxy, std::shared_ptr pScene, int pageId, bool isAnAutomaticBackup, bool forceImmediateSaving) { checkIfDocumentRepositoryExists(); @@ -935,17 +898,6 @@ std::shared_ptr UBPersistenceManager::persistDocumentMetadata(s } -void UBPersistenceManager::renamePage(std::shared_ptr pDocumentProxy, const int sourceIndex, const int targetIndex) -{ - UBApplication::showMessage(tr("Renaming pages (%1/%2)").arg(sourceIndex).arg(pDocumentProxy->pageCount())); - QFile svg(pDocumentProxy->persistencePath() + sceneFilenameForId(sourceIndex)); - svg.rename(pDocumentProxy->persistencePath() + sceneFilenameForId(targetIndex)); - - QFile thumb(pDocumentProxy->persistencePath() + thumbnailFilenameForId(sourceIndex)); - thumb.rename(pDocumentProxy->persistencePath() + thumbnailFilenameForId(targetIndex)); -} - - QUuid UBPersistenceManager::copyPage(std::shared_ptr source, const int sourceIndex, std::shared_ptr target, const int targetIndex) { QFile thumb(source->persistencePath() + thumbnailFilenameForId(sourceIndex)); @@ -960,39 +912,6 @@ QUuid UBPersistenceManager::copyPage(std::shared_ptr source, co } -int UBPersistenceManager::sceneCount(const std::shared_ptr proxy) -{ - const QString pPath = proxy->persistencePath(); - - int pageIndex = 0; - bool moreToProcess = true; - bool addedMissingZeroPage = false; - - while (moreToProcess) - { - QString fileName = pPath + sceneFilenameForId(pageIndex); - - QFile file(fileName); - - if (file.exists()) - { - pageIndex++; - } - else - { - moreToProcess = false; - } - } - - if(pageIndex == 1 && addedMissingZeroPage){ - // increment is done only to check if there are other pages than the missing zero page - // This situation means -> no pages on the document - return 0; - } - - return pageIndex; -} - QString UBPersistenceManager::generateUniqueDocumentPath(const QString& baseFolder) { QDateTime now = QDateTime::currentDateTime(); @@ -1027,39 +946,23 @@ void UBPersistenceManager::generatePathIfNeeded(std::shared_ptr bool UBPersistenceManager::addDirectoryContentToDocument(const QString& documentRootFolder, std::shared_ptr pDocument) { - QStringList sourceScenes = pageFiles(documentRootFolder); - if (sourceScenes.empty()) - return false; - - int targetPageCount = pDocument->pageCount(); + auto proxy = std::make_shared(documentRootFolder); + auto sourceDocument = UBDocument::getDocument(proxy); - for(int sourceIndex = 0 ; sourceIndex < sourceScenes.size(); sourceIndex++) + if (sourceDocument->pageCount() == 0) { - int targetIndex = targetPageCount + sourceIndex; - - QFile svg(documentRootFolder + "/" + sourceScenes[sourceIndex]); - if (!svg.copy(pDocument->persistencePath() + sceneFilenameForId(targetIndex))) - return false; - - UBSvgSubsetAdaptor::setSceneUuid(pDocument, targetIndex, QUuid::createUuid()); - - QFile thumb(documentRootFolder + thumbnailFilenameForId(sourceIndex)); - // We can ignore error in this case, thumbnail will be genarated - thumb.copy(pDocument->persistencePath() + thumbnailFilenameForId(targetIndex)); + return false; } - foreach(QString dir, mDocumentSubDirectories) - { - qDebug() << "copying " << documentRootFolder << "/" << dir << " to " << pDocument->persistencePath() << "/" + dir; + auto targetDocument = UBDocument::getDocument(pDocument); + int targetPageCount = targetDocument->pageCount(); - QDir srcDir(documentRootFolder + "/" + dir); - if (srcDir.exists()) - if (!UBFileSystemUtils::copyDir(documentRootFolder + "/" + dir, pDocument->persistencePath() + "/" + dir)) - return false; + for (int sourceIndex = 0; sourceIndex < sourceDocument->pageCount(); sourceIndex++) + { + int targetIndex = targetPageCount + sourceIndex; + sourceDocument->copyPage(sourceIndex, targetDocument, targetIndex); } - pDocument->setPageCount(pDocument->pageCount()); - //issue NC - NNE - 20131213 : At this point, all is well done. return true; } diff --git a/src/core/UBPersistenceManager.h b/src/core/UBPersistenceManager.h index b943618e9..b9099daf9 100644 --- a/src/core/UBPersistenceManager.h +++ b/src/core/UBPersistenceManager.h @@ -109,7 +109,6 @@ class UBPersistenceManager : public QObject virtual std::shared_ptr loadDocumentScene(std::shared_ptr pDocumentProxy, int pageId); void prepareSceneLoading(std::shared_ptr proxy, int pageId); std::shared_ptr getDocumentScene(std::shared_ptr pDocumentProxy, int pageId); - void reassignDocProxy(std::shared_ptr newDocument, std::shared_ptr oldDocument); // QList > documentProxies; UBDocumentTreeNode *mDocumentTreeStructure; @@ -158,14 +157,11 @@ class UBPersistenceManager : public QObject void documentMetadataChanged(std::shared_ptr pDocumentProxy); // The following signals are emitted in UBDocument - void documentSceneDuplicated(std::shared_ptr pDocumentProxy, int pIndex); - void documentSceneMoved(std::shared_ptr pDocumentProxy, int fromIndex, int toIndex); - void documentSceneDeleted(std::shared_ptr pDocumentProxy, int pIndex); + void documentSceneDuplicated(UBDocument* document, int pIndex); + void documentSceneMoved(UBDocument* document, int fromIndex, int toIndex); + void documentSceneDeleted(UBDocument* document, int pIndex); private: - static int sceneCount(const std::shared_ptr pDocumentProxy); - void renamePage(std::shared_ptr pDocumentProxy, - const int sourceIndex, const int targetIndex); QUuid copyPage(std::shared_ptr source, const int sourceIndex, std::shared_ptr target, const int targetIndex); void generatePathIfNeeded(std::shared_ptr pDocumentProxy); diff --git a/src/core/UBSceneCache.cpp b/src/core/UBSceneCache.cpp index 4616564ef..ac75a9e6c 100644 --- a/src/core/UBSceneCache.cpp +++ b/src/core/UBSceneCache.cpp @@ -157,9 +157,21 @@ void UBSceneCache::removeScene(std::shared_ptr proxy, int pageI void UBSceneCache::removeAllScenes(std::shared_ptr proxy) { - for(int i = 0 ; i < proxy->pageCount(); i++) + // get list of all page ids for proxy, avoid modifying the map here + auto lowerBound = mSceneCache.lowerBound({proxy, 0}); + auto upperBound = mSceneCache.upperBound({proxy, INT_MAX}); + + QList pageIds; + + for (auto iter = lowerBound; iter != upperBound; ++iter) + { + pageIds << iter.key().mPageId; + } + + // delete scenes by id + for(auto pageId : pageIds) { - removeScene(proxy, i); + removeScene(proxy, pageId); } } @@ -207,34 +219,6 @@ void UBSceneCache::moveScene(std::shared_ptr proxy, int sourceI } -void UBSceneCache::reassignDocProxy(std::shared_ptr newDocument, std::shared_ptr oldDocument) -{ - if (!newDocument || !oldDocument) { - return; - } - if (newDocument->pageCount() != oldDocument->pageCount()) { - return; - } - if (!QFileInfo(oldDocument->persistencePath()).exists()) { - return; - } - for (int i = 0; i < oldDocument->pageCount(); i++) { - - UBSceneCacheID sourceKey(oldDocument, i); - auto entry = mSceneCache.value(sourceKey); - - if (entry->isSceneAvailable()) - { - entry->scene()->setDocument(newDocument); - } - - mCachedKeyFIFO.removeAll(sourceKey); - int count = mSceneCache.remove(sourceKey); - - insertEntry({newDocument, i}, entry); - } -} - void UBSceneCache::shiftUpScenes(std::shared_ptr proxy, int startIncIndex, int endIncIndex) { diff --git a/src/core/UBSceneCache.h b/src/core/UBSceneCache.h index 5c4b8ed22..aa7060106 100644 --- a/src/core/UBSceneCache.h +++ b/src/core/UBSceneCache.h @@ -60,15 +60,17 @@ class UBSceneCacheID int mPageId; }; -inline bool operator==(const UBSceneCacheID &id1, const UBSceneCacheID &id2) +inline bool operator<(const UBSceneCacheID &id1, const UBSceneCacheID &id2) { - return id1.mDocumentProxy == id2.mDocumentProxy - && id1.mPageId == id2.mPageId; + return id1.mDocumentProxy < id2.mDocumentProxy || + (id1.mDocumentProxy == id2.mDocumentProxy + && id1.mPageId < id2.mPageId); } -inline uint qHash(const UBSceneCacheID &id) +inline bool operator==(const UBSceneCacheID &id1, const UBSceneCacheID &id2) { - return qHash(id.mPageId); + return id1.mDocumentProxy == id2.mDocumentProxy + && id1.mPageId == id2.mPageId; } @@ -94,8 +96,6 @@ class UBSceneCache void moveScene(std::shared_ptr proxy, int sourceIndex, int targetIndex); - void reassignDocProxy(std::shared_ptr newDocument, std::shared_ptr oldDocument); - void shiftUpScenes(std::shared_ptr proxy, int startIncIndex, int endIncIndex); @@ -116,18 +116,15 @@ class UBSceneCache QTimer* mTimer = nullptr; }; -// typedef QFuture> FutureScene; -// typedef std::variant, FutureScene> CacheEntry; - void internalMoveScene(std::shared_ptr proxy, int sourceIndex, int targetIndex); void insertEntry(UBSceneCacheID key, std::shared_ptr entry); - QHash> mSceneCache; + QMap> mSceneCache; QQueue mCachedKeyFIFO; - QHash mViewStates; + QMap mViewStates; }; diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index dca1622b5..e23b8ff27 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -102,13 +102,20 @@ void UBDocument::deletePages(QList indexes) } // delete the scenes + if (pageIds.count() == pageCount()) + { + // deleting all pages is blocked in the UI. Just log if it happens anyway + qWarning() << "UBDocument::deletePages: declined attempt to remove all pages of a document"; + return; + } + UBPersistenceManager::persistenceManager()->deleteDocumentScenes(mProxy, pageIds); for (int i = indexes.size() - 1; i >= 0; --i) { mThumbnailScene->deleteThumbnail(indexes.at(i), false); mToc->remove(indexes.at(i)); - emit UBPersistenceManager::persistenceManager()->documentSceneDeleted(mProxy, indexes.at(i)); + emit UBPersistenceManager::persistenceManager()->documentSceneDeleted(this, indexes.at(i)); } mThumbnailScene->renumberThumbnails(indexes.first()); @@ -119,7 +126,7 @@ void UBDocument::deletePages(QList indexes) void UBDocument::duplicatePage(int index) { copyPage(index, this, index + 1); - emit UBPersistenceManager::persistenceManager()->documentSceneDuplicated(mProxy, index + 1); + emit UBPersistenceManager::persistenceManager()->documentSceneDuplicated(this, index + 1); } void UBDocument::movePage(int fromIndex, int toIndex) @@ -127,7 +134,7 @@ void UBDocument::movePage(int fromIndex, int toIndex) mThumbnailScene->moveThumbnail(fromIndex, toIndex); mToc->move(fromIndex, toIndex); mToc->save(); - emit UBPersistenceManager::persistenceManager()->documentSceneMoved(mProxy, fromIndex, toIndex); + emit UBPersistenceManager::persistenceManager()->documentSceneMoved(this, fromIndex, toIndex); } void UBDocument::copyPage(int fromIndex, std::shared_ptr to, int toIndex) @@ -305,6 +312,12 @@ void UBDocument::scan() // Scan through the pages starting from the smallest number and counting up. QStringList pages = UBPersistenceManager::persistenceManager()->pageFiles(mProxy->persistencePath()); + if (pages.isEmpty()) + { + qWarning() << "No pages found - " << mProxy->persistencePath(); + mProxy->setMetaData(UBSettings::documentName, UBPersistenceManager::tr("Broken - %1").arg(mProxy->documentFolderName())); + } + // Load the scenes and check the media assets. int pageProcessed = -1; diff --git a/src/document/UBDocumentContainer.cpp b/src/document/UBDocumentContainer.cpp index b9a486100..b7d036d62 100644 --- a/src/document/UBDocumentContainer.cpp +++ b/src/document/UBDocumentContainer.cpp @@ -51,11 +51,22 @@ void UBDocumentContainer::setDocument(std::shared_ptr document, { if (mCurrentDocument != document || forceReload) { - mCurrentDocument = document; - emit documentSet(mCurrentDocument); + pureSetDocument(document); + emit documentSet(document); } } +void UBDocumentContainer::pureSetDocument(std::shared_ptr document) +{ + mCurrentDocument = document; + mActiveDocument = UBDocument::getDocument(mCurrentDocument); +} + +std::shared_ptr UBDocumentContainer::activeDocument() +{ + return mActiveDocument; +} + void UBDocumentContainer::duplicatePage(int index) { auto document = UBDocument::getDocument(selectedDocument()); @@ -80,14 +91,12 @@ void UBDocumentContainer::moveSceneToIndex(std::shared_ptr prox void UBDocumentContainer::deletePages(QList& pageIndexes) { - auto document = UBDocument::getDocument(mCurrentDocument); - document->deletePages(pageIndexes); + mActiveDocument->deletePages(pageIndexes); } void UBDocumentContainer::addPage(int index) { - auto document = UBDocument::getDocument(mCurrentDocument); - document->createPage(index); + mActiveDocument->createPage(index); } diff --git a/src/document/UBDocumentContainer.h b/src/document/UBDocumentContainer.h index 157fcaf76..9d9a867cc 100644 --- a/src/document/UBDocumentContainer.h +++ b/src/document/UBDocumentContainer.h @@ -33,6 +33,9 @@ #include #include "UBDocumentProxy.h" +// forward +class UBDocument; + class UBDocumentContainer : public QObject { Q_OBJECT @@ -42,10 +45,10 @@ class UBDocumentContainer : public QObject virtual ~UBDocumentContainer(); void setDocument(std::shared_ptr document, bool forceReload = false); - void pureSetDocument(std::shared_ptr document) {mCurrentDocument = document;} + void pureSetDocument(std::shared_ptr document); std::shared_ptr selectedDocument(){return mCurrentDocument;} - int pageCount() const{return mCurrentDocument->pageCount();} + std::shared_ptr activeDocument(); static int pageFromSceneIndex(int sceneIndex); static int sceneIndexFromPage(int sceneIndex); @@ -59,6 +62,7 @@ class UBDocumentContainer : public QObject private: std::shared_ptr mCurrentDocument; + std::shared_ptr mActiveDocument; signals: void documentSet(std::shared_ptr document); diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index d501c848b..969954ca3 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -737,11 +737,12 @@ bool UBDocumentTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction act foreach (UBMimeDataItem sourceItem, ubMime->items()) { std::shared_ptr fromProxy = sourceItem.documentProxy(); - int fromIndex = sourceItem.sceneIndex(); - int toIndex = targetDocProxy->pageCount(); - auto fromDocument = UBDocument::getDocument(fromProxy); auto targetDocument = UBDocument::getDocument(targetDocProxy); + + int fromIndex = sourceItem.sceneIndex(); + int toIndex = targetDocument->pageCount(); + fromDocument->copyPage(fromIndex, targetDocument, toIndex); } @@ -1644,7 +1645,7 @@ void UBDocumentTreeView::dropEvent(QDropEvent *event) { std::shared_ptr fromProxy = sourceItem.documentProxy(); int fromIndex = sourceItem.sceneIndex(); - int toIndex = targetDocProxy->pageCount(); + int toIndex = targetDocument->pageCount(); UBApplication::showMessage(tr("Copying page %1/%2").arg(++count).arg(total), true); @@ -3365,7 +3366,7 @@ void UBDocumentController::addToDocument() mBoardController->addScene(pageInfoList.at(i).first, pageInfoList.at(i).second, false); } - int newActiveSceneIndex = selectedItems.count() == mBoardController->selectedDocument()->pageCount() ? 0 : oldActiveSceneIndex + 1; + int newActiveSceneIndex = selectedItems.count() == mBoardController->activeDocument()->pageCount() ? 0 : oldActiveSceneIndex + 1; mDocumentUI->thumbnailWidget->selectItemAt(newActiveSceneIndex, false); selectDocument(mBoardController->selectedDocument()); QDateTime now = QDateTime::currentDateTime(); @@ -3592,10 +3593,6 @@ void UBDocumentController::updateActions() QModelIndex selectedIndex = firstSelectedTreeIndex(); std::shared_ptr selectedProxy = docModel->proxyData(selectedIndex); - int pageCount = -1; - if (selectedProxy) { - pageCount = selectedProxy->pageCount(); - } bool pageSelected = false; bool groupSelected = false; @@ -3638,7 +3635,7 @@ void UBDocumentController::updateActions() } else if (pageSelected) { QList selection = mDocumentUI->thumbnailWidget->selectedItems(); - if(pageCount == 1) { + if(mDocumentUI->thumbnailWidget->document()->pageCount() == 1) { mMainWindow->actionDuplicate->setEnabled(!trashSelected && pageCanBeDuplicated(UBDocumentContainer::pageFromSceneIndex(0))); } else { @@ -3814,7 +3811,7 @@ bool UBDocumentController::pageCanBeMovedUp(int page) bool UBDocumentController::pageCanBeMovedDown(int page) { - return page < selectedDocument()->pageCount() - 1; + return page < activeDocument()->pageCount() - 1; } bool UBDocumentController::pageCanBeDuplicated(int page) @@ -3878,7 +3875,7 @@ bool UBDocumentController::everySceneSelected() const UBThumbnail* p = dynamic_cast(selection.at(0)); if (p) { - return (selection.count() == mDocumentUI->thumbnailWidget->document()->proxy()->pageCount()); + return (selection.count() == mDocumentUI->thumbnailWidget->document()->pageCount()); } } return false; @@ -3892,7 +3889,7 @@ bool UBDocumentController::firstAndOnlySceneSelected() const UBThumbnail* p = dynamic_cast(selection.at(i)); if (p) { - int pageCount = mDocumentUI->thumbnailWidget->document()->proxy()->pageCount(); + int pageCount = mDocumentUI->thumbnailWidget->document()->pageCount(); if (pageCount > 1) //not the only scene { return false; diff --git a/src/document/UBDocumentProxy.cpp b/src/document/UBDocumentProxy.cpp index 9c4b64d7e..958ce45f6 100644 --- a/src/document/UBDocumentProxy.cpp +++ b/src/document/UBDocumentProxy.cpp @@ -40,8 +40,7 @@ #include "adaptors/UBMetadataDcSubsetAdaptor.h" UBDocumentProxy::UBDocumentProxy() - : mPageCount(0) - , mPageDpi(0) + : mPageDpi(0) , mPersistencePath("") , mDocumentDateLittleEndian("") , mDocumentUpdatedAtLittleEndian("") @@ -54,8 +53,7 @@ UBDocumentProxy::UBDocumentProxy() UBDocumentProxy::UBDocumentProxy(const QString& pPersistancePath) - : mPageCount(0) - , mPageDpi(0) + : mPageDpi(0) , mNeedsCleanup(true) , mLastVisitedIndex(0) , mIsInFavoriteList(false) @@ -95,7 +93,6 @@ std::shared_ptr UBDocumentProxy::deepCopy() const copy->mPersistencePath = QString(mPersistencePath); copy->mMetaDatas = QMap(mMetaDatas); - copy->mPageCount = mPageCount; copy->mLastVisitedIndex = mLastVisitedIndex; copy->mIsInFavoriteList = mIsInFavoriteList; @@ -122,17 +119,6 @@ void UBDocumentProxy::setIsInFavoristeList(bool isInFavoriteList) mIsInFavoriteList = isInFavoriteList; } -int UBDocumentProxy::pageCount() -{ - return mPageCount; -} - - -void UBDocumentProxy::setPageCount(int pPageCount) -{ - mPageCount = pPageCount; -} - int UBDocumentProxy::pageDpi() { return mPageDpi; @@ -160,36 +146,6 @@ bool UBDocumentProxy::testAndResetCleanupNeeded() return tmp; } -int UBDocumentProxy::incPageCount() -{ - if (mPageCount <= 0) - { - mPageCount = 1; - } - else - { - mPageCount++; - } - - return mPageCount; - -} - - -int UBDocumentProxy::decPageCount() -{ - mPageCount --; - - if (mPageCount < 0) - { - mPageCount = 0; - } - - mNeedsCleanup = true; - - return mPageCount; -} - QString UBDocumentProxy::persistencePath() const { return mPersistencePath; diff --git a/src/document/UBDocumentProxy.h b/src/document/UBDocumentProxy.h index dc12644ca..5d8603937 100644 --- a/src/document/UBDocumentProxy.h +++ b/src/document/UBDocumentProxy.h @@ -96,8 +96,6 @@ class UBDocumentProxy QUuid uuid() const; void setUuid(const QUuid& uuid); - int pageCount(); - int pageDpi(); void setPageDpi(int dpi); @@ -112,11 +110,6 @@ class UBDocumentProxy bool isInFavoriteList() const; void setIsInFavoristeList(bool isInFavoristeList); - protected: - void setPageCount(int pPageCount); - int incPageCount(); - int decPageCount(); - private: void init(); @@ -128,8 +121,6 @@ class UBDocumentProxy QMap mMetaDatas; - int mPageCount; - int mPageDpi; QMap mWidgetCompatibility; From 56bc7d20bfb085498de22d4de4474fe82b28805c Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 27 Apr 2025 11:08:55 +0200 Subject: [PATCH 014/133] feat: improve handling of media asset UUIDs - keep separate asset UUID for SVG items - rename mediaAssetUuid to createMediaAssetUuid - make setMediaAsset pure virtual and implement it in all derived classes - add UBMediaAssetItem::uuidFromPath to derive UUID from path - add UBMediaAssetItem::mediaAssetUuid to get asset UUID - allow to switch renderer for UBGraphicsPDFItem when PDF file is renamed Signed-off-by: letsfindaway --- src/adaptors/UBSvgSubsetAdaptor.cpp | 1 + src/board/UBBoardController.cpp | 6 +++--- src/core/UBDocumentManager.cpp | 2 +- src/domain/UBGraphicsPDFItem.cpp | 11 +++++++++++ src/domain/UBGraphicsPDFItem.h | 1 + src/domain/UBGraphicsScene.cpp | 2 +- src/domain/UBGraphicsSvgItem.cpp | 9 +++++++-- src/domain/UBGraphicsSvgItem.h | 1 + src/domain/UBMediaAssetItem.cpp | 24 +++++++++++++++++++++++- src/domain/UBMediaAssetItem.h | 9 +++++++-- src/pdf/GraphicsPDFItem.cpp | 11 +++++++++++ src/pdf/GraphicsPDFItem.h | 4 ++++ 12 files changed, 71 insertions(+), 10 deletions(-) diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index 603f79912..74c63a838 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -2185,6 +2185,7 @@ UBGraphicsSvgItem* UBSvgSubsetAdaptor::UBSvgSubsetReader::svgItemFromSvg() QString href = imageHref.toString(); svgItem = new UBGraphicsSvgItem(mDocumentPath + "/" + UBFileSystemUtils::normalizeFilePath(href)); + svgItem->setMediaAsset(mDocumentPath, href); } else { diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index 21c1bd660..e99aa1220 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -1385,7 +1385,7 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl if (pData.length() > 0) { - QUuid uuid = UBMediaAssetItem::mediaAssetUuid(pData); + QUuid uuid = UBMediaAssetItem::createMediaAssetUuid(pData); QString destFile; bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(selectedDocument(), sourceUrl.toString(), @@ -1429,7 +1429,7 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl if (pData.length() > 0) { - QUuid uuid = UBMediaAssetItem::mediaAssetUuid(pData); + QUuid uuid = UBMediaAssetItem::createMediaAssetUuid(pData); QString destFile; bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(selectedDocument(), sourceUrl.toString(), @@ -2400,7 +2400,7 @@ UBGraphicsWidgetItem *UBBoardController::addW3cWidget(const QUrl &pUrl, const QP } } - QUuid assetUuid = UBMediaAssetItem::mediaAssetUuid(data); + QUuid assetUuid = UBMediaAssetItem::createMediaAssetUuid(data); QString destPath; if (!UBPersistenceManager::persistenceManager()->addGraphicsWidgetToDocument(selectedDocument(), pUrl.toLocalFile(), assetUuid, destPath)) diff --git a/src/core/UBDocumentManager.cpp b/src/core/UBDocumentManager.cpp index fcfb20f76..ea48963bb 100644 --- a/src/core/UBDocumentManager.cpp +++ b/src/core/UBDocumentManager.cpp @@ -281,7 +281,7 @@ int UBDocumentManager::addFilesToDocument(std::shared_ptr docum { data = file.readAll(); file.close(); - uuid = UBMediaAssetItem::mediaAssetUuid(data); + uuid = UBMediaAssetItem::createMediaAssetUuid(data); } QString filepath = file.fileName(); diff --git a/src/domain/UBGraphicsPDFItem.cpp b/src/domain/UBGraphicsPDFItem.cpp index b996ef44c..943092048 100644 --- a/src/domain/UBGraphicsPDFItem.cpp +++ b/src/domain/UBGraphicsPDFItem.cpp @@ -57,6 +57,17 @@ QList UBGraphicsPDFItem::mediaAssets() const return {UBPersistenceManager::objectDirectory + "/" + fileUuid().toString() + ".pdf"}; } +void UBGraphicsPDFItem::setMediaAsset(const QString& documentPath, const QString& mediaAsset) +{ + if (mediaAsset.at(0) != mediaAsset) + { + // exchange renderer for new asset + const auto uuid = uuidFromPath(mediaAsset); + auto newRenderer = PDFRenderer::rendererForUuid(uuid, documentPath + "/" + mediaAsset); + switchRenderer(newRenderer); + } +} + QVariant UBGraphicsPDFItem::itemChange(GraphicsItemChange change, const QVariant &value) { QVariant newValue = Delegate()->itemChange(change, value); diff --git a/src/domain/UBGraphicsPDFItem.h b/src/domain/UBGraphicsPDFItem.h index c9a9ae2db..6e6587ae5 100644 --- a/src/domain/UBGraphicsPDFItem.h +++ b/src/domain/UBGraphicsPDFItem.h @@ -54,6 +54,7 @@ class UBGraphicsPDFItem: public GraphicsPDFItem, public UBMediaAssetItem, public } virtual QList mediaAssets() const override; + virtual void setMediaAsset(const QString& documentPath, const QString& mediaAsset) override; virtual UBItem* deepCopy() const override; diff --git a/src/domain/UBGraphicsScene.cpp b/src/domain/UBGraphicsScene.cpp index fd76058d3..559bc2d8b 100644 --- a/src/domain/UBGraphicsScene.cpp +++ b/src/domain/UBGraphicsScene.cpp @@ -1637,7 +1637,7 @@ UBGraphicsPixmapItem* UBGraphicsScene::addImage(QByteArray pData, QGraphicsItem* format = "png." + format; } - QString fileName = UBPersistenceManager::imageDirectory + "/" + UBMediaAssetItem::mediaAssetUuid(pData).toString() + "." + format; + QString fileName = UBPersistenceManager::imageDirectory + "/" + UBMediaAssetItem::createMediaAssetUuid(pData).toString() + "." + format; pixmapItem->setMediaAsset(documentPath, fileName); QString path = documentPath + "/" + fileName; diff --git a/src/domain/UBGraphicsSvgItem.cpp b/src/domain/UBGraphicsSvgItem.cpp index cbfa26cba..6cb89af5c 100644 --- a/src/domain/UBGraphicsSvgItem.cpp +++ b/src/domain/UBGraphicsSvgItem.cpp @@ -55,7 +55,7 @@ UBGraphicsSvgItem::UBGraphicsSvgItem(const QString& pFilePath, QGraphicsItem* pa { mFileData = f.readAll(); f.close(); - mMediaAssetUuid = mediaAssetUuid(mFileData); + mMediaAssetUuid = createMediaAssetUuid(mFileData); } } @@ -68,7 +68,7 @@ UBGraphicsSvgItem::UBGraphicsSvgItem(const QByteArray& pFileData, QGraphicsItem* setSharedRenderer(renderer); mFileData = pFileData; - mMediaAssetUuid = mediaAssetUuid(mFileData); + mMediaAssetUuid = createMediaAssetUuid(mFileData); } @@ -103,6 +103,11 @@ QList UBGraphicsSvgItem::mediaAssets() const return {UBPersistenceManager::imageDirectory + "/" + mMediaAssetUuid.toString() + ".svg"}; } +void UBGraphicsSvgItem::setMediaAsset(const QString& documentPath, const QString& mediaAsset) +{ + mMediaAssetUuid = uuidFromPath(mediaAsset); +} + QByteArray UBGraphicsSvgItem::fileData() const { diff --git a/src/domain/UBGraphicsSvgItem.h b/src/domain/UBGraphicsSvgItem.h index 0e0413aed..643e64a2b 100644 --- a/src/domain/UBGraphicsSvgItem.h +++ b/src/domain/UBGraphicsSvgItem.h @@ -51,6 +51,7 @@ class UBGraphicsSvgItem: public QGraphicsSvgItem, public UBMediaAssetItem, publi virtual ~UBGraphicsSvgItem(); virtual QList mediaAssets() const override; + virtual void setMediaAsset(const QString& documentPath, const QString& mediaAsset) override; QByteArray fileData() const; diff --git a/src/domain/UBMediaAssetItem.cpp b/src/domain/UBMediaAssetItem.cpp index b582c415f..0ace9f01c 100644 --- a/src/domain/UBMediaAssetItem.cpp +++ b/src/domain/UBMediaAssetItem.cpp @@ -21,9 +21,31 @@ #include "UBMediaAssetItem.h" -QUuid UBMediaAssetItem::mediaAssetUuid(const QByteArray& data) +#include + +QUuid UBMediaAssetItem::mediaAssetUuid() const +{ + return uuidFromPath(mediaAssets().value(0, "")); +} + +QUuid UBMediaAssetItem::createMediaAssetUuid(const QByteArray& data) { static QUuid namespaceUuid{QUuid::createUuidV5(QUuid(), QString("OpenBoard"))}; return QUuid::createUuidV5(namespaceUuid, data); } + +QUuid UBMediaAssetItem::uuidFromPath(const QString& path) const +{ + static QRegularExpression uuidPattern("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"); + + // scan asset file name for UUID + QRegularExpressionMatch match = uuidPattern.match(path); + + if (match.hasMatch()) + { + return QUuid{match.captured()}; + } + + return {}; +} diff --git a/src/domain/UBMediaAssetItem.h b/src/domain/UBMediaAssetItem.h index 2d3def474..f4928f563 100644 --- a/src/domain/UBMediaAssetItem.h +++ b/src/domain/UBMediaAssetItem.h @@ -36,7 +36,12 @@ class UBMediaAssetItem : public UBItem virtual ~UBMediaAssetItem() = default; virtual QList mediaAssets() const = 0; - virtual void setMediaAsset(const QString& documentPath, const QString& mediaAsset) {} + virtual void setMediaAsset(const QString& documentPath, const QString& mediaAsset) = 0; - static QUuid mediaAssetUuid(const QByteArray& data); + QUuid mediaAssetUuid() const; + + static QUuid createMediaAssetUuid(const QByteArray& data); + +protected: + QUuid uuidFromPath(const QString& path) const; }; diff --git a/src/pdf/GraphicsPDFItem.cpp b/src/pdf/GraphicsPDFItem.cpp index af52195f1..cb4b0a198 100644 --- a/src/pdf/GraphicsPDFItem.cpp +++ b/src/pdf/GraphicsPDFItem.cpp @@ -80,6 +80,17 @@ void GraphicsPDFItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *o } +void GraphicsPDFItem::switchRenderer(PDFRenderer* newRenderer) +{ + disconnect(mRenderer, SIGNAL(signalUpdateParent()), this, SLOT(OnRequireUpdate())); + mRenderer->detach(); + + mRenderer = newRenderer; + + mRenderer->attach(); + connect(mRenderer, SIGNAL(signalUpdateParent()), this, SLOT(OnRequireUpdate())); +} + void GraphicsPDFItem::OnRequireUpdate() { updateChild(); diff --git a/src/pdf/GraphicsPDFItem.h b/src/pdf/GraphicsPDFItem.h index 0eb9ed5cd..5ae1d3b02 100644 --- a/src/pdf/GraphicsPDFItem.h +++ b/src/pdf/GraphicsPDFItem.h @@ -54,6 +54,10 @@ class GraphicsPDFItem : public QObject, public QGraphicsItem void setCacheAllowed(bool const value) { mIsCacheAllowed = value; } QSizeF pageSize() const { return mRenderer->pointSizeF(mPageNumber); } virtual void updateChild() = 0; + + protected: + void switchRenderer(PDFRenderer* newRenderer); + protected: PDFRenderer *mRenderer; int mPageNumber; From 552d16348d3a76e639447282c457ed69ac77fd56 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Thu, 15 May 2025 15:20:24 +0200 Subject: [PATCH 015/133] feat: fully convert document while scanning - UBPersistenceManager: add function to copy assets - UBPersistenceManager: add function to cleanup unreferenced assets - UBPersistenceManager: remove unused fileDirectory - UBSceneCache: remove unused functions moving scenes - UBDocument::scan - display progress messages - rename media assets when they do not have a UuidV5 - delete unreferenced media assets when scan is complete - UBDocument: also delete unref. media assets when deleting UBDocument - UBMediaAssetItem: add function to create UuidV5 from file or dir Signed-off-by: letsfindaway --- src/board/UBBoardController.cpp | 15 +--- src/core/UBPersistenceManager.cpp | 36 +++++++++- src/core/UBPersistenceManager.h | 4 +- src/core/UBSceneCache.cpp | 80 ---------------------- src/core/UBSceneCache.h | 6 -- src/document/UBDocument.cpp | 109 +++++++++++++++++++++++++----- src/document/UBDocument.h | 5 +- src/domain/UBMediaAssetItem.cpp | 42 ++++++++++++ src/domain/UBMediaAssetItem.h | 1 + 9 files changed, 177 insertions(+), 121 deletions(-) diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index e99aa1220..a8fe9e609 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -2387,20 +2387,7 @@ UBGraphicsWidgetItem *UBBoardController::addW3cWidget(const QUrl &pUrl, const QP return nullptr; } - const auto widgetFiles = widgetDir.entryInfoList({"*.xml", "*.html"}, QDir::Files, QDir::Name); - QByteArray data; - - for (const auto fileInfo : widgetFiles) - { - QFile file(fileInfo.absoluteFilePath()); - - if (file.open(QFile::ReadOnly)) - { - data.append(file.readAll()); - } - } - - QUuid assetUuid = UBMediaAssetItem::createMediaAssetUuid(data); + QUuid assetUuid = UBMediaAssetItem::createMediaAssetUuid(pUrl.toLocalFile()); QString destPath; if (!UBPersistenceManager::persistenceManager()->addGraphicsWidgetToDocument(selectedDocument(), pUrl.toLocalFile(), assetUuid, destPath)) diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index eb2512370..840eb178c 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -60,7 +60,6 @@ const QString UBPersistenceManager::objectDirectory = "objects"; // added to UBP const QString UBPersistenceManager::widgetDirectory = "widgets"; // added to UBPersistenceManager::mAllDirectories const QString UBPersistenceManager::videoDirectory = "videos"; // added to UBPersistenceManager::mAllDirectories const QString UBPersistenceManager::audioDirectory = "audios"; // added to -const QString UBPersistenceManager::fileDirectory = "files"; // Issue 1683 (Evolution) - AOU - 20131206 const QString UBPersistenceManager::myDocumentsName = "MyDocuments"; const QString UBPersistenceManager::modelsName = "Models"; @@ -87,7 +86,6 @@ UBPersistenceManager::UBPersistenceManager(QObject *pParent) mDocumentSubDirectories << widgetDirectory; mDocumentSubDirectories << videoDirectory; mDocumentSubDirectories << audioDirectory; - mDocumentSubDirectories << fileDirectory; // Issue 1683 (Evolution) - AOU - 20131206 mDocumentRepositoryPath = UBSettings::userDocumentDirectory(); mFoldersXmlStorageName = mDocumentRepositoryPath + "/" + fFolders; @@ -848,6 +846,40 @@ std::shared_ptr UBPersistenceManager::getDocumentScene(std::sha return mSceneCache.value(pDocumentProxy, pageId); } +bool UBPersistenceManager::copyAsset(std::shared_ptr proxy, const QString& fromRelativePath, const QString& toRelativePath) +{ + const auto source = proxy->persistencePath() + "/" + fromRelativePath; + const auto target = proxy->persistencePath() + "/" + toRelativePath; + return UBFileSystemUtils::copy(source, target); +} + +void UBPersistenceManager::cleanupMediaAssets(std::shared_ptr proxy, QSet referencedMediaAssets) +{ + const auto documentPath = proxy->persistencePath() + "/"; + + for (const auto subfolder : mDocumentSubDirectories) + { + const auto assets = QDir(documentPath + subfolder).entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); + + for (const auto asset : assets) + { + const auto mediaAsset = subfolder + "/" + asset.fileName(); + + if (!referencedMediaAssets.contains(mediaAsset)) + { + if (asset.isDir()) + { + UBFileSystemUtils::deleteDir(asset.absoluteFilePath()); + } + else + { + UBFileSystemUtils::deleteFile(asset.absoluteFilePath()); + } + } + } + } +} + void UBPersistenceManager::persistDocumentScene(std::shared_ptr pDocumentProxy, std::shared_ptr pScene, int pageId, bool isAnAutomaticBackup, bool forceImmediateSaving) { checkIfDocumentRepositoryExists(); diff --git a/src/core/UBPersistenceManager.h b/src/core/UBPersistenceManager.h index b9099daf9..ce4d6f646 100644 --- a/src/core/UBPersistenceManager.h +++ b/src/core/UBPersistenceManager.h @@ -59,7 +59,6 @@ class UBPersistenceManager : public QObject static const QString videoDirectory; static const QString audioDirectory; static const QString widgetDirectory; - static const QString fileDirectory; // Issue 1683 (Evolution) - AOU - 20131206 static const QString myDocumentsName; static const QString modelsName; @@ -110,6 +109,9 @@ class UBPersistenceManager : public QObject void prepareSceneLoading(std::shared_ptr proxy, int pageId); std::shared_ptr getDocumentScene(std::shared_ptr pDocumentProxy, int pageId); + bool copyAsset(std::shared_ptr proxy, const QString& fromRelativePath, const QString& toRelativePath); + void cleanupMediaAssets(std::shared_ptr proxy, QSet referencedMediaAssets); + // QList > documentProxies; UBDocumentTreeNode *mDocumentTreeStructure; UBDocumentTreeModel *mDocumentTreeStructureModel; diff --git a/src/core/UBSceneCache.cpp b/src/core/UBSceneCache.cpp index ac75a9e6c..dde94d18b 100644 --- a/src/core/UBSceneCache.cpp +++ b/src/core/UBSceneCache.cpp @@ -176,86 +176,6 @@ void UBSceneCache::removeAllScenes(std::shared_ptr proxy) } -void UBSceneCache::moveScene(std::shared_ptr proxy, int sourceIndex, int targetIndex) -{ - UBSceneCacheID keySource(proxy, sourceIndex); - - std::shared_ptr entry; - bool hasEntry = mSceneCache.contains(keySource); - - if (hasEntry) - { - entry = mSceneCache.value(keySource); - mCachedKeyFIFO.removeAll(keySource); - } - - if (sourceIndex < targetIndex) - { - for (int i = sourceIndex + 1; i <= targetIndex; i++) - { - internalMoveScene(proxy, i, i - 1); - } - } - else - { - for (int i = sourceIndex - 1; i >= targetIndex; i--) - { - internalMoveScene(proxy, i, i + 1); - } - } - - UBSceneCacheID keyTarget(proxy, targetIndex); - - if (hasEntry) - { - insertEntry(keyTarget, entry); - mCachedKeyFIFO.enqueue(keyTarget); - } - else if (mSceneCache.contains(keyTarget)) - { - entry = mSceneCache.take(keyTarget); - mCachedKeyFIFO.removeAll(keyTarget); - } - -} - - -void UBSceneCache::shiftUpScenes(std::shared_ptr proxy, int startIncIndex, int endIncIndex) -{ - for(int i = endIncIndex; i >= startIncIndex; i--) - { - UBApplication::showMessage(QObject::tr("Moving cached scenes (%1/%2)").arg(i).arg(endIncIndex)); - internalMoveScene(proxy, i, i + 1); - } -} - - -void UBSceneCache::internalMoveScene(std::shared_ptr proxy, int sourceIndex, int targetIndex) -{ - UBSceneCacheID sourceKey(proxy, sourceIndex); - - if (mSceneCache.contains(sourceKey)) - { - auto scene = mSceneCache.take(sourceKey); - mCachedKeyFIFO.removeAll(sourceKey); - - UBSceneCacheID targetKey(proxy, targetIndex); - mSceneCache.insert(targetKey, scene); - mCachedKeyFIFO.enqueue(targetKey); - - } - else - { - UBSceneCacheID targetKey(proxy, targetIndex); - if (mSceneCache.contains(targetKey)) - { - mSceneCache.take(targetKey); - - mCachedKeyFIFO.removeAll(targetKey); - } - } -} - void UBSceneCache::insertEntry(UBSceneCacheID key, std::shared_ptr entry) { mSceneCache.insert(key, entry); diff --git a/src/core/UBSceneCache.h b/src/core/UBSceneCache.h index aa7060106..9a409aa92 100644 --- a/src/core/UBSceneCache.h +++ b/src/core/UBSceneCache.h @@ -94,10 +94,6 @@ class UBSceneCache void removeAllScenes(std::shared_ptr proxy); - void moveScene(std::shared_ptr proxy, int sourceIndex, int targetIndex); - - void shiftUpScenes(std::shared_ptr proxy, int startIncIndex, int endIncIndex); - private: class SceneCacheEntry @@ -116,8 +112,6 @@ class UBSceneCache QTimer* mTimer = nullptr; }; - void internalMoveScene(std::shared_ptr proxy, int sourceIndex, int targetIndex); - void insertEntry(UBSceneCacheID key, std::shared_ptr entry); QMap> mSceneCache; diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index e23b8ff27..b19668089 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -22,11 +22,13 @@ #include "UBDocument.h" +#include "adaptors/UBMetadataDcSubsetAdaptor.h" #include "adaptors/UBThumbnailAdaptor.h" #include "core/UBApplication.h" #include "core/UBPersistenceManager.h" #include "document/UBDocumentController.h" #include "document/UBToc.h" +#include "domain/UBMediaAssetItem.h" #include "gui/UBMainWindow.h" #include "gui/UBThumbnailScene.h" @@ -35,15 +37,17 @@ QList> UBDocument::sDocuments; UBDocument::UBDocument(std::shared_ptr proxy) : mProxy(proxy) - , mThumbnailScene(new UBThumbnailScene(this)) { toc(); - mThumbnailScene->createThumbnails(); } UBDocument::~UBDocument() { - delete mThumbnailScene; + if (QFile::exists(mProxy->persistencePath())) + { + mToc->save(); + deleteUnreferencedAssets(); + } } std::shared_ptr UBDocument::proxy() const @@ -113,13 +117,13 @@ void UBDocument::deletePages(QList indexes) for (int i = indexes.size() - 1; i >= 0; --i) { - mThumbnailScene->deleteThumbnail(indexes.at(i), false); + thumbnailScene()->deleteThumbnail(indexes.at(i), false); mToc->remove(indexes.at(i)); emit UBPersistenceManager::persistenceManager()->documentSceneDeleted(this, indexes.at(i)); } - mThumbnailScene->renumberThumbnails(indexes.first()); - mThumbnailScene->arrangeThumbnails(indexes.first()); + thumbnailScene()->renumberThumbnails(indexes.first()); + thumbnailScene()->arrangeThumbnails(indexes.first()); mToc->save(); } @@ -131,7 +135,14 @@ void UBDocument::duplicatePage(int index) void UBDocument::movePage(int fromIndex, int toIndex) { - mThumbnailScene->moveThumbnail(fromIndex, toIndex); + auto scene = getScene(fromIndex); + + if (scene && scene->isModified()) + { + persistPage(scene, fromIndex); + } + + thumbnailScene()->moveThumbnail(fromIndex, toIndex); mToc->move(fromIndex, toIndex); mToc->save(); emit UBPersistenceManager::persistenceManager()->documentSceneMoved(this, fromIndex, toIndex); @@ -150,7 +161,7 @@ std::shared_ptr UBDocument::createPage(int index, bool useUndoR mToc->setUuid(index, scene->uuid()); mToc->save(); - mThumbnailScene->insertThumbnail(index, scene); + thumbnailScene()->insertThumbnail(index, scene); return scene; } @@ -171,7 +182,7 @@ void UBDocument::persistPage(std::shared_ptr scene, int index, mToc->save(); } - mThumbnailScene->reloadThumbnail(index); + thumbnailScene()->reloadThumbnail(index); } std::shared_ptr UBDocument::loadScene(int index, bool cacheNeighboringScenes) @@ -216,9 +227,15 @@ QList UBDocument::pageRelativeDependencies(int index) return {}; } -UBThumbnailScene* UBDocument::thumbnailScene() const +UBThumbnailScene* UBDocument::thumbnailScene() { - return mThumbnailScene; + if (!mThumbnailScene) + { + mThumbnailScene = std::unique_ptr(new UBThumbnailScene(this)); + mThumbnailScene->createThumbnails(); + } + + return mThumbnailScene.get(); } UBToc* UBDocument::toc() @@ -227,7 +244,8 @@ UBToc* UBDocument::toc() { mToc = new UBToc{mProxy->persistencePath()}; - if (!mToc->load() || QVersionNumber::fromString(mProxy->metaData(UBSettings::documentVersion).toString()) < QVersionNumber(4, 9, 0)) + if (!mToc->load() || + QVersionNumber::fromString(mProxy->metaData(UBSettings::documentVersion).toString()) < QVersionNumber::fromString(UBSettings::currentFileVersion)) { scan(); mToc->save(); @@ -301,6 +319,8 @@ std::shared_ptr UBDocument::getDocument(std::shared_ptr tocSceneUuids; @@ -320,13 +340,37 @@ void UBDocument::scan() // Load the scenes and check the media assets. int pageProcessed = -1; + int currentPage = 0; for (const auto page : pages) { + UBApplication::showMessage(UBDocumentController::tr("Scanning page %1 of %2").arg(++currentPage).arg(pages.count()), true); int pageId = page.mid(4, page.length() - 8).toInt(); auto scene = UBPersistenceManager::persistenceManager()->loadDocumentScene(mProxy, pageId); - // Check the media asset UUIDs. - // TODO Really?? Convert it to a SHA-1 based UUIDv5 if needed. Copy the asset file in this case. + + const auto mediaAssetItems = scene->mediaAssetItems(); + + for (auto item : mediaAssetItems) + { + // Check the media asset UUIDs. + // Convert it to a SHA-1 based UUIDv5 if needed. Copy the asset file in this case. + QUuid assetUuid = item->mediaAssetUuid(); + + if (assetUuid.version() != QUuid::Sha1) + { + // copy media asset using a new UuidV5 + const auto source = item->mediaAssets().at(0); + const auto sourcePath = mProxy->persistencePath() + "/" + source; + const auto assetUuidV5 = UBMediaAssetItem::createMediaAssetUuid(sourcePath); + + auto target = source; + target.replace(assetUuid.toString(QUuid::WithoutBraces), assetUuidV5.toString(QUuid::WithoutBraces)); + + UBPersistenceManager::persistenceManager()->copyAsset(mProxy, source, target); + item->setMediaAsset(mProxy->persistencePath(), target); + scene->setModified(true); + } + } // Check whether the tocSceneUuids already contains this scene. // If yes, locate and update the TOC entry @@ -351,6 +395,11 @@ void UBDocument::scan() mToc->setPageId(pageProcessed, pageId); mToc->setAssets(pageProcessed, scene->relativeDependencies()); } + + if (scene->isModified()) + { + persistPage(scene, pageProcessed); + } } // When finished, remove all scenes still in tocSceneUuids from the TOC. @@ -361,8 +410,17 @@ void UBDocument::scan() mToc->remove(mToc->findUuid(uuid)); } - // TODO cleanup possibly later Go through the TOC and create a set of all referenced media assets. // Delete all unreferenced media asset files. + UBApplication::showMessage(UBDocumentController::tr("Remove unused assets").arg(++currentPage).arg(pages.count()), true); + deleteUnreferencedAssets(); + + // now we have updated the document version + mProxy->setMetaData(UBSettings::documentVersion, UBSettings::currentFileVersion); + UBMetadataDcSubsetAdaptor::persist(mProxy); + + UBApplication::showMessage(UBDocumentController::tr("Scan completed")); + + QApplication::restoreOverrideCursor(); } void UBDocument::copyPage(int fromIndex, UBDocument* to, int toIndex) @@ -374,7 +432,7 @@ void UBDocument::copyPage(int fromIndex, UBDocument* to, int toIndex) const auto uuid = UBPersistenceManager::persistenceManager()->copyDocumentScene(mProxy, mToc->pageId(fromIndex), to->proxy(), pageId, dependencies); // add thumbnail - to->mThumbnailScene->insertThumbnail(toIndex); + to->thumbnailScene()->insertThumbnail(toIndex); // update target TOC to->mToc->setUuid(toIndex, uuid); @@ -382,6 +440,25 @@ void UBDocument::copyPage(int fromIndex, UBDocument* to, int toIndex) to->mToc->save(); } +void UBDocument::deleteUnreferencedAssets() +{ + // Go through the TOC and create a set of all referenced media assets. + QSet referencedMediaAssets; + + for (int index = 0; index < mToc->pageCount(); ++index) + { + const auto assets = mToc->assets(index); + + for (const auto asset : assets) + { + referencedMediaAssets << asset; + } + } + + // Cleanup unused media assets + UBPersistenceManager::persistenceManager()->cleanupMediaAssets(mProxy, referencedMediaAssets); +} + std::shared_ptr UBDocument::findDocument(std::shared_ptr proxy) { if (!proxy) diff --git a/src/document/UBDocument.h b/src/document/UBDocument.h index 5ebf78deb..a26ec5229 100644 --- a/src/document/UBDocument.h +++ b/src/document/UBDocument.h @@ -65,7 +65,7 @@ class UBDocument std::shared_ptr loadScene(int index, bool cacheNeighboringScenes = true); std::shared_ptr getScene(int index); QList pageRelativeDependencies(int index); - UBThumbnailScene* thumbnailScene() const; + UBThumbnailScene* thumbnailScene(); UBToc* toc(); int pageCount(); @@ -78,12 +78,13 @@ class UBDocument private: void scan(); void copyPage(int fromIndex, UBDocument* to, int toIndex); + void deleteUnreferencedAssets(); static std::shared_ptr findDocument(std::shared_ptr proxy); private: std::shared_ptr mProxy{nullptr}; - UBThumbnailScene* mThumbnailScene{nullptr}; + std::unique_ptr mThumbnailScene; UBToc* mToc{nullptr}; static QList> sDocuments; diff --git a/src/domain/UBMediaAssetItem.cpp b/src/domain/UBMediaAssetItem.cpp index 0ace9f01c..9b2815d34 100644 --- a/src/domain/UBMediaAssetItem.cpp +++ b/src/domain/UBMediaAssetItem.cpp @@ -35,6 +35,48 @@ QUuid UBMediaAssetItem::createMediaAssetUuid(const QByteArray& data) return QUuid::createUuidV5(namespaceUuid, data); } +QUuid UBMediaAssetItem::createMediaAssetUuid(const QString& path) +{ + QFileInfo fileInfo{path}; + + if (!fileInfo.exists()) + { + return {}; + } + + if (fileInfo.isFile() && fileInfo.isReadable()) + { + QFile file{path}; + + if (file.open(QFile::ReadOnly)) + { + return createMediaAssetUuid(file.readAll()); + } + + return {}; + } + + if (fileInfo.isDir()) + { + const auto widgetFiles = fileInfo.dir().entryInfoList({"*.xml", "*.html"}, QDir::Files, QDir::Name); + QByteArray data; + + for (const auto fileInfo : widgetFiles) + { + QFile file(fileInfo.absoluteFilePath()); + + if (file.open(QFile::ReadOnly)) + { + data.append(file.readAll()); + } + } + + return createMediaAssetUuid(data); + } + + return {}; +} + QUuid UBMediaAssetItem::uuidFromPath(const QString& path) const { static QRegularExpression uuidPattern("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"); diff --git a/src/domain/UBMediaAssetItem.h b/src/domain/UBMediaAssetItem.h index f4928f563..c572b2121 100644 --- a/src/domain/UBMediaAssetItem.h +++ b/src/domain/UBMediaAssetItem.h @@ -41,6 +41,7 @@ class UBMediaAssetItem : public UBItem QUuid mediaAssetUuid() const; static QUuid createMediaAssetUuid(const QByteArray& data); + static QUuid createMediaAssetUuid(const QString& path); protected: QUuid uuidFromPath(const QString& path) const; From 95f20025829c46bf62fafb3065c299a9ca268111 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Fri, 16 May 2025 13:09:52 +0200 Subject: [PATCH 016/133] feat: renumber pages on export - when exporting a document, renumber the page files in ascending order so that the document is backward compatible - works for UBZ and UBX - fix some copyright headers Signed-off-by: letsfindaway --- src/adaptors/CMakeLists.txt | 2 + src/adaptors/UBExportDocument.cpp | 18 ++++- src/adaptors/UBExportDocumentSetAdaptor.cpp | 17 ++++- src/adaptors/UBPageMapper.cpp | 80 +++++++++++++++++++++ src/adaptors/UBPageMapper.h | 62 ++++++++++++++++ src/adaptors/adaptors.pri | 2 + src/document/UBToc.cpp | 9 ++- src/document/UBToc.h | 7 +- src/document/UBTocSerializer.cpp | 2 +- src/document/UBTocSerializer.h | 2 +- src/frameworks/UBFileSystemUtils.cpp | 17 ++++- src/frameworks/UBFileSystemUtils.h | 4 +- 12 files changed, 207 insertions(+), 15 deletions(-) create mode 100644 src/adaptors/UBPageMapper.cpp create mode 100644 src/adaptors/UBPageMapper.h diff --git a/src/adaptors/CMakeLists.txt b/src/adaptors/CMakeLists.txt index e9a43b2ad..107edbafc 100644 --- a/src/adaptors/CMakeLists.txt +++ b/src/adaptors/CMakeLists.txt @@ -23,6 +23,8 @@ target_sources(${PROJECT_NAME} PRIVATE UBImportPDF.h UBMetadataDcSubsetAdaptor.cpp UBMetadataDcSubsetAdaptor.h + UBPageMapper.cpp + UBPageMapper.h UBSvgSubsetAdaptor.cpp UBSvgSubsetAdaptor.h UBThumbnailAdaptor.cpp diff --git a/src/adaptors/UBExportDocument.cpp b/src/adaptors/UBExportDocument.cpp index 12fb98cfb..0569f2f97 100644 --- a/src/adaptors/UBExportDocument.cpp +++ b/src/adaptors/UBExportDocument.cpp @@ -31,13 +31,15 @@ #include "frameworks/UBPlatformUtils.h" +#include "adaptors/UBPageMapper.h" + #include "core/UBDocumentManager.h" #include "core/UBApplication.h" +#include "core/UBSettings.h" #include "document/UBDocumentProxy.h" #include "document/UBDocumentController.h" - -#include "globals/UBGlobals.h" +#include "document/UBToc.h" #ifdef Q_OS_OSX #include @@ -78,8 +80,18 @@ bool UBExportDocument::persistsDocument(std::shared_ptr pDocume QDir documentDir = QDir(pDocumentProxy->persistencePath()); + // try to load a TOC for mapping and check version number + UBToc toc{pDocumentProxy->persistencePath()}; + std::unique_ptr mapper{nullptr}; + const auto version = QVersionNumber::fromString(pDocumentProxy->metaData(UBSettings::documentVersion).toString()); + + if (toc.load() && version >= QVersionNumber::fromString(UBSettings::currentFileVersion)) + { + mapper = std::unique_ptr{new UBPageMapper{pDocumentProxy->persistencePath(), &toc}}; + } + QuaZipFile outFile(&zip); - UBFileSystemUtils::compressDirInZip(documentDir, "", &outFile, true, this); + UBFileSystemUtils::compressDirInZip(documentDir, "", &outFile, true, mapper.get(), this); zip.close(); diff --git a/src/adaptors/UBExportDocumentSetAdaptor.cpp b/src/adaptors/UBExportDocumentSetAdaptor.cpp index 2413ebb92..0f0fa2f71 100644 --- a/src/adaptors/UBExportDocumentSetAdaptor.cpp +++ b/src/adaptors/UBExportDocumentSetAdaptor.cpp @@ -28,6 +28,8 @@ #include "UBExportDocumentSetAdaptor.h" #include "UBExportDocument.h" +#include "adaptors/UBPageMapper.h" + #include "frameworks/UBPlatformUtils.h" #include "core/UBDocumentManager.h" @@ -35,8 +37,8 @@ #include "document/UBDocumentProxy.h" #include "document/UBDocumentController.h" +#include "document/UBToc.h" -#include "globals/UBGlobals.h" #include "core/UBPersistenceManager.h" #ifdef Q_OS_OSX @@ -167,8 +169,19 @@ bool UBExportDocumentSetAdaptor::addDocumentToZip(const QModelIndex &pIndex, UBD QString documentPath(pDocumentProxy->persistencePath()); QDir documentDir = QDir(pDocumentProxy->persistencePath()); + + // try to load a TOC for mapping and check version number + UBToc toc{pDocumentProxy->persistencePath()}; + std::unique_ptr mapper{nullptr}; + const auto version = QVersionNumber::fromString(pDocumentProxy->metaData(UBSettings::documentVersion).toString()); + + if (toc.load() && version >= QVersionNumber::fromString(UBSettings::currentFileVersion)) + { + mapper = std::unique_ptr{new UBPageMapper{pDocumentProxy->persistencePath(), &toc}}; + } + QuaZipFile zipFile(&zip); - UBFileSystemUtils::compressDirInZip(documentDir, QFileInfo(documentPath).fileName() + "/", &zipFile, false); + UBFileSystemUtils::compressDirInZip(documentDir, QFileInfo(documentPath).fileName() + "/", &zipFile, false, mapper.get()); if(zip.getZipError() != 0) { diff --git a/src/adaptors/UBPageMapper.cpp b/src/adaptors/UBPageMapper.cpp new file mode 100644 index 000000000..5fbf5505b --- /dev/null +++ b/src/adaptors/UBPageMapper.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + +#include "UBPageMapper.h" + +#include "core/UBPersistenceManager.h" +#include "document/UBToc.h" + +UBPageMapper::UBPageMapper(const QString& documentPath, UBToc* toc) + : mDocumentPath{documentPath} + , mSourceToc{toc} +{ + if (!mTempDir.isValid()) + { + qWarning() << "UBPageMapper: unable to create temporary directory"; + return; + } + + auto pm = UBPersistenceManager::persistenceManager(); + mMappedToc = std::unique_ptr{new UBToc(*mSourceToc, mTempDir.path())}; + + // create page map and target TOC + for (int index = 0; index < mSourceToc->pageCount(); ++index) + { + const auto id = mSourceToc->pageId(index); + + // remove the leading "/" from the scene and thumbnail file names + mFileMap[pm->sceneFilenameForId(id).mid(1)] = pm->sceneFilenameForId(index).mid(1); + mFileMap[pm->thumbnailFilenameForId(id).mid(1)] = pm->thumbnailFilenameForId(index).mid(1); + + // set id to be same as index in the mapped TOC + mMappedToc->setPageId(index, index); + } + + mMappedToc->save(); +} + +UBPageMapper::MapResult UBPageMapper::map(const QString& filename) const +{ + if (!mMappedToc) + { + return {QFileInfo{mDocumentPath + "/" + filename}, filename}; + } + + if (filename.startsWith("toc.")) + { + // return the mapped TOC + return {QFileInfo(mTempDir.path() + "/" + filename), filename}; + } + + const auto mappedFilename = mFileMap.value(filename); + + if (!mappedFilename.isEmpty()) + { + // return the mapped file + return {QFileInfo{mDocumentPath + "/" + filename}, mappedFilename}; + } + + // return unmapped file + return {QFileInfo{mDocumentPath + "/" + filename}, filename}; +} diff --git a/src/adaptors/UBPageMapper.h b/src/adaptors/UBPageMapper.h new file mode 100644 index 000000000..88de2711c --- /dev/null +++ b/src/adaptors/UBPageMapper.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + +#pragma once + +#include +#include +#include + +#include + +// forward +class UBToc; + +/** + * @brief The UBPageMapper maps a file name which should be saved in a ZIP + * file for export to an input file and an output file name. + * + * This function is used to sequentially renumber pages on export. Page file + * names are created according to the page sequence in the TOC. Additionally + * an updated TOC is created which reflects the renamed page files. + */ +class UBPageMapper +{ +public: + struct MapResult + { + QFileInfo input; ///< file for reading + QString output; ///< file name for the output file in the ZIP archive + }; + +public: + UBPageMapper(const QString& documentPath, UBToc* toc); + + MapResult map(const QString& filename) const; + +private: + const QString mDocumentPath; + const UBToc* mSourceToc{nullptr}; + std::unique_ptr mMappedToc; + QHash mFileMap; + QTemporaryDir mTempDir; +}; diff --git a/src/adaptors/adaptors.pri b/src/adaptors/adaptors.pri index d8cc98ab0..242ab0ad7 100644 --- a/src/adaptors/adaptors.pri +++ b/src/adaptors/adaptors.pri @@ -12,6 +12,7 @@ HEADERS += src/adaptors/UBExportAdaptor.h\ src/adaptors/UBImportPDF.h \ src/adaptors/UBImportImage.h \ src/adaptors/UBExportWeb.h \ + src/adaptors/UBPageMapper.h \ $$PWD/UBExportDocumentSetAdaptor.h \ $$PWD/UBImportDocumentSetAdaptor.h @@ -29,5 +30,6 @@ SOURCES += src/adaptors/UBExportAdaptor.cpp\ src/adaptors/UBImportPDF.cpp \ src/adaptors/UBImportImage.cpp \ src/adaptors/UBExportWeb.cpp \ + src/adaptors/UBPageMapper.cpp \ $$PWD/UBExportDocumentSetAdaptor.cpp \ $$PWD/UBImportDocumentSetAdaptor.cpp diff --git a/src/document/UBToc.cpp b/src/document/UBToc.cpp index 12ee9c8b1..90e017771 100644 --- a/src/document/UBToc.cpp +++ b/src/document/UBToc.cpp @@ -30,11 +30,18 @@ static const QString UUID{"uuid"}; static const QString PAGE_ID{"id"}; static const QString ASSETS("assets"); -UBToc::UBToc(QString documentPath) +UBToc::UBToc(const QString& documentPath) : mDocumentPath{documentPath} { } +UBToc::UBToc(const UBToc& other, const QString& documentPath) + : mDocumentPath{documentPath} + , mVersion{other.mVersion} + , mToc{other.mToc} +{ +} + QVersionNumber UBToc::version() const { return mVersion; diff --git a/src/document/UBToc.h b/src/document/UBToc.h index e59872995..ba23544b7 100644 --- a/src/document/UBToc.h +++ b/src/document/UBToc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2025API of Département de l'Instruction Publique (DIP-SEM) + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) * * This file is part of OpenBoard. * @@ -33,7 +33,8 @@ static const QVersionNumber TOC_VERSION{1, 0}; class UBToc { public: - UBToc(QString documentPath); + UBToc(const QString& documentPath); + UBToc(const UBToc& other, const QString& documentPath); QVersionNumber version() const; @@ -67,7 +68,7 @@ class UBToc void assureSize(int index); private: - QString mDocumentPath; + const QString mDocumentPath; QVersionNumber mVersion{TOC_VERSION}; QVector mToc; int mNextAvailablePageId{0}; diff --git a/src/document/UBTocSerializer.cpp b/src/document/UBTocSerializer.cpp index 0de392e0c..5977e563f 100644 --- a/src/document/UBTocSerializer.cpp +++ b/src/document/UBTocSerializer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2025API of Département de l'Instruction Publique (DIP-SEM) + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) * * This file is part of OpenBoard. * diff --git a/src/document/UBTocSerializer.h b/src/document/UBTocSerializer.h index 87764d667..9d7d9d1e2 100644 --- a/src/document/UBTocSerializer.h +++ b/src/document/UBTocSerializer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2025API of Département de l'Instruction Publique (DIP-SEM) + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) * * This file is part of OpenBoard. * diff --git a/src/frameworks/UBFileSystemUtils.cpp b/src/frameworks/UBFileSystemUtils.cpp index 2791fd3ef..ea238237b 100644 --- a/src/frameworks/UBFileSystemUtils.cpp +++ b/src/frameworks/UBFileSystemUtils.cpp @@ -31,7 +31,7 @@ #include -#include "core/UBApplication.h" +#include "adaptors/UBPageMapper.h" #include "globals/UBGlobals.h" @@ -657,7 +657,8 @@ QString UBFileSystemUtils::getFirstExistingFileFromList(const QString& path, con } -bool UBFileSystemUtils::compressDirInZip(const QDir& pDir, const QString& pDestPath, QuaZipFile *pOutZipFile, bool pRootDocumentFolder, UBProcessingProgressListener* progressListener) +bool UBFileSystemUtils::compressDirInZip(const QDir& pDir, const QString& pDestPath, QuaZipFile *pOutZipFile, + bool pRootDocumentFolder, UBPageMapper* mapper, UBProcessingProgressListener* progressListener) { QFileInfoList files = pDir.entryInfoList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); @@ -699,6 +700,16 @@ bool UBFileSystemUtils::compressDirInZip(const QDir& pDir, const QString& pDestP progressListener->processing(objectType, pageFiles.indexOf(file), pageFiles.size()); } + auto outFilename = file.fileName(); + + // map file + if (mapper) + { + auto result = mapper->map(file.fileName()); + file = result.input; + outFilename = result.output; + } + QFile inFile(file.absoluteFilePath()); if(!inFile.open(QIODevice::ReadOnly)) { @@ -708,7 +719,7 @@ bool UBFileSystemUtils::compressDirInZip(const QDir& pDir, const QString& pDestP qDebug() << "will open" << pDestPath << file.fileName() << inFile.fileName(); - if(!pOutZipFile->open(QIODevice::WriteOnly, QuaZipNewInfo(pDestPath + file.fileName(), inFile.fileName()))) + if(!pOutZipFile->open(QIODevice::WriteOnly, QuaZipNewInfo(pDestPath + outFilename, inFile.fileName()))) { qWarning() << "Compression of file" << inFile.fileName() << " failed. Cause: outFile.open(): " << pOutZipFile->getZipError(); inFile.close(); diff --git a/src/frameworks/UBFileSystemUtils.h b/src/frameworks/UBFileSystemUtils.h index 67b844a6d..56a37e528 100644 --- a/src/frameworks/UBFileSystemUtils.h +++ b/src/frameworks/UBFileSystemUtils.h @@ -36,6 +36,7 @@ #include "core/UB.h" class QuaZipFile; +class UBPageMapper; class UBProcessingProgressListener; class UBFileSystemUtils : public QObject @@ -104,7 +105,8 @@ class UBFileSystemUtils : public QObject * @return bool. true if compression is successful. */ static bool compressDirInZip(const QDir& pDir, const QString& pDestDir, QuaZipFile *pOutZipFile - , bool pRootDocumentFolder, UBProcessingProgressListener* progressListener = 0); + , bool pRootDocumentFolder, UBPageMapper* mapper = nullptr + , UBProcessingProgressListener* progressListener = nullptr); static bool expandZipToDir(const QFile& pZipFile, const QDir& pTargetDir); From 0a04f2839849e75d70a79d52da731fe15453752c Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Fri, 23 May 2025 11:43:55 +0200 Subject: [PATCH 017/133] refactor: use QtConcurrent for UBBackgroundLoader - QtConcurrent::mapped provides the functions implemented in UBBackgroundLoader nearly out of the box - use multiple threads, thus improving performance - add constructor to limit amount of data for each file Signed-off-by: letsfindaway --- src/frameworks/UBBackgroundLoader.cpp | 90 ++++++++------------------- src/frameworks/UBBackgroundLoader.h | 38 ++++++----- src/gui/UBThumbnailScene.cpp | 1 - 3 files changed, 45 insertions(+), 84 deletions(-) diff --git a/src/frameworks/UBBackgroundLoader.cpp b/src/frameworks/UBBackgroundLoader.cpp index f27d0e773..8af981330 100644 --- a/src/frameworks/UBBackgroundLoader.cpp +++ b/src/frameworks/UBBackgroundLoader.cpp @@ -23,105 +23,69 @@ #include "UBBackgroundLoader.h" #include +#include -#include "core/UBApplication.h" -UBBackgroundLoader::UBBackgroundLoader(QObject* parent) - : QThread{parent} +UBBackgroundLoader::UBBackgroundLoader(const QList>& paths, int maxBytes, QObject* parent) + : QObject{parent} + , mCount{paths.count()} { + mFuture = QtConcurrent::mapped(paths, ReadData{maxBytes}); } -UBBackgroundLoader::UBBackgroundLoader(QList> paths, QObject* parent) - : QThread{parent} +UBBackgroundLoader::UBBackgroundLoader(const QList>& paths, QObject* parent) + : UBBackgroundLoader{paths, -1, parent} { - mPaths.insert(mPaths.cend(), paths.constBegin(), paths.constEnd()); - mPathCounter.release(paths.size()); } UBBackgroundLoader::~UBBackgroundLoader() { abort(); - wait(); } bool UBBackgroundLoader::isIdle() { - QMutexLocker lock{&mMutex}; - return mPaths.empty() && mResults.empty(); + return mFuture.isFinished() && mIndex == mFuture.resultCount(); } bool UBBackgroundLoader::isResultAvailable() { - QMutexLocker lock{&mMutex}; - return !mResults.empty(); + return mFuture.isResultReadyAt(mIndex); } std::pair UBBackgroundLoader::takeResult() { - QMutexLocker lock{&mMutex}; - - if (mResults.empty()) - { - return {}; - } - - const auto result = mResults.front(); - mResults.pop_front(); - return result; + return mFuture.resultAt(mIndex++); } -void UBBackgroundLoader::start() +void UBBackgroundLoader::abort() { - mRunning = true; - QThread::start(); + mFuture.cancel(); } -void UBBackgroundLoader::addPaths(QList> paths) +UBBackgroundLoader::ReadData::ReadData(int maxBytes) + : mMaxBytes{maxBytes} { - QMutexLocker lock{&mMutex}; - mPaths.insert(mPaths.cend(), paths.constBegin(), paths.constEnd()); - mPathCounter.release(paths.size()); } -void UBBackgroundLoader::abort() +UBBackgroundLoader::ReadData::result_type UBBackgroundLoader::ReadData::operator()(const std::pair& path) { - mRunning = false; - mPathCounter.release(); -} + QFile file{path.second}; + QByteArray result; -void UBBackgroundLoader::run() -{ - while (mRunning && !UBApplication::isClosing) + if (file.open(QFile::ReadOnly)) { - mPathCounter.acquire(); - - if (mRunning && !UBApplication::isClosing) + if (mMaxBytes < 0) { - std::pair path; - - { - QMutexLocker lock{&mMutex}; - path = mPaths.front(); - mPaths.pop_front(); - } - - QFile file{path.second}; - QByteArray result; - - if (file.open(QFile::ReadOnly)) - { - result = file.readAll(); - file.close(); - } - - { - QMutexLocker lock{&mMutex}; - mResults.push_back({path.first, result}); - } - - emit resultAvailable(path.first, result); + result = file.readAll(); + } + else + { + result = file.read(mMaxBytes); } + + file.close(); } - quit(); + return {path.first, result}; } diff --git a/src/frameworks/UBBackgroundLoader.h b/src/frameworks/UBBackgroundLoader.h index 2fec80318..0795ad820 100644 --- a/src/frameworks/UBBackgroundLoader.h +++ b/src/frameworks/UBBackgroundLoader.h @@ -22,40 +22,38 @@ #pragma once -#include +#include #include -#include -#include -#include -class UBBackgroundLoader : public QThread + +class UBBackgroundLoader : public QObject { Q_OBJECT public: - explicit UBBackgroundLoader(QObject* parent = nullptr); - UBBackgroundLoader(QList> paths, QObject* parent = nullptr); + UBBackgroundLoader(const QList>& paths, int maxBytes, QObject* parent = nullptr); + UBBackgroundLoader(const QList>& paths, QObject* parent = nullptr); virtual ~UBBackgroundLoader(); bool isIdle(); bool isResultAvailable(); std::pair takeResult(); - -public slots: - void start(); - void addPaths(QList> paths); void abort(); -signals: - void resultAvailable(int index, QByteArray data); +private: + struct ReadData + { + typedef std::pair result_type; + + ReadData(int maxBytes); + result_type operator()(const std::pair& path); -protected: - void run() override; + private: + const int mMaxBytes{-1}; + }; private: - std::deque> mPaths{}; - std::deque> mResults{}; - QMutex mMutex{}; - QSemaphore mPathCounter{}; - bool mRunning{false}; + QFuture> mFuture; + const qsizetype mCount{0}; + int mIndex{0}; }; diff --git a/src/gui/UBThumbnailScene.cpp b/src/gui/UBThumbnailScene.cpp index 8b5bf0eb1..fc5e0bf4f 100644 --- a/src/gui/UBThumbnailScene.cpp +++ b/src/gui/UBThumbnailScene.cpp @@ -229,7 +229,6 @@ void UBThumbnailScene::createThumbnails(int startIndex) } mLoader = new UBBackgroundLoader{paths, this}; - mLoader->start(); // now create all missing thumbnails for document as they arrive from the loader loadNextThumbnail(); From 2526c6ae153495e929a2770316c121ab4a9d13eb Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Wed, 28 May 2025 09:53:15 +0200 Subject: [PATCH 018/133] perf: document scan in background - separate scanning into two phases (UUID and asset) - perform UUID scanning when document is selected - perform asset scanning in background when document is opened - limit number of parallel loaded scenes for asset scanning - retrieve results from background loader by signal/slot to allow throttling - retrieve scene UUID and version from scene header - use separate threads for future watcher and blocking buffer - do not cache scenes loaded for asset scanning - save TOC only if modified Signed-off-by: letsfindaway --- src/adaptors/UBSvgSubsetAdaptor.cpp | 63 ++++- src/adaptors/UBSvgSubsetAdaptor.h | 4 +- src/core/UBPersistenceManager.cpp | 19 +- src/core/UBPersistenceManager.h | 2 +- src/core/UBSceneCache.cpp | 61 +++-- src/core/UBSceneCache.h | 8 +- src/document/UBDocument.cpp | 338 ++++++++++++++++++++------ src/document/UBDocument.h | 16 +- src/document/UBDocumentController.cpp | 1 + src/document/UBToc.cpp | 34 ++- src/document/UBToc.h | 7 +- src/domain/UBGraphicsScene.cpp | 6 + src/domain/UBGraphicsScene.h | 1 + src/frameworks/CMakeLists.txt | 2 + src/frameworks/UBBackgroundLoader.cpp | 64 +++-- src/frameworks/UBBackgroundLoader.h | 27 +- src/frameworks/UBBlockingBuffer.cpp | 107 ++++++++ src/frameworks/UBBlockingBuffer.h | 58 +++++ src/frameworks/frameworks.pri | 2 + src/gui/UBThumbnailScene.cpp | 110 +++------ src/gui/UBThumbnailScene.h | 2 +- 21 files changed, 707 insertions(+), 225 deletions(-) create mode 100644 src/frameworks/UBBlockingBuffer.cpp create mode 100644 src/frameworks/UBBlockingBuffer.h diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index 74c63a838..1a71d5b68 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -303,6 +303,64 @@ QUuid UBSvgSubsetAdaptor::sceneUuid(std::shared_ptr proxy, cons return uuid; } +QUuid UBSvgSubsetAdaptor::sceneUuid(const QString& xmlContent) +{ + const int uuidIndex = xmlContent.indexOf("uuid"); + + if (-1 == uuidIndex) + { + qWarning() << "Cannot find uuid attribute"; + return {}; + } + + int quoteStartIndex = xmlContent.indexOf('"', uuidIndex); + + if (-1 == quoteStartIndex) + { + qWarning() << "Cannot find start of uuid attribute value"; + return {}; + } + + int quoteEndIndex = xmlContent.indexOf('"', quoteStartIndex + 1); + + if (-1 == quoteEndIndex) + { + qWarning() << "Cannot find end of uuid attribute value"; + return {}; + } + + return QUuid{xmlContent.mid(quoteStartIndex + 1, quoteEndIndex - quoteStartIndex - 1)}; +} + +QVersionNumber UBSvgSubsetAdaptor::sceneVersion(const QString& xmlContent) +{ + const int versionIndex = xmlContent.indexOf("ub:version"); + + if (-1 == versionIndex) + { + qWarning() << "Cannot find ub:version attribute"; + return {}; + } + + int quoteStartIndex = xmlContent.indexOf('"', versionIndex); + + if (-1 == quoteStartIndex) + { + qWarning() << "Cannot find start of ub:version attribute value"; + return {}; + } + + int quoteEndIndex = xmlContent.indexOf('"', quoteStartIndex + 1); + + if (-1 == quoteEndIndex) + { + qWarning() << "Cannot find end of ub:version attribute value"; + return {}; + } + + return QVersionNumber::fromString(xmlContent.mid(quoteStartIndex + 1, quoteEndIndex - quoteStartIndex - 1)); +} + std::shared_ptr UBSvgSubsetAdaptor::loadScene(std::shared_ptr proxy, const QByteArray& pArray) { @@ -310,9 +368,10 @@ std::shared_ptr UBSvgSubsetAdaptor::loadScene(std::shared_ptr UBSvgSubsetAdaptor::prepareLoadingScene(std::shared_ptr proxy, const int pageId) +std::shared_ptr UBSvgSubsetAdaptor::prepareLoadingScene(std::shared_ptr proxy, + const int pageId, std::optional xmlContent) { - const auto fileContent = loadSceneAsText(proxy, pageId); + const auto fileContent = xmlContent.value_or(loadSceneAsText(proxy, pageId)); auto context = std::make_shared(proxy, fileContent); return context; } diff --git a/src/adaptors/UBSvgSubsetAdaptor.h b/src/adaptors/UBSvgSubsetAdaptor.h index 9b89417dc..4ebacd469 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.h +++ b/src/adaptors/UBSvgSubsetAdaptor.h @@ -85,11 +85,13 @@ class UBSvgSubsetAdaptor static QByteArray loadSceneAsText(std::shared_ptr proxy, const int pageId); static std::shared_ptr loadScene(std::shared_ptr proxy, const QByteArray& pArray); - static std::shared_ptr prepareLoadingScene(std::shared_ptr proxy, const int pageId); + static std::shared_ptr prepareLoadingScene(std::shared_ptr proxy, const int pageId, std::optional xmlContent = {}); static void persistScene(std::shared_ptr proxy, std::shared_ptr pScene, const int pageId); static QUuid sceneUuid(std::shared_ptr proxy, const int pageId); + static QUuid sceneUuid(const QString& xmlContent); + static QVersionNumber sceneVersion(const QString& xmlContent); static void setSceneUuid(std::shared_ptr proxy, const int pageId, QUuid pUuid); static void replicateScene(const QString& sourcePath, const QString& targetPath, QUuid uuid); diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index 840eb178c..581f6e34a 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -682,16 +682,6 @@ std::shared_ptr UBPersistenceManager::createDocumentFromDir(con doc->setMetaData(UBSettings::documentName, pName); } - doc->setUuid(QUuid::createUuid()); - auto document = UBDocument::getDocument(doc); - - for(int i = 0; i < document->pageCount(); i++) - { - UBSvgSubsetAdaptor::setSceneUuid(doc, i, QUuid::createUuid()); - UBThumbnailAdaptor::generateMissingThumbnail(document.get(), i); - } - - //work around the bool addDoc = false; if (!promptDialogIfExists) { @@ -833,12 +823,9 @@ std::shared_ptr UBPersistenceManager::loadDocumentScene(std::sh return mSceneCache.value(proxy, pageId); } -void UBPersistenceManager::prepareSceneLoading(std::shared_ptr proxy, int pageId) +std::shared_ptr UBPersistenceManager::prepareSceneLoading(std::shared_ptr proxy, int pageId, std::optional xmlContent, bool cached) { - if (!mSceneCache.contains(proxy, pageId)) - { - mSceneCache.prepareLoading(proxy, pageId); - } + return mSceneCache.prepareLoading(proxy, pageId, xmlContent, cached); } std::shared_ptr UBPersistenceManager::getDocumentScene(std::shared_ptr pDocumentProxy, int pageId) @@ -913,8 +900,6 @@ void UBPersistenceManager::persistDocumentScene(std::shared_ptr std::shared_ptr UBPersistenceManager::persistDocumentMetadata(std::shared_ptr pDocumentProxy, bool forceImmediateSaving) { - //cleanupDocument(pDocumentProxy); - if (forceImmediateSaving) { UBMetadataDcSubsetAdaptor::persist(pDocumentProxy); diff --git a/src/core/UBPersistenceManager.h b/src/core/UBPersistenceManager.h index ce4d6f646..0a4f7554c 100644 --- a/src/core/UBPersistenceManager.h +++ b/src/core/UBPersistenceManager.h @@ -106,7 +106,7 @@ class UBPersistenceManager : public QObject virtual std::shared_ptr createDocumentSceneAt(std::shared_ptr pDocumentProxy, int pageId, bool useUndoRedoStack = true); virtual std::shared_ptr loadDocumentScene(std::shared_ptr pDocumentProxy, int pageId); - void prepareSceneLoading(std::shared_ptr proxy, int pageId); + std::shared_ptr prepareSceneLoading(std::shared_ptr proxy, int pageId, std::optional xmlContent = {}, bool cached = true); std::shared_ptr getDocumentScene(std::shared_ptr pDocumentProxy, int pageId); bool copyAsset(std::shared_ptr proxy, const QString& fromRelativePath, const QString& toRelativePath); diff --git a/src/core/UBSceneCache.cpp b/src/core/UBSceneCache.cpp index dde94d18b..90575f552 100644 --- a/src/core/UBSceneCache.cpp +++ b/src/core/UBSceneCache.cpp @@ -61,38 +61,32 @@ std::shared_ptr UBSceneCache::createScene(std::shared_ptr UBSceneCache::prepareLoading(std::shared_ptr proxy, int pageId) +std::shared_ptr UBSceneCache::prepareLoading(std::shared_ptr proxy, int pageId, std::optional xmlContent, bool cached) { if (mSceneCache.contains({proxy, pageId})) { - return value(proxy, pageId); + return nullptr; } // no entry in cache; create a cache entry to load scene qDebug() << "Preparing to load scene" << pageId; - auto cacheEntry = std::make_shared(proxy, pageId); + auto cacheEntry = std::make_shared(proxy, pageId, xmlContent); + + if (cached) + { + insertEntry({proxy, pageId}, cacheEntry); + } - insertEntry({proxy, pageId}, cacheEntry); cacheEntry->startLoading(); - return nullptr; + + // return the cache entry as opaque handle to keep the entry alive for uncached loading + return cacheEntry; } void UBSceneCache::insert (std::shared_ptr proxy, int pageId, std::shared_ptr scene) { - // remove all entries pointing to this scene - const auto keylist = mSceneCache.keys(); - - for (const auto& key : keylist) - { - auto entry = mSceneCache.value(key); - - if (entry->isSceneAvailable() && entry->scene() == scene) - { - mSceneCache.remove(key); - mCachedKeyFIFO.removeAll(key); - } - } + removeSceneFromCache(scene); UBSceneCacheID key{proxy, pageId}; insertEntry(key, std::make_shared(scene)); @@ -144,7 +138,7 @@ void UBSceneCache::removeScene(std::shared_ptr proxy, int pageI if (!entry->isSceneAvailable() || !entry->scene()->isActive()) { - int count = mSceneCache.remove(key); + mSceneCache.remove(key); mCachedKeyFIFO.removeAll(key); if (entry->isSceneAvailable()) @@ -175,6 +169,28 @@ void UBSceneCache::removeAllScenes(std::shared_ptr proxy) } } +void UBSceneCache::removeSceneFromCache(std::shared_ptr scene) +{ + if (scene->isActive()) + { + return; + } + + // remove all entries pointing to this scene + const auto keylist = mSceneCache.keys(); + + for (const auto& key : keylist) + { + auto entry = mSceneCache.value(key); + + if (entry->isSceneAvailable() && entry->scene() == scene) + { + mSceneCache.remove(key); + mCachedKeyFIFO.removeAll(key); + } + } +} + void UBSceneCache::insertEntry(UBSceneCacheID key, std::shared_ptr entry) { @@ -204,9 +220,9 @@ void UBSceneCache::insertEntry(UBSceneCacheID key, std::shared_ptr proxy, int pageId) +UBSceneCache::SceneCacheEntry::SceneCacheEntry(std::shared_ptr proxy, int pageId, std::optional xmlContent) { - mContext = UBSvgSubsetAdaptor::prepareLoadingScene(proxy, pageId); + mContext = UBSvgSubsetAdaptor::prepareLoadingScene(proxy, pageId, xmlContent); } UBSceneCache::SceneCacheEntry::SceneCacheEntry(std::shared_ptr scene) @@ -230,6 +246,7 @@ void UBSceneCache::SceneCacheEntry::startLoading() { mTimer->stop(); delete mTimer; + mTimer = nullptr; return; } @@ -244,6 +261,7 @@ void UBSceneCache::SceneCacheEntry::startLoading() mTimer->stop(); delete mTimer; mTimer = nullptr; + mScene->loadingCompleted(shared_from_this()); } } }); @@ -274,6 +292,7 @@ std::shared_ptr UBSceneCache::SceneCacheEntry::scene() } mScene = mContext->scene(); + mScene->loadingCompleted(shared_from_this()); mContext = nullptr; } diff --git a/src/core/UBSceneCache.h b/src/core/UBSceneCache.h index 9a409aa92..9e4342a1c 100644 --- a/src/core/UBSceneCache.h +++ b/src/core/UBSceneCache.h @@ -82,7 +82,7 @@ class UBSceneCache std::shared_ptr createScene(std::shared_ptr proxy, int pageId, bool useUndoRedoStack); - std::shared_ptr prepareLoading(std::shared_ptr proxy, int pageId); + std::shared_ptr prepareLoading(std::shared_ptr proxy, int pageId, std::optional xmlContent = {}, bool cached = true); void insert (std::shared_ptr proxy, int pageId, std::shared_ptr scene); @@ -94,12 +94,14 @@ class UBSceneCache void removeAllScenes(std::shared_ptr proxy); + void removeSceneFromCache(std::shared_ptr scene); + private: - class SceneCacheEntry + class SceneCacheEntry : public std::enable_shared_from_this { public: - SceneCacheEntry(std::shared_ptr proxy, int pageId); + SceneCacheEntry(std::shared_ptr proxy, int pageId, std::optional xmlContent = {}); SceneCacheEntry(std::shared_ptr scene); ~SceneCacheEntry(); void startLoading(); diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index b19668089..7dfdc4fbe 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -29,6 +29,7 @@ #include "document/UBDocumentController.h" #include "document/UBToc.h" #include "domain/UBMediaAssetItem.h" +#include "frameworks/UBBackgroundLoader.h" #include "gui/UBMainWindow.h" #include "gui/UBThumbnailScene.h" @@ -38,16 +39,32 @@ QList> UBDocument::sDocuments; UBDocument::UBDocument(std::shared_ptr proxy) : mProxy(proxy) { - toc(); } UBDocument::~UBDocument() { + if (mSceneAssetLoader) + { + mSceneAssetLoader->abort(); + delete mSceneAssetLoader; + } + if (QFile::exists(mProxy->persistencePath())) { + if (mSceneHeaderLoader) + { + mSceneHeaderLoader->waitForFinished(); + delete mSceneHeaderLoader; + } + mToc->save(); deleteUnreferencedAssets(); } + else if (mSceneHeaderLoader) + { + mSceneHeaderLoader->abort(); + delete mSceneHeaderLoader; + } } std::shared_ptr UBDocument::proxy() const @@ -114,6 +131,7 @@ void UBDocument::deletePages(QList indexes) } UBPersistenceManager::persistenceManager()->deleteDocumentScenes(mProxy, pageIds); + assureLoaderFinished(); for (int i = indexes.size() - 1; i >= 0; --i) { @@ -142,6 +160,7 @@ void UBDocument::movePage(int fromIndex, int toIndex) persistPage(scene, fromIndex); } + assureLoaderFinished(); thumbnailScene()->moveThumbnail(fromIndex, toIndex); mToc->move(fromIndex, toIndex); mToc->save(); @@ -156,6 +175,7 @@ void UBDocument::copyPage(int fromIndex, std::shared_ptr to, int toI std::shared_ptr UBDocument::createPage(int index, bool useUndoRedoStack) { // create a new TOC entry for the page + assureLoaderFinished(); auto pageId = mToc->insert(index); auto scene = UBPersistenceManager::persistenceManager()->createDocumentSceneAt(mProxy, pageId, useUndoRedoStack); mToc->setUuid(index, scene->uuid()); @@ -207,21 +227,28 @@ std::shared_ptr UBDocument::loadScene(int index, bool cacheNeig } } - return UBPersistenceManager::persistenceManager()->loadDocumentScene(mProxy, toc()->pageId(index)); + return UBPersistenceManager::persistenceManager()->loadDocumentScene(mProxy, mToc->pageId(index)); } std::shared_ptr UBDocument::getScene(int index) { - return UBPersistenceManager::persistenceManager()->getDocumentScene(mProxy, toc()->pageId(index)); + return UBPersistenceManager::persistenceManager()->getDocumentScene(mProxy, mToc->pageId(index)); } QList UBDocument::pageRelativeDependencies(int index) { + if (mToc->hasAssets(index)) + { + return mToc->assets(index); + } + auto scene = loadScene(index, false); if (scene) { - return scene->relativeDependencies(); + const auto dependencies = scene->relativeDependencies(); + mToc->setAssets(index, dependencies); + return dependencies; } return {}; @@ -243,11 +270,13 @@ UBToc* UBDocument::toc() if (!mToc) { mToc = new UBToc{mProxy->persistencePath()}; + const auto tocPresent = mToc->load(); - if (!mToc->load() || - QVersionNumber::fromString(mProxy->metaData(UBSettings::documentVersion).toString()) < QVersionNumber::fromString(UBSettings::currentFileVersion)) + if (!tocPresent || + QVersionNumber::fromString(mProxy->metaData(UBSettings::documentVersion).toString()) < + QVersionNumber::fromString(UBSettings::currentFileVersion)) { - scan(); + scan(tocPresent); mToc->save(); } } @@ -257,7 +286,7 @@ UBToc* UBDocument::toc() int UBDocument::pageCount() { - return toc()->pageCount(); + return mToc->pageCount(); } QString UBDocument::sceneFile(int index) @@ -284,6 +313,125 @@ QString UBDocument::thumbnailFile(int index) return mProxy->persistencePath() + filename; } +void UBDocument::sceneLoaded(UBGraphicsScene* scene, std::shared_ptr handle) +{ + mLoaderHandles.remove(handle); + + const auto persistenceManager = UBPersistenceManager::persistenceManager(); + auto index = mToc->findUuid(scene->uuid()); + + if (index >= 0 && !mToc->hasAssets(index)) + { + const auto mediaAssetItems = scene->mediaAssetItems(); + + for (auto item : mediaAssetItems) + { + // Check the media asset UUIDs. + // Convert it to a SHA-1 based UUIDv5 if needed. Copy the asset file in this case. + QUuid assetUuid = item->mediaAssetUuid(); + + if (assetUuid.version() != QUuid::Sha1) + { + // lookup UUIDv5 in cache or create from content + const auto source = item->mediaAssets().at(0); + const auto sourcePath = mProxy->persistencePath() + "/" + source; + + QUuid assetUuidV5; + bool needsCopy = false; + + if (mUuidV5Map.contains(assetUuid)) + { + assetUuidV5 = mUuidV5Map.value(assetUuid); + } + else + { + assetUuidV5 = UBMediaAssetItem::createMediaAssetUuid(sourcePath); + mUuidV5Map[assetUuid] = assetUuidV5; + needsCopy = true; + } + + auto target = source; + target.replace(assetUuid.toString(QUuid::WithoutBraces), assetUuidV5.toString(QUuid::WithoutBraces)); + + // copy assets + if (needsCopy) + { + persistenceManager->copyAsset(mProxy, source, target); + } + + item->setMediaAsset(mProxy->persistencePath(), target); + scene->setModified(true); + } + } + + mToc->setAssets(index, scene->relativeDependencies()); + } + + if (scene->isModified()) + { + persistenceManager->persistDocumentScene(mProxy, scene->shared_from_this(), mToc->pageId(index)); + } + + // prepare next scene + if (mSceneAssetLoader) + { + mSceneAssetLoader->resultProcessed(index); + } +} + +void UBDocument::scanAssets() +{ + assureLoaderFinished(); + + // create a list of page IDs and paths of pages without asset info for background loading + QList> paths; + const auto persistenceManager = UBPersistenceManager::persistenceManager(); + + for (int index = 0; index < mToc->pageCount(); ++index) + { + if (!mToc->hasAssets(index)) + { + int pageId = mToc->pageId(index); + paths.append({index, mProxy->persistencePath() + persistenceManager->sceneFilenameForId(pageId)}); + } + } + + if (!paths.empty()) + { + qDebug() << "Scan" << paths.count() << "scenes for assets"; + // load scenes for scanning + mSceneAssetLoader = new UBBackgroundLoader; + + QObject::connect(mSceneAssetLoader, &UBBackgroundLoader::resultAvailable, mSceneAssetLoader, [this](int index, const QByteArray& data){ + UBApplication::showMessage(UBDocumentController::tr("Scanning page %1 of %2").arg(index).arg(mToc->pageCount()), true); + + const auto pageId = mToc->pageId(index); + + if (pageId >= 0 && !data.isEmpty()) + { + const auto handle = UBPersistenceManager::persistenceManager()->prepareSceneLoading(mProxy, pageId, data, false); + + if (handle) + { + // loading started, keep handle until finished + mLoaderHandles << handle; + return; + } + } + + // page deleted or already in cache, loading not necessary + mSceneAssetLoader->resultProcessed(index); + }); + + QObject::connect(mSceneAssetLoader, &UBBackgroundLoader::finished, mSceneAssetLoader, [this](){ + UBApplication::showMessage(UBDocumentController::tr("Scan completed")); + qDebug() << "Asset scan completed"; + }); + + mSceneAssetLoader->load(paths); + } +} + /** * @brief Get document for proxy. * @@ -311,25 +459,18 @@ std::shared_ptr UBDocument::getDocument(std::shared_ptr(new UBDocument(proxy)); + document->toc(); // load and initialize TOC sDocuments << document; } return document; } -void UBDocument::scan() +void UBDocument::scan(bool tocPresent) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - // Create a set of all scene UUIDs - QSet tocSceneUuids; - - for (int i = 0; i < pageCount(); ++i) - { - tocSceneUuids.insert(mToc->uuid(i)); - } - - // Scan through the pages starting from the smallest number and counting up. + // scan through the pages starting from the smallest number and counting up. QStringList pages = UBPersistenceManager::persistenceManager()->pageFiles(mProxy->persistencePath()); if (pages.isEmpty()) @@ -338,81 +479,111 @@ void UBDocument::scan() mProxy->setMetaData(UBSettings::documentName, UBPersistenceManager::tr("Broken - %1").arg(mProxy->documentFolderName())); } - // Load the scenes and check the media assets. - int pageProcessed = -1; - int currentPage = 0; + // create a list of page IDs and paths for background loading + QList> paths; for (const auto page : pages) { - UBApplication::showMessage(UBDocumentController::tr("Scanning page %1 of %2").arg(++currentPage).arg(pages.count()), true); int pageId = page.mid(4, page.length() - 8).toInt(); - auto scene = UBPersistenceManager::persistenceManager()->loadDocumentScene(mProxy, pageId); + paths.append({pageId, mProxy->persistencePath() + "/" + page}); + } - const auto mediaAssetItems = scene->mediaAssetItems(); + if (tocPresent) + { + // we have a TOC, but the document was last modified by an earlier version of OpenBoard + // necessary to verify all scene UUIDs and update TOC accordingly - for (auto item : mediaAssetItems) + // create a set of all scene UUIDs in the TOC + QSet tocSceneUuids; + + for (int i = 0; i < pageCount(); ++i) { - // Check the media asset UUIDs. - // Convert it to a SHA-1 based UUIDv5 if needed. Copy the asset file in this case. - QUuid assetUuid = item->mediaAssetUuid(); + tocSceneUuids.insert(mToc->uuid(i)); + } - if (assetUuid.version() != QUuid::Sha1) - { - // copy media asset using a new UuidV5 - const auto source = item->mediaAssets().at(0); - const auto sourcePath = mProxy->persistencePath() + "/" + source; - const auto assetUuidV5 = UBMediaAssetItem::createMediaAssetUuid(sourcePath); + // load the first 300 bytes of each file in background, enough to get version and UUID + UBBackgroundLoader loader; + int pageProcessed = -1; + int currentPage = 0; + const auto currentVersion = QVersionNumber::fromString(UBSettings::currentFileVersion); - auto target = source; - target.replace(assetUuid.toString(QUuid::WithoutBraces), assetUuidV5.toString(QUuid::WithoutBraces)); + QObject::connect(&loader, &UBBackgroundLoader::resultAvailable, &loader, [&](int index, const QByteArray& data){ + UBApplication::showMessage(UBDocumentController::tr("Scanning page %1 of %2").arg(++currentPage).arg(pages.count()), true); + const auto uuid = UBSvgSubsetAdaptor::sceneUuid(data); - UBPersistenceManager::persistenceManager()->copyAsset(mProxy, source, target); - item->setMediaAsset(mProxy->persistencePath(), target); - scene->setModified(true); + // Check whether the tocSceneUuids already contains this scene. + // If yes, locate and update the TOC entry + if (tocSceneUuids.contains(uuid)) + { + const int index = mToc->findUuid(uuid); + + if (index >= 0) + { + pageProcessed = index; + tocSceneUuids.remove(uuid); + + // invalidate assets if scene was modified by an earlier version + if (UBSvgSubsetAdaptor::sceneVersion(data) < currentVersion) + { + mToc->unsetAssets(index); + } + } + } + else + { + // add the file name and thumbnail file name to the TOC after the last processed TOC entry + qDebug() << "scan: insert scene" << index << "at offset" << pageProcessed; + ++pageProcessed; + mToc->insert(pageProcessed); + mToc->setUuid(pageProcessed, uuid); + mToc->setPageId(pageProcessed, index); } - } - // Check whether the tocSceneUuids already contains this scene. - // If yes, locate and update the TOC entry - if (tocSceneUuids.contains(scene->uuid())) - { - const int index = mToc->findUuid(scene->uuid()); + loader.resultProcessed(index); + }); - if (index >= 0) + QObject::connect(&loader, &UBBackgroundLoader::finished, &loader, [&](){ + // When finished, remove all scenes still in tocSceneUuids from the TOC. + // Those scenes might have been deleted using a previous version of OpenBoard. + for (const auto uuid : tocSceneUuids) { - mToc->setAssets(index, scene->relativeDependencies()); - pageProcessed = index; - tocSceneUuids.remove(scene->uuid()); + qDebug() << "scan: removing scene from TOC" << uuid; + mToc->remove(mToc->findUuid(uuid)); } - } - else - { - // add the file name, thumbnail file name and asset list to the TOC after the last processed TOC entry - qDebug() << "scan: insert scene" << pageId << "at offset" << pageProcessed; - ++pageProcessed; - mToc->insert(pageProcessed); - mToc->setUuid(pageProcessed, scene->uuid()); - mToc->setPageId(pageProcessed, pageId); - mToc->setAssets(pageProcessed, scene->relativeDependencies()); - } - if (scene->isModified()) - { - persistPage(scene, pageProcessed); - } - } + UBApplication::showMessage(UBDocumentController::tr("Scan completed")); + mToc->save(); + }); - // When finished, remove all scenes still in tocSceneUuids from the TOC. - // Those scenes might have been deleted using a previous version of OpenBoard. - for (const auto uuid : tocSceneUuids) - { - qDebug() << "scan: removing scene from TOC" << uuid; - mToc->remove(mToc->findUuid(uuid)); + loader.load(paths, 300); + loader.waitForFinished(); } + else if (!paths.empty()) + { + // start reading the UUIDs in background, but make sure it is completed when the UBDocument is deleted + mSceneHeaderLoader = new UBBackgroundLoader; + mSceneHeaderLoader->setKeepAlive(shared_from_this()); + + QObject::connect(mSceneHeaderLoader, &UBBackgroundLoader::resultAvailable, mSceneHeaderLoader, [this](int index, const QByteArray& data){ + const auto uuid = UBSvgSubsetAdaptor::sceneUuid(data); + mToc->setUuid(index, uuid); + mSceneHeaderLoader->resultProcessed(index); + }); + + QObject::connect(mSceneHeaderLoader, &UBBackgroundLoader::finished, mSceneHeaderLoader, [this](){ + mSceneHeaderLoader->deleteLater(); + mSceneHeaderLoader = nullptr; + mToc->save(); + }); - // Delete all unreferenced media asset files. - UBApplication::showMessage(UBDocumentController::tr("Remove unused assets").arg(++currentPage).arg(pages.count()), true); - deleteUnreferencedAssets(); + mSceneHeaderLoader->load(paths, 300); + + // set the page ID for the pages + for (int index = 0; index < pages.count(); ++index) + { + mToc->setPageId(index, paths.at(index).first); + } + } // now we have updated the document version mProxy->setMetaData(UBSettings::documentVersion, UBSettings::currentFileVersion); @@ -428,6 +599,7 @@ void UBDocument::copyPage(int fromIndex, UBDocument* to, int toIndex) const auto dependencies = pageRelativeDependencies(fromIndex); // copy scene + to->assureLoaderFinished(); const auto pageId = to->mToc->insert(toIndex); const auto uuid = UBPersistenceManager::persistenceManager()->copyDocumentScene(mProxy, mToc->pageId(fromIndex), to->proxy(), pageId, dependencies); @@ -447,6 +619,12 @@ void UBDocument::deleteUnreferencedAssets() for (int index = 0; index < mToc->pageCount(); ++index) { + if (!mToc->hasAssets(index)) + { + // no cleanup with incomplete asset information + return; + } + const auto assets = mToc->assets(index); for (const auto asset : assets) @@ -459,6 +637,18 @@ void UBDocument::deleteUnreferencedAssets() UBPersistenceManager::persistenceManager()->cleanupMediaAssets(mProxy, referencedMediaAssets); } +void UBDocument::assureLoaderFinished() +{ + if (mSceneHeaderLoader) + { + UBApplication::setOverrideCursor(Qt::WaitCursor); + UBApplication::showMessage(UBDocumentController::tr("Wait for the document scan to finish"), true); + mSceneHeaderLoader->waitForFinished(); + UBApplication::showMessage(UBDocumentController::tr("Document scan finished")); + UBApplication::restoreOverrideCursor(); + } +} + std::shared_ptr UBDocument::findDocument(std::shared_ptr proxy) { if (!proxy) diff --git a/src/document/UBDocument.h b/src/document/UBDocument.h index a26ec5229..c24df86ba 100644 --- a/src/document/UBDocument.h +++ b/src/document/UBDocument.h @@ -22,12 +22,16 @@ #pragma once +#include #include +#include +#include #include // forward +class UBBackgroundLoader; class UBDocumentProxy; class UBGraphicsScene; class UBThumbnailScene; @@ -45,7 +49,7 @@ class UBToc; * getDocument() function. They are always referenced by a shared pointer and live as long * as anybody wants to work with the doument. */ -class UBDocument +class UBDocument : public std::enable_shared_from_this { private: UBDocument(std::shared_ptr proxy); @@ -73,12 +77,16 @@ class UBDocument QString sceneFile(int index); QString thumbnailFile(int index); + void sceneLoaded(UBGraphicsScene* scene, std::shared_ptr handle); + void scanAssets(); + static std::shared_ptr getDocument(std::shared_ptr proxy); private: - void scan(); + void scan(bool tocPresent); void copyPage(int fromIndex, UBDocument* to, int toIndex); void deleteUnreferencedAssets(); + void assureLoaderFinished(); static std::shared_ptr findDocument(std::shared_ptr proxy); @@ -86,6 +94,10 @@ class UBDocument std::shared_ptr mProxy{nullptr}; std::unique_ptr mThumbnailScene; UBToc* mToc{nullptr}; + UBBackgroundLoader* mSceneHeaderLoader{nullptr}; + UBBackgroundLoader* mSceneAssetLoader{nullptr}; + QHash mUuidV5Map{}; + QSet> mLoaderHandles; static QList> sDocuments; }; diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index 969954ca3..ec4ba3f19 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -3399,6 +3399,7 @@ bool UBDocumentController::isOKToOpenDocument(std::shared_ptr p || docVersion.startsWith("4.3") || docVersion.startsWith("4.4") || docVersion.startsWith("4.5") || docVersion.startsWith("4.6") || docVersion.startsWith("4.8") || docVersion.startsWith("4.9")) { + UBDocument::getDocument(proxy)->scanAssets(); // Invoke widget upgrader widgetUpgradeAdaptor.upgradeWidgets(proxy); return true; diff --git a/src/document/UBToc.cpp b/src/document/UBToc.cpp index 90e017771..a9a49a0f0 100644 --- a/src/document/UBToc.cpp +++ b/src/document/UBToc.cpp @@ -58,6 +58,7 @@ int UBToc::insert(int index) { int pageId = nextAvailablePageId(); mToc.insert(index, {{PAGE_ID, pageId}}); + mModified = true; return pageId; } @@ -74,6 +75,7 @@ void UBToc::move(int fromIndex, int toIndex) auto entry = mToc.at(fromIndex); mToc.removeAt(fromIndex); mToc.insert(toIndex, entry); + mModified = true; } void UBToc::remove(int index) @@ -81,6 +83,7 @@ void UBToc::remove(int index) if (index >= 0 && index < mToc.count()) { mToc.remove(index); + mModified = true; } } @@ -103,9 +106,10 @@ void UBToc::setUuid(int index, const QUuid& uuid) assureSize(index); mToc[index][UUID] = uuid; + mModified = true; } -int UBToc::findUuid(const QUuid& sceneUuid) +int UBToc::findUuid(const QUuid& sceneUuid) const { for (int i = 0; i < mToc.size(); ++i) { @@ -137,6 +141,7 @@ void UBToc::setPageId(int index, int pageId) assureSize(index); mToc[index][PAGE_ID] = pageId; + mModified = true; } QStringList UBToc::assets(int index) const @@ -158,6 +163,22 @@ void UBToc::setAssets(int index, const QStringList& assets) assureSize(index); mToc[index][ASSETS] = assets; + mModified = true; +} + +void UBToc::unsetAssets(int index) +{ + mToc[index].remove(ASSETS); +} + +bool UBToc::hasAssets(int index) const +{ + if (index < 0 || index >= mToc.count()) + { + return false; + } + + return mToc.at(index).contains(ASSETS); } bool UBToc::load() @@ -170,13 +191,18 @@ bool UBToc::load() mNextAvailablePageId = std::max(mNextAvailablePageId, entry[PAGE_ID].toInt() + 1); } + mModified = false; return ok; } -void UBToc::save() const +void UBToc::save() { - UBTocJsonSerializer serializer(mDocumentPath); - serializer.save(mVersion, mToc); + if (mModified) + { + UBTocJsonSerializer serializer(mDocumentPath); + serializer.save(mVersion, mToc); + mModified = false; + } } int UBToc::nextAvailablePageId() diff --git a/src/document/UBToc.h b/src/document/UBToc.h index ba23544b7..b1dd43d26 100644 --- a/src/document/UBToc.h +++ b/src/document/UBToc.h @@ -49,17 +49,19 @@ class UBToc // access values QUuid uuid(int index) const; void setUuid(int index, const QUuid& uuid); - int findUuid(const QUuid& sceneUuid); + int findUuid(const QUuid& sceneUuid) const; int pageId(int index) const; void setPageId(int index, int pageId); QStringList assets(int index) const; void setAssets(int index, const QStringList& assets); + void unsetAssets(int index); + bool hasAssets(int index) const; // load and save bool load(); - void save() const; + void save(); // next available pageId int nextAvailablePageId(); @@ -72,4 +74,5 @@ class UBToc QVersionNumber mVersion{TOC_VERSION}; QVector mToc; int mNextAvailablePageId{0}; + bool mModified{false}; }; diff --git a/src/domain/UBGraphicsScene.cpp b/src/domain/UBGraphicsScene.cpp index 559bc2d8b..010d2c741 100644 --- a/src/domain/UBGraphicsScene.cpp +++ b/src/domain/UBGraphicsScene.cpp @@ -54,6 +54,7 @@ #include "tools/UBGraphicsCurtainItem.h" #include "tools/UBGraphicsCache.h" +#include "document/UBDocument.h" #include "document/UBDocumentProxy.h" #include "board/UBBoardController.h" @@ -2450,6 +2451,11 @@ void UBGraphicsScene::controlViewportChanged() } } +void UBGraphicsScene::loadingCompleted(std::shared_ptr handle) +{ + UBDocument::getDocument(mDocument)->sceneLoaded(this, handle); +} + void UBGraphicsScene::addCompass(QPointF center) { UBGraphicsCompass* compass = new UBGraphicsCompass(); // mem : owned and destroyed by the scene diff --git a/src/domain/UBGraphicsScene.h b/src/domain/UBGraphicsScene.h index bdf41d3fe..68d086a0e 100644 --- a/src/domain/UBGraphicsScene.h +++ b/src/domain/UBGraphicsScene.h @@ -379,6 +379,7 @@ public slots: void stylusToolChanged(int tool, int previousTool); void controlViewportChanged(); + void loadingCompleted(std::shared_ptr handle); signals: void zoomChanged(qreal zoomFactor); diff --git a/src/frameworks/CMakeLists.txt b/src/frameworks/CMakeLists.txt index faa702e72..368ef3b34 100644 --- a/src/frameworks/CMakeLists.txt +++ b/src/frameworks/CMakeLists.txt @@ -3,6 +3,8 @@ target_sources(openboard PRIVATE UBBackgroundLoader.h UBBase32.cpp UBBase32.h + UBBlockingBuffer.cpp + UBBlockingBuffer.h UBCoreGraphicsScene.cpp UBCoreGraphicsScene.h UBCryptoUtils.cpp diff --git a/src/frameworks/UBBackgroundLoader.cpp b/src/frameworks/UBBackgroundLoader.cpp index 8af981330..8a1696f96 100644 --- a/src/frameworks/UBBackgroundLoader.cpp +++ b/src/frameworks/UBBackgroundLoader.cpp @@ -23,44 +23,78 @@ #include "UBBackgroundLoader.h" #include +#include #include +#include "frameworks/UBBlockingBuffer.h" -UBBackgroundLoader::UBBackgroundLoader(const QList>& paths, int maxBytes, QObject* parent) +UBBackgroundLoader::UBBackgroundLoader(QObject* parent) : QObject{parent} - , mCount{paths.count()} { - mFuture = QtConcurrent::mapped(paths, ReadData{maxBytes}); -} + mWatcher = new QFutureWatcher>; + mWatcher->setPendingResultsLimit(2); + mWatcherThread = new QThread{this}; + mWatcher->moveToThread(mWatcherThread); -UBBackgroundLoader::UBBackgroundLoader(const QList>& paths, QObject* parent) - : UBBackgroundLoader{paths, -1, parent} -{ + mBlockingBuffer = new UBBlockingBuffer{this}; + mBlockingBuffer->setWatcher(mWatcher); + + connect(mBlockingBuffer, &UBBlockingBuffer::resultAvailable, this, &UBBackgroundLoader::resultAvailable); + connect(mBlockingBuffer, &UBBlockingBuffer::finished, this, &UBBackgroundLoader::finished); + + connect(mWatcher, &QFutureWatcher>::finished, mWatcherThread, &QThread::quit); + + mBlockingBuffer->start(); + mWatcherThread->start(); } UBBackgroundLoader::~UBBackgroundLoader() { + qDebug() << "Destruct UBBackgroundLoader"; + mWatcher->cancel(); + mWatcherThread->quit(); + mBlockingBuffer->halt(); + mWatcherThread->wait(); + mBlockingBuffer->wait(); abort(); + + delete mWatcher; } -bool UBBackgroundLoader::isIdle() +void UBBackgroundLoader::load(const QList>& paths, int maxBytes) { - return mFuture.isFinished() && mIndex == mFuture.resultCount(); +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + mFuture = QtConcurrent::mapped(paths, ReadData{maxBytes}); +#else + // use a separate thread pool for each loader so that tasks are interwoven between loaders + auto threadPool = new QThreadPool{this}; + threadPool->setMaxThreadCount(4); + mFuture = QtConcurrent::mapped(threadPool, paths, ReadData{maxBytes}); +#endif + + mWatcher->setFuture(mFuture); + + qDebug() << "UBBackgroundLoader: Start loading" << paths.at(0).second; } -bool UBBackgroundLoader::isResultAvailable() +void UBBackgroundLoader::abort() { - return mFuture.isResultReadyAt(mIndex); + mFuture.cancel(); } -std::pair UBBackgroundLoader::takeResult() +void UBBackgroundLoader::waitForFinished() { - return mFuture.resultAt(mIndex++); + mFuture.waitForFinished(); } -void UBBackgroundLoader::abort() +void UBBackgroundLoader::setKeepAlive(std::shared_ptr keepAlive) { - mFuture.cancel(); + mKeepAlive = keepAlive; +} + +void UBBackgroundLoader::resultProcessed(int index) +{ + mBlockingBuffer->resultProcessed(index); } UBBackgroundLoader::ReadData::ReadData(int maxBytes) diff --git a/src/frameworks/UBBackgroundLoader.h b/src/frameworks/UBBackgroundLoader.h index 0795ad820..07b7df891 100644 --- a/src/frameworks/UBBackgroundLoader.h +++ b/src/frameworks/UBBackgroundLoader.h @@ -25,24 +25,34 @@ #include #include +// forward +class UBBlockingBuffer; + class UBBackgroundLoader : public QObject { Q_OBJECT public: - UBBackgroundLoader(const QList>& paths, int maxBytes, QObject* parent = nullptr); - UBBackgroundLoader(const QList>& paths, QObject* parent = nullptr); + UBBackgroundLoader(QObject* parent = nullptr); virtual ~UBBackgroundLoader(); - bool isIdle(); - bool isResultAvailable(); - std::pair takeResult(); + void load(const QList>& paths, int maxBytes = -1); void abort(); + void waitForFinished(); + void setKeepAlive(std::shared_ptr keepAlive); + +public slots: + void resultProcessed(int index); + +signals: + void resultAvailable(int index, const QByteArray& data); + void finished(); private: - struct ReadData + class ReadData { + public: typedef std::pair result_type; ReadData(int maxBytes); @@ -54,6 +64,9 @@ class UBBackgroundLoader : public QObject private: QFuture> mFuture; - const qsizetype mCount{0}; int mIndex{0}; + QFutureWatcher>* mWatcher{nullptr}; + std::shared_ptr mKeepAlive; + UBBlockingBuffer* mBlockingBuffer{nullptr}; + QThread* mWatcherThread{nullptr}; }; diff --git a/src/frameworks/UBBlockingBuffer.cpp b/src/frameworks/UBBlockingBuffer.cpp new file mode 100644 index 000000000..bd7dbfcc9 --- /dev/null +++ b/src/frameworks/UBBlockingBuffer.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + +#include "UBBlockingBuffer.h" + +UBBlockingBuffer::UBBlockingBuffer(QObject* parent) + : QThread{parent} +{ +} + +void UBBlockingBuffer::setWatcher(QFutureWatcher>* watcher) +{ + mWatcher = watcher; + + connect(mWatcher, &QFutureWatcher>::resultReadyAt, this, &UBBlockingBuffer::addResult, + Qt::DirectConnection); + connect(mWatcher, &QFutureWatcher>::finished, this, &UBBlockingBuffer::watcherFinished, + Qt::DirectConnection); +} + +void UBBlockingBuffer::addResult(int index) +{ + if (!isInterruptionRequested()) + { + mAvailableSpace.acquire(); + + if (mWatcher) + { + const auto result = mWatcher->resultAt(index); + + QMutexLocker lock{&mMutex}; + mBuffer.emplace_back(result.first, result.second); + mAvailableResults.release(); + } + } +} + +void UBBlockingBuffer::resultProcessed(int index) +{ + mAvailableSpace.release(); +} + +void UBBlockingBuffer::watcherFinished() +{ + if (!isInterruptionRequested()) + { + // add a "finished" marker to the buffer + mAvailableSpace.acquire(); + QMutexLocker lock{&mMutex}; + mBuffer.emplace_back(-1, QByteArray{}); + mAvailableResults.release(); + } +} + +void UBBlockingBuffer::halt() +{ + requestInterruption(); + + mAvailableResults.release(); + mAvailableSpace.release(999); // last results and finish marker + mWatcher = nullptr; +} + +void UBBlockingBuffer::run() +{ + while (true) + { + mAvailableResults.acquire(); + QMutexLocker lock{&mMutex}; + + if (isInterruptionRequested()) + { + return; + } + + const auto result = mBuffer.front(); + mBuffer.pop_front(); + + if (result.first >= 0) + { + emit resultAvailable(result.first, result.second); + } + else + { + emit finished(); + } + } +} diff --git a/src/frameworks/UBBlockingBuffer.h b/src/frameworks/UBBlockingBuffer.h new file mode 100644 index 000000000..87c0d8abf --- /dev/null +++ b/src/frameworks/UBBlockingBuffer.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + +#pragma once + +#include +#include +#include + +#include + +class UBBlockingBuffer : public QThread +{ + Q_OBJECT + +public: + UBBlockingBuffer(QObject* parent = nullptr); + void setWatcher(QFutureWatcher>* watcher); + +public slots: + void addResult(int index); + void resultProcessed(int index); + void watcherFinished(); + void halt(); + +signals: + void resultAvailable(int index, const QByteArray& data); + void finished(); + +protected: + void run() override; + +private: + QFutureWatcher>* mWatcher; + QSemaphore mAvailableResults; + QSemaphore mAvailableSpace{1}; + QMutex mMutex; + std::deque> mBuffer; +}; diff --git a/src/frameworks/frameworks.pri b/src/frameworks/frameworks.pri index 728b8f8df..165ed1a5a 100644 --- a/src/frameworks/frameworks.pri +++ b/src/frameworks/frameworks.pri @@ -7,6 +7,7 @@ HEADERS += src/frameworks/UBGeometryUtils.h \ src/frameworks/UBCoreGraphicsScene.h \ src/frameworks/UBCryptoUtils.h \ src/frameworks/UBBackgroundLoader.h \ + src/frameworks/UBBlockingBuffer.h \ src/frameworks/UBBase32.h SOURCES += src/frameworks/UBGeometryUtils.cpp \ @@ -17,6 +18,7 @@ SOURCES += src/frameworks/UBGeometryUtils.cpp \ src/frameworks/UBCoreGraphicsScene.cpp \ src/frameworks/UBCryptoUtils.cpp \ src/frameworks/UBBackgroundLoader.cpp \ + src/frameworks/UBBlockingBuffer.cpp \ src/frameworks/UBBase32.cpp diff --git a/src/gui/UBThumbnailScene.cpp b/src/gui/UBThumbnailScene.cpp index fc5e0bf4f..04c9581a6 100644 --- a/src/gui/UBThumbnailScene.cpp +++ b/src/gui/UBThumbnailScene.cpp @@ -228,10 +228,24 @@ void UBThumbnailScene::createThumbnails(int startIndex) return; } - mLoader = new UBBackgroundLoader{paths, this}; + mLoader = new UBBackgroundLoader{this}; - // now create all missing thumbnails for document as they arrive from the loader - loadNextThumbnail(); + connect(mLoader, &UBBackgroundLoader::resultAvailable, this, [this](int index, const QByteArray& data){ + // now create all missing thumbnails for document as they arrive from the loader + loadThumbnail(index, data); + + if (mLoader) + { + mLoader->resultProcessed(index); + } + }); + connect(mLoader, &UBBackgroundLoader::finished, this, [this](){ + // delete loader + mLoader->deleteLater(); + mLoader = nullptr; + }); + + mLoader->load(paths); } /** @@ -274,7 +288,7 @@ void UBThumbnailScene::insertThumbnail(int pageIndex, std::shared_ptrisIdle()) + if (!thumbnailItem) { - if (UBApplication::isClosing) - { - return; - } + QPixmap pixmap; - if (!mLoader->isResultAvailable()) + if (data.isEmpty()) { - // no data available, defer next execution - QTimer::singleShot(50, mLoader, [this]() { loadNextThumbnail(); }); - return; + pixmap = UBThumbnailAdaptor::generateMissingThumbnail(mDocument, index); } - - int firstIndex = -1; - - for (int i = 0; i < bulkSize; ++i) + else { - if (!mLoader->isResultAvailable()) - { - break; - } - - // take and process next result - const auto result = mLoader->takeResult(); - const auto index = result.first; - auto thumbnailItem = mThumbnailItems.at(index); - - if (!thumbnailItem) - { - QPixmap pixmap; - - if (result.second.isEmpty()) - { - pixmap = UBThumbnailAdaptor::generateMissingThumbnail(mDocument, index); - } - else - { - pixmap.loadFromData(result.second); - } - - thumbnailItem = new UBThumbnail; - - thumbnailItem->setPixmap(pixmap); - thumbnailItem->setSceneIndex(index); - - mThumbnailItems[index] = thumbnailItem; - addItem(thumbnailItem); - - if (firstIndex < 0) - { - firstIndex = index; - } - } + pixmap.loadFromData(data); } - if (firstIndex >= 0) - { - arrangeThumbnails(firstIndex); - } + thumbnailItem = new UBThumbnail; - // load next thumbnails in a deferred task executed on the main thread when it is idle. - QTimer::singleShot(1, mLoader, [this]() { loadNextThumbnail(); }); - } - else - { - // finished. set undeletable if only one page - if (mThumbnailItems.size() == 1) - { - thumbnailAt(0)->setDeletable(false); - } + thumbnailItem->setPixmap(pixmap); + thumbnailItem->setSceneIndex(index); - // delete background loader - delete mLoader; - mLoader = nullptr; + mThumbnailItems[index] = thumbnailItem; + addItem(thumbnailItem); + + arrangeThumbnails(index, index + 1); } } diff --git a/src/gui/UBThumbnailScene.h b/src/gui/UBThumbnailScene.h index 942aeb320..c566a08de 100644 --- a/src/gui/UBThumbnailScene.h +++ b/src/gui/UBThumbnailScene.h @@ -71,7 +71,7 @@ class UBThumbnailScene : public QGraphicsScene private: friend class UBThumbnail; UBThumbnailArranger* currentThumbnailArranger(); - void loadNextThumbnail(); + void loadThumbnail(int index, const QByteArray& data); void renumberThumbnails(int fromIndex = 0, int toIndex = -1) const; private: From 16c48b7fe9427e292cfa64078025148bfbf71afb Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Fri, 6 Sep 2024 10:03:01 +0200 Subject: [PATCH 019/133] refactor: avoid QKeyCombination warnings on Qt6 - Qt6 introduced a new class QKeyCombination - in Qt5, a simple int was used - use the proper functions for each Qt version in UBShortcutManager --- src/core/UBShortcutManager.cpp | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/core/UBShortcutManager.cpp b/src/core/UBShortcutManager.cpp index dfe8c8239..29b948704 100644 --- a/src/core/UBShortcutManager.cpp +++ b/src/core/UBShortcutManager.cpp @@ -39,6 +39,21 @@ static const char* descriptionProperty("description"); static const char* mouseButtonProperty("mouseButton"); static const char* tabletButtonProperty("tabletButton"); +// helper function to flip keyboard modifier depending on Qt version +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QKeyCombination flipModifier(const QKeyCombination& keyCombination, Qt::KeyboardModifier modifier) + { + Qt::KeyboardModifiers mod = keyCombination.keyboardModifiers(); + mod.setFlag(modifier, !mod.testFlag(modifier)); + return QKeyCombination(mod, keyCombination.key()); + } +#else + int flipModifier(int keyCombination, Qt::KeyboardModifier modifier) + { + return keyCombination ^ modifier; + } +#endif + UBShortcutManager* UBShortcutManager::sShortcutManager = nullptr; UBShortcutManager::UBShortcutManager() : mIgnoreCtrl(false) @@ -608,7 +623,7 @@ bool UBShortcutManager::hasCtrlConflicts(const QKeySequence &additionalShortcut) else { shortcuts << action->shortcut(); - ctrlShortcuts << QKeySequence(action->shortcut()[0] ^ Qt::CTRL); + ctrlShortcuts << QKeySequence(flipModifier(action->shortcut()[0], Qt::ControlModifier)); } } @@ -616,7 +631,7 @@ bool UBShortcutManager::hasCtrlConflicts(const QKeySequence &additionalShortcut) if (!additionalShortcut.isEmpty()) { shortcuts << additionalShortcut; - ctrlShortcuts << QKeySequence(additionalShortcut[0] ^ Qt::CTRL); + ctrlShortcuts << QKeySequence(flipModifier(additionalShortcut[0], Qt::ControlModifier)); } return shortcuts.intersects(ctrlShortcuts); @@ -688,8 +703,14 @@ void UBShortcutManager::ignoreCtrl(bool ignore) { QList shortcuts = action->shortcuts(); - if (ignore && !shortcuts.empty() && shortcuts[0][0] & Qt::CTRL) { - QKeySequence noCtrl(shortcuts[0][0] ^ Qt::CTRL); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + bool hasCtrl = !shortcuts.empty() && shortcuts[0][0].keyboardModifiers().testFlag(Qt::ControlModifier); +#else + bool hasCtrl = !shortcuts.empty() && shortcuts[0][0] & Qt::ControlModifier; +#endif + + if (ignore && hasCtrl) { + QKeySequence noCtrl(flipModifier(shortcuts[0][0], Qt::ControlModifier)); shortcuts << noCtrl; action->setShortcuts(shortcuts); } @@ -829,7 +850,11 @@ bool UBActionGroupHistory::keyReleased(QKeyEvent *event) if (keySequence.count() > 0) { +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + int actionKey = action->shortcut()[0].key(); +#else int actionKey = action->shortcut()[0] & ~Qt::KeyboardModifierMask; +#endif if (key == actionKey) { From 9fbbc144d33728c8ab99e25ef43e94c5dc1109ae Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Wed, 13 Aug 2025 11:40:39 +0200 Subject: [PATCH 020/133] perf: improve preparation for loading thumbnails - avoid check for existence of thumbnail files in main thread - create missing thumbnails later when loading fails --- src/gui/UBThumbnailScene.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/gui/UBThumbnailScene.cpp b/src/gui/UBThumbnailScene.cpp index 04c9581a6..84f74305a 100644 --- a/src/gui/UBThumbnailScene.cpp +++ b/src/gui/UBThumbnailScene.cpp @@ -205,12 +205,6 @@ void UBThumbnailScene::createThumbnails(int startIndex) for (int index = startIndex; index < mDocument->pageCount(); ++index) { const auto thumbnailPath = UBThumbnailAdaptor::thumbnailUrl(mDocument, index).toLocalFile(); - - if (!QFile::exists(thumbnailPath)) - { - UBThumbnailAdaptor::generateMissingThumbnail(mDocument, index); - } - paths << std::pair{index, thumbnailPath}; } From f3a28a999387344ebb809d47556a8e4d150e3780 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Wed, 13 Aug 2025 17:38:01 +0200 Subject: [PATCH 021/133] fixup refactor: rename to hasAssetsEntry Signed-off-by: letsfindaway --- src/document/UBDocument.cpp | 8 ++++---- src/document/UBToc.cpp | 2 +- src/document/UBToc.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index 7dfdc4fbe..f8a5af5a9 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -237,7 +237,7 @@ std::shared_ptr UBDocument::getScene(int index) QList UBDocument::pageRelativeDependencies(int index) { - if (mToc->hasAssets(index)) + if (mToc->hasAssetsEntry(index)) { return mToc->assets(index); } @@ -320,7 +320,7 @@ void UBDocument::sceneLoaded(UBGraphicsScene* scene, std::shared_ptr handl const auto persistenceManager = UBPersistenceManager::persistenceManager(); auto index = mToc->findUuid(scene->uuid()); - if (index >= 0 && !mToc->hasAssets(index)) + if (index >= 0 && !mToc->hasAssetsEntry(index)) { const auto mediaAssetItems = scene->mediaAssetItems(); @@ -389,7 +389,7 @@ void UBDocument::scanAssets() for (int index = 0; index < mToc->pageCount(); ++index) { - if (!mToc->hasAssets(index)) + if (!mToc->hasAssetsEntry(index)) { int pageId = mToc->pageId(index); paths.append({index, mProxy->persistencePath() + persistenceManager->sceneFilenameForId(pageId)}); @@ -619,7 +619,7 @@ void UBDocument::deleteUnreferencedAssets() for (int index = 0; index < mToc->pageCount(); ++index) { - if (!mToc->hasAssets(index)) + if (!mToc->hasAssetsEntry(index)) { // no cleanup with incomplete asset information return; diff --git a/src/document/UBToc.cpp b/src/document/UBToc.cpp index a9a49a0f0..77cd6e921 100644 --- a/src/document/UBToc.cpp +++ b/src/document/UBToc.cpp @@ -171,7 +171,7 @@ void UBToc::unsetAssets(int index) mToc[index].remove(ASSETS); } -bool UBToc::hasAssets(int index) const +bool UBToc::hasAssetsEntry(int index) const { if (index < 0 || index >= mToc.count()) { diff --git a/src/document/UBToc.h b/src/document/UBToc.h index b1dd43d26..bb138d6fa 100644 --- a/src/document/UBToc.h +++ b/src/document/UBToc.h @@ -57,7 +57,7 @@ class UBToc QStringList assets(int index) const; void setAssets(int index, const QStringList& assets); void unsetAssets(int index); - bool hasAssets(int index) const; + bool hasAssetsEntry(int index) const; // load and save bool load(); From d6de1965984ecd8614d1326ea7570018e2120eef Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 17 Aug 2025 15:49:15 +0200 Subject: [PATCH 022/133] refactor: reame UBToc to UBDocumentToc - express that this is a table of contents for a document --- src/adaptors/UBExportDocument.cpp | 4 +- src/adaptors/UBExportDocumentSetAdaptor.cpp | 4 +- src/adaptors/UBPageMapper.cpp | 6 +-- src/adaptors/UBPageMapper.h | 8 ++-- src/core/UBPersistenceManager.cpp | 4 +- src/document/CMakeLists.txt | 4 +- src/document/UBDocument.cpp | 6 +-- src/document/UBDocument.h | 6 +-- src/document/{UBToc.cpp => UBDocumentToc.cpp} | 42 +++++++++---------- src/document/{UBToc.h => UBDocumentToc.h} | 10 ++--- src/document/document.pri | 4 +- 11 files changed, 49 insertions(+), 49 deletions(-) rename src/document/{UBToc.cpp => UBDocumentToc.cpp} (77%) rename src/document/{UBToc.h => UBDocumentToc.h} (88%) diff --git a/src/adaptors/UBExportDocument.cpp b/src/adaptors/UBExportDocument.cpp index 0569f2f97..2c35b7566 100644 --- a/src/adaptors/UBExportDocument.cpp +++ b/src/adaptors/UBExportDocument.cpp @@ -39,7 +39,7 @@ #include "document/UBDocumentProxy.h" #include "document/UBDocumentController.h" -#include "document/UBToc.h" +#include "document/UBDocumentToc.h" #ifdef Q_OS_OSX #include @@ -81,7 +81,7 @@ bool UBExportDocument::persistsDocument(std::shared_ptr pDocume QDir documentDir = QDir(pDocumentProxy->persistencePath()); // try to load a TOC for mapping and check version number - UBToc toc{pDocumentProxy->persistencePath()}; + UBDocumentToc toc{pDocumentProxy->persistencePath()}; std::unique_ptr mapper{nullptr}; const auto version = QVersionNumber::fromString(pDocumentProxy->metaData(UBSettings::documentVersion).toString()); diff --git a/src/adaptors/UBExportDocumentSetAdaptor.cpp b/src/adaptors/UBExportDocumentSetAdaptor.cpp index 0f0fa2f71..70c49d38f 100644 --- a/src/adaptors/UBExportDocumentSetAdaptor.cpp +++ b/src/adaptors/UBExportDocumentSetAdaptor.cpp @@ -37,7 +37,7 @@ #include "document/UBDocumentProxy.h" #include "document/UBDocumentController.h" -#include "document/UBToc.h" +#include "document/UBDocumentToc.h" #include "core/UBPersistenceManager.h" @@ -171,7 +171,7 @@ bool UBExportDocumentSetAdaptor::addDocumentToZip(const QModelIndex &pIndex, UBD QDir documentDir = QDir(pDocumentProxy->persistencePath()); // try to load a TOC for mapping and check version number - UBToc toc{pDocumentProxy->persistencePath()}; + UBDocumentToc toc{pDocumentProxy->persistencePath()}; std::unique_ptr mapper{nullptr}; const auto version = QVersionNumber::fromString(pDocumentProxy->metaData(UBSettings::documentVersion).toString()); diff --git a/src/adaptors/UBPageMapper.cpp b/src/adaptors/UBPageMapper.cpp index 5fbf5505b..79e01637d 100644 --- a/src/adaptors/UBPageMapper.cpp +++ b/src/adaptors/UBPageMapper.cpp @@ -23,9 +23,9 @@ #include "UBPageMapper.h" #include "core/UBPersistenceManager.h" -#include "document/UBToc.h" +#include "document/UBDocumentToc.h" -UBPageMapper::UBPageMapper(const QString& documentPath, UBToc* toc) +UBPageMapper::UBPageMapper(const QString& documentPath, UBDocumentToc* toc) : mDocumentPath{documentPath} , mSourceToc{toc} { @@ -36,7 +36,7 @@ UBPageMapper::UBPageMapper(const QString& documentPath, UBToc* toc) } auto pm = UBPersistenceManager::persistenceManager(); - mMappedToc = std::unique_ptr{new UBToc(*mSourceToc, mTempDir.path())}; + mMappedToc = std::unique_ptr{new UBDocumentToc(*mSourceToc, mTempDir.path())}; // create page map and target TOC for (int index = 0; index < mSourceToc->pageCount(); ++index) diff --git a/src/adaptors/UBPageMapper.h b/src/adaptors/UBPageMapper.h index 88de2711c..f4016c218 100644 --- a/src/adaptors/UBPageMapper.h +++ b/src/adaptors/UBPageMapper.h @@ -29,7 +29,7 @@ #include // forward -class UBToc; +class UBDocumentToc; /** * @brief The UBPageMapper maps a file name which should be saved in a ZIP @@ -49,14 +49,14 @@ class UBPageMapper }; public: - UBPageMapper(const QString& documentPath, UBToc* toc); + UBPageMapper(const QString& documentPath, UBDocumentToc* toc); MapResult map(const QString& filename) const; private: const QString mDocumentPath; - const UBToc* mSourceToc{nullptr}; - std::unique_ptr mMappedToc; + const UBDocumentToc* mSourceToc{nullptr}; + std::unique_ptr mMappedToc; QHash mFileMap; QTemporaryDir mTempDir; }; diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index 581f6e34a..438b4dfcc 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -49,7 +49,7 @@ #include "document/UBDocument.h" #include "document/UBDocumentController.h" #include "document/UBDocumentProxy.h" -#include "document/UBToc.h" +#include "document/UBDocumentToc.h" #include "frameworks/UBFileSystemUtils.h" @@ -598,7 +598,7 @@ std::shared_ptr UBPersistenceManager::createDocument(const QStr return nullptr; // if we can't create the path, abort function. } - UBToc toc{doc->persistencePath()}; + UBDocumentToc toc{doc->persistencePath()}; if (withEmptyPage) { diff --git a/src/document/CMakeLists.txt b/src/document/CMakeLists.txt index 47aca1022..a6e1f4c36 100644 --- a/src/document/CMakeLists.txt +++ b/src/document/CMakeLists.txt @@ -7,10 +7,10 @@ target_sources(${PROJECT_NAME} PRIVATE UBDocumentController.h UBDocumentProxy.cpp UBDocumentProxy.h + UBDocumentToc.cpp + UBDocumentToc.h UBSortFilterProxyModel.cpp UBSortFilterProxyModel.h - UBToc.cpp - UBToc.h UBTocSerializer.cpp UBTocSerializer.h ) diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index f8a5af5a9..9bc934ae5 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -27,7 +27,7 @@ #include "core/UBApplication.h" #include "core/UBPersistenceManager.h" #include "document/UBDocumentController.h" -#include "document/UBToc.h" +#include "document/UBDocumentToc.h" #include "domain/UBMediaAssetItem.h" #include "frameworks/UBBackgroundLoader.h" #include "gui/UBMainWindow.h" @@ -265,11 +265,11 @@ UBThumbnailScene* UBDocument::thumbnailScene() return mThumbnailScene.get(); } -UBToc* UBDocument::toc() +UBDocumentToc* UBDocument::toc() { if (!mToc) { - mToc = new UBToc{mProxy->persistencePath()}; + mToc = new UBDocumentToc{mProxy->persistencePath()}; const auto tocPresent = mToc->load(); if (!tocPresent || diff --git a/src/document/UBDocument.h b/src/document/UBDocument.h index c24df86ba..b750a1515 100644 --- a/src/document/UBDocument.h +++ b/src/document/UBDocument.h @@ -33,9 +33,9 @@ // forward class UBBackgroundLoader; class UBDocumentProxy; +class UBDocumentToc; class UBGraphicsScene; class UBThumbnailScene; -class UBToc; /** @@ -70,7 +70,7 @@ class UBDocument : public std::enable_shared_from_this std::shared_ptr getScene(int index); QList pageRelativeDependencies(int index); UBThumbnailScene* thumbnailScene(); - UBToc* toc(); + UBDocumentToc* toc(); int pageCount(); @@ -93,7 +93,7 @@ class UBDocument : public std::enable_shared_from_this private: std::shared_ptr mProxy{nullptr}; std::unique_ptr mThumbnailScene; - UBToc* mToc{nullptr}; + UBDocumentToc* mToc{nullptr}; UBBackgroundLoader* mSceneHeaderLoader{nullptr}; UBBackgroundLoader* mSceneAssetLoader{nullptr}; QHash mUuidV5Map{}; diff --git a/src/document/UBToc.cpp b/src/document/UBDocumentToc.cpp similarity index 77% rename from src/document/UBToc.cpp rename to src/document/UBDocumentToc.cpp index 77cd6e921..76b02ca32 100644 --- a/src/document/UBToc.cpp +++ b/src/document/UBDocumentToc.cpp @@ -20,7 +20,7 @@ */ -#include "UBToc.h" +#include "UBDocumentToc.h" #include @@ -30,29 +30,29 @@ static const QString UUID{"uuid"}; static const QString PAGE_ID{"id"}; static const QString ASSETS("assets"); -UBToc::UBToc(const QString& documentPath) +UBDocumentToc::UBDocumentToc(const QString& documentPath) : mDocumentPath{documentPath} { } -UBToc::UBToc(const UBToc& other, const QString& documentPath) +UBDocumentToc::UBDocumentToc(const UBDocumentToc& other, const QString& documentPath) : mDocumentPath{documentPath} , mVersion{other.mVersion} , mToc{other.mToc} { } -QVersionNumber UBToc::version() const +QVersionNumber UBDocumentToc::version() const { return mVersion; } -int UBToc::pageCount() const +int UBDocumentToc::pageCount() const { return mToc.count(); } -int UBToc::insert(int index) +int UBDocumentToc::insert(int index) { if (index >= 0 && index <= mToc.count()) { @@ -65,7 +65,7 @@ int UBToc::insert(int index) return -1; } -void UBToc::move(int fromIndex, int toIndex) +void UBDocumentToc::move(int fromIndex, int toIndex) { if (fromIndex < 0 || fromIndex >= mToc.count() || toIndex < 0 || toIndex >= mToc.count()) { @@ -78,7 +78,7 @@ void UBToc::move(int fromIndex, int toIndex) mModified = true; } -void UBToc::remove(int index) +void UBDocumentToc::remove(int index) { if (index >= 0 && index < mToc.count()) { @@ -87,7 +87,7 @@ void UBToc::remove(int index) } } -QUuid UBToc::uuid(int index) const +QUuid UBDocumentToc::uuid(int index) const { if (index < 0 || index >= mToc.count()) { @@ -97,7 +97,7 @@ QUuid UBToc::uuid(int index) const return mToc.at(index).value(UUID).toUuid(); } -void UBToc::setUuid(int index, const QUuid& uuid) +void UBDocumentToc::setUuid(int index, const QUuid& uuid) { if (index < 0) { @@ -109,7 +109,7 @@ void UBToc::setUuid(int index, const QUuid& uuid) mModified = true; } -int UBToc::findUuid(const QUuid& sceneUuid) const +int UBDocumentToc::findUuid(const QUuid& sceneUuid) const { for (int i = 0; i < mToc.size(); ++i) { @@ -122,7 +122,7 @@ int UBToc::findUuid(const QUuid& sceneUuid) const return -1; } -int UBToc::pageId(int index) const +int UBDocumentToc::pageId(int index) const { if (index < 0 || index >= mToc.count()) { @@ -132,7 +132,7 @@ int UBToc::pageId(int index) const return mToc.at(index).value(PAGE_ID).toInt(); } -void UBToc::setPageId(int index, int pageId) +void UBDocumentToc::setPageId(int index, int pageId) { if (index < 0) { @@ -144,7 +144,7 @@ void UBToc::setPageId(int index, int pageId) mModified = true; } -QStringList UBToc::assets(int index) const +QStringList UBDocumentToc::assets(int index) const { if (index < 0 || index >= mToc.count()) { @@ -154,7 +154,7 @@ QStringList UBToc::assets(int index) const return mToc.at(index).value(ASSETS).toStringList(); } -void UBToc::setAssets(int index, const QStringList& assets) +void UBDocumentToc::setAssets(int index, const QStringList& assets) { if (index < 0) { @@ -166,12 +166,12 @@ void UBToc::setAssets(int index, const QStringList& assets) mModified = true; } -void UBToc::unsetAssets(int index) +void UBDocumentToc::unsetAssets(int index) { mToc[index].remove(ASSETS); } -bool UBToc::hasAssetsEntry(int index) const +bool UBDocumentToc::hasAssetsEntry(int index) const { if (index < 0 || index >= mToc.count()) { @@ -181,7 +181,7 @@ bool UBToc::hasAssetsEntry(int index) const return mToc.at(index).contains(ASSETS); } -bool UBToc::load() +bool UBDocumentToc::load() { UBTocJsonSerializer serializer(mDocumentPath); const auto ok = serializer.load(mVersion, mToc); @@ -195,7 +195,7 @@ bool UBToc::load() return ok; } -void UBToc::save() +void UBDocumentToc::save() { if (mModified) { @@ -205,12 +205,12 @@ void UBToc::save() } } -int UBToc::nextAvailablePageId() +int UBDocumentToc::nextAvailablePageId() { return mNextAvailablePageId++; } -void UBToc::assureSize(int index) +void UBDocumentToc::assureSize(int index) { if (index >= mToc.count()) { diff --git a/src/document/UBToc.h b/src/document/UBDocumentToc.h similarity index 88% rename from src/document/UBToc.h rename to src/document/UBDocumentToc.h index bb138d6fa..49b2beded 100644 --- a/src/document/UBToc.h +++ b/src/document/UBDocumentToc.h @@ -28,13 +28,13 @@ #include -static const QVersionNumber TOC_VERSION{1, 0}; +static const QVersionNumber DOCUMENT_TOC_VERSION{1, 0}; -class UBToc +class UBDocumentToc { public: - UBToc(const QString& documentPath); - UBToc(const UBToc& other, const QString& documentPath); + UBDocumentToc(const QString& documentPath); + UBDocumentToc(const UBDocumentToc& other, const QString& documentPath); QVersionNumber version() const; @@ -71,7 +71,7 @@ class UBToc private: const QString mDocumentPath; - QVersionNumber mVersion{TOC_VERSION}; + QVersionNumber mVersion{DOCUMENT_TOC_VERSION}; QVector mToc; int mNextAvailablePageId{0}; bool mModified{false}; diff --git a/src/document/document.pri b/src/document/document.pri index 1cb581c87..68d165a7d 100644 --- a/src/document/document.pri +++ b/src/document/document.pri @@ -3,14 +3,14 @@ HEADERS += \ src/document/UBDocumentContainer.h \ src/document/UBDocumentController.h \ src/document/UBDocumentProxy.h \ + src/document/UBDocumentToc.h \ src/document/UBSortFilterProxyModel.h \ - src/document/UBToc.h \ src/document/UBTocSerializer.h SOURCES += \ src/document/UBDocument.cpp \ src/document/UBDocumentContainer.cpp \ src/document/UBDocumentController.cpp \ src/document/UBDocumentProxy.cpp \ + src/document/UBDocumentToc.cpp \ src/document/UBSortFilterProxyModel.cpp \ - src/document/UBToc.cpp \ src/document/UBTocSerializer.cpp From f4f5f4e3c364aea33d1d538ccdca914f3bd3e063 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 5 Jan 2025 10:19:14 +0100 Subject: [PATCH 023/133] refactor: UBDocumentTreeMimeData - add mime type - remove URLs --- src/document/UBDocumentController.cpp | 21 ++++++--------------- src/document/UBDocumentController.h | 11 ++++++----- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index ec4ba3f19..2a6d042cc 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -684,32 +684,23 @@ QDateTime UBDocumentTreeModel::findCatalogCreationDate(UBDocumentTreeNode *node) QStringList UBDocumentTreeModel::mimeTypes() const { - QStringList types; - types << "text/uri-list" << "image/png" << "image/tiff" << "image/gif" << "image/jpeg"; + static const QStringList types{UBApplication::mimeTypeUniboardDocument}; return types; } QMimeData *UBDocumentTreeModel::mimeData (const QModelIndexList &indexes) const { - UBDocumentTreeMimeData *mimeData = new UBDocumentTreeMimeData(); QList indexList; - QList urlList; - foreach (QModelIndex index, indexes) { - if (index.isValid()) { + for (const auto& index : indexes) + { + if (index.isValid()) + { indexList.append(index); - urlList.append(QUrl()); } } -#if defined(Q_OS_OSX) - #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - if (QOperatingSystemVersion::current().majorVersion() == 10 && QOperatingSystemVersion::current().minorVersion() < 15) /* <= Mojave */ - mimeData->setUrls(urlList); - #endif -#else - mimeData->setUrls(urlList); -#endif + UBDocumentTreeMimeData* mimeData = new UBDocumentTreeMimeData(); mimeData->setIndexes(indexList); return mimeData; diff --git a/src/document/UBDocumentController.h b/src/document/UBDocumentController.h index bd094bbb0..8307603a9 100644 --- a/src/document/UBDocumentController.h +++ b/src/document/UBDocumentController.h @@ -291,12 +291,13 @@ class UBDocumentTreeMimeData : public QMimeData { Q_OBJECT - public: - QList indexes() const {return mIndexes;} - void setIndexes (const QList &pIndexes) {mIndexes = pIndexes;} +public: + UBDocumentTreeMimeData() { setData(UBApplication::mimeTypeUniboardDocument, {}); } + QList indexes() const {return mIndexes;} + void setIndexes (const QList &pIndexes) {mIndexes = pIndexes;} - private: - QList mIndexes; +private: + QList mIndexes; }; class UBDocumentTreeView : public QTreeView From ab7b0aba106fb0e5f81c9a87c1d7108574cf2219 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 5 Jan 2025 11:55:15 +0100 Subject: [PATCH 024/133] fix: drop indications - always highlight complete row when dropping a page on the tree - show copy cursor when dropping a page - show move cursor when moving a document - start page drag action with move and copy actions enabled - add function to determine base model --- src/document/UBDocumentController.cpp | 127 ++++++++++++++------------ src/document/UBDocumentController.h | 4 +- src/gui/UBDocumentThumbnailWidget.cpp | 2 +- 3 files changed, 73 insertions(+), 60 deletions(-) diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index 2a6d042cc..c7b10301a 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -517,7 +517,7 @@ QVariant UBDocumentTreeModel::data(const QModelIndex &index, int role) const return QBrush(0xD9DFEB); } - if (mHighLighted.isValid() && index == mHighLighted) { + if (mHighLighted.isValid() && index.row() == mHighLighted.row()) { return QBrush(0x6682B5); } } @@ -1441,6 +1441,37 @@ bool UBDocumentTreeModel::nodeLessThan(const UBDocumentTreeNode *firstIndex, con return firstIndex->nodeName() < secondIndex->nodeName(); } +void UBDocumentTreeModel::setHighLighted(const QModelIndex& newHighLighted) +{ + QModelIndex from; + QModelIndex to; + + if (mHighLighted.isValid()) + { + from = mHighLighted.siblingAtColumn(0); + to = mHighLighted.siblingAtColumn(1); + }; + + if (newHighLighted.isValid()) + { + if (!from.isValid()) + { + from = newHighLighted.siblingAtColumn(0); + } + + to = newHighLighted.siblingAtColumn(1); + } + + mHighLighted = newHighLighted; + + if (from.row() > to.row()) + { + std::swap(from, to); + } + + emit dataChanged(from, to, {Qt::BackgroundRole}); +} + UBDocumentTreeModel::~UBDocumentTreeModel() { delete mRootNode; @@ -1515,89 +1546,72 @@ void UBDocumentTreeView::mousePressEvent(QMouseEvent *event) void UBDocumentTreeView::dragEnterEvent(QDragEnterEvent *event) { - QTreeView::dragEnterEvent(event); - event->accept(); - event->acceptProposedAction(); + if (event->mimeData()->hasFormat(UBApplication::mimeTypeUniboardPage)) + { + // accept copying a page + event->setDropAction(Qt::CopyAction); + event->accept(); + } + else if (event->mimeData()->hasFormat(UBApplication::mimeTypeUniboardDocument)) + { + // accept moving a document + event->setDropAction(Qt::MoveAction); + event->accept(); + } } void UBDocumentTreeView::dragLeaveEvent(QDragLeaveEvent *event) { Q_UNUSED(event); - UBDocumentTreeModel *docModel = 0; - - UBSortFilterProxyModel *proxy = dynamic_cast(model()); - - if(proxy){ - docModel = dynamic_cast(proxy->sourceModel()); - }else{ - docModel = dynamic_cast(model()); - } - - docModel->setHighLighted(QModelIndex()); + baseModel()->setHighLighted(QModelIndex()); update(); } void UBDocumentTreeView::dragMoveEvent(QDragMoveEvent *event) { - QModelIndex index; - if (selectedIndexes().count() > 0) + if (event->mimeData()->hasFormat(UBApplication::mimeTypeUniboardPage)) { - index = selectedIndexes().first(); - } - #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - QPoint eventPos = event->position().toPoint(); + QPoint eventPos = event->position().toPoint(); #else - QPoint eventPos = event->pos(); + QPoint eventPos = event->pos(); #endif - bool acceptIt = isAcceptable(index, indexAt(eventPos)); - - if (event->mimeData()->hasFormat(UBApplication::mimeTypeUniboardPage)) { - UBSortFilterProxyModel *proxy = dynamic_cast(model()); - - UBDocumentTreeModel *docModel = 0; - - if(proxy){ - docModel = dynamic_cast(proxy->sourceModel()); - }else{ - docModel = dynamic_cast(model()); - } + UBDocumentTreeModel* docModel{baseModel()}; QModelIndex targetIndex = mapIndexToSource(indexAt(eventPos)); - if (!docModel || !docModel->isDocument(targetIndex) || docModel->inTrash(targetIndex)) { - event->ignore(); - event->setDropAction(Qt::IgnoreAction); + if (!targetIndex.isValid() || !docModel || !docModel->isDocument(targetIndex) || docModel->inTrash(targetIndex)) + { + event->ignore(visualRect(targetIndex)); if (docModel) { docModel->setHighLighted(QModelIndex()); } - - acceptIt = false; - } else { + } + else + { + event->setDropAction(Qt::CopyAction); + event->accept(visualRect(targetIndex)); docModel->setHighLighted(targetIndex); - acceptIt = true; } - updateIndexEnvirons(indexAt(eventPos)); } - QTreeView::dragMoveEvent(event); - - event->setAccepted(acceptIt); + else if (event->mimeData()->hasFormat(UBApplication::mimeTypeUniboardDocument)) + { + event->accept(); + QTreeView::dragMoveEvent(event); + } } void UBDocumentTreeView::dropEvent(QDropEvent *event) { event->ignore(); event->setDropAction(Qt::IgnoreAction); - UBDocumentTreeModel *docModel = 0; + UBDocumentTreeModel* docModel{baseModel()}; //N/C - NNE - 20140408 UBSortFilterProxyModel *proxy = dynamic_cast(model()); - if(proxy){ - docModel = dynamic_cast(proxy->sourceModel()); - } #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QPoint eventPos = event->position().toPoint(); @@ -1676,6 +1690,12 @@ void UBDocumentTreeView::rowsAboutToBeRemoved(const QModelIndex &parent, int sta QTreeView::rowsAboutToBeRemoved(parent, start, end); } +UBDocumentTreeModel* UBDocumentTreeView::baseModel() const +{ + UBSortFilterProxyModel *proxy = dynamic_cast(model()); + return dynamic_cast(proxy ? proxy->sourceModel() : model()); +} + bool UBDocumentTreeView::isAcceptable(const QModelIndex &dragIndex, const QModelIndex &atIndex) { QModelIndex dragIndexSource = mapIndexToSource(dragIndex); @@ -1692,14 +1712,6 @@ Qt::DropAction UBDocumentTreeView::acceptableAction(const QModelIndex &dragIndex return Qt::MoveAction; } -void UBDocumentTreeView::updateIndexEnvirons(const QModelIndex &index) -{ - QRect updateRect = visualRect(index); - const int multipler = 3; - updateRect.adjust(0, -updateRect.height() * multipler, 0, updateRect.height() * multipler); - update(updateRect); -} - //N/C - NNE - 20140404 QModelIndex UBDocumentTreeView::mapIndexToSource(const QModelIndex &index) { @@ -2227,6 +2239,7 @@ void UBDocumentController::setupViews() mDocumentUI->documentTreeView->setItemDelegate(new UBDocumentTreeItemDelegate(this)); mDocumentUI->documentTreeView->setDragEnabled(true); mDocumentUI->documentTreeView->setAcceptDrops(true); + mDocumentUI->documentTreeView->setDefaultDropAction(Qt::MoveAction); mDocumentUI->documentTreeView->viewport()->setAcceptDrops(true); mDocumentUI->documentTreeView->setDropIndicatorShown(true); mDocumentUI->documentTreeView->header()->setStretchLastSection(false); diff --git a/src/document/UBDocumentController.h b/src/document/UBDocumentController.h index 8307603a9..d0444efb9 100644 --- a/src/document/UBDocumentController.h +++ b/src/document/UBDocumentController.h @@ -241,7 +241,7 @@ class UBDocumentTreeModel : public QAbstractItemModel { QPersistentModelIndex untitledDocumentsIndex() const {return mMyDocuments;} UBDocumentTreeNode *nodeFromIndex(const QModelIndex &pIndex) const; static bool nodeLessThan(const UBDocumentTreeNode *firstIndex, const UBDocumentTreeNode *secondIndex); - void setHighLighted(const QModelIndex &newHighLighted) {mHighLighted = newHighLighted;} + void setHighLighted(const QModelIndex &newHighLighted); QModelIndex highLighted() {return mHighLighted;} std::shared_ptr findDocumentByFolderName(QString folderName) const; std::shared_ptr findDocumentByFolderName(UBDocumentTreeNode* node, QString folderName) const; @@ -330,8 +330,8 @@ public slots: private: bool isAcceptable(const QModelIndex &dragIndex, const QModelIndex &atIndex); + UBDocumentTreeModel* baseModel() const; Qt::DropAction acceptableAction(const QModelIndex &dragIndex, const QModelIndex &atIndex); - void updateIndexEnvirons(const QModelIndex &index); }; class UBValidator : public QValidator diff --git a/src/gui/UBDocumentThumbnailWidget.cpp b/src/gui/UBDocumentThumbnailWidget.cpp index f0c857b0d..ea344580e 100644 --- a/src/gui/UBDocumentThumbnailWidget.cpp +++ b/src/gui/UBDocumentThumbnailWidget.cpp @@ -107,7 +107,7 @@ void UBDocumentThumbnailWidget::mouseMoveEvent(QMouseEvent *event) drag->setPixmap(sceneItem->pixmap().scaledToWidth(100)); drag->setHotSpot(QPoint(drag->pixmap().width()/2, drag->pixmap().height() / 2)); - drag->exec(Qt::MoveAction); + drag->exec({Qt::MoveAction, Qt::CopyAction}); } UBDocumentThumbnailsView::mouseMoveEvent(event); From 108e46f56438fe30b3adecb5e49756a8cd34da6f Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Tue, 7 Jan 2025 08:57:05 +0100 Subject: [PATCH 025/133] refactor: drop handling - use indexes from mime data - remove dead code dropMimeData --- src/document/UBDocumentController.cpp | 136 +++++--------------------- src/document/UBDocumentController.h | 10 +- 2 files changed, 28 insertions(+), 118 deletions(-) diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index c7b10301a..f84636a49 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -690,96 +690,18 @@ QStringList UBDocumentTreeModel::mimeTypes() const QMimeData *UBDocumentTreeModel::mimeData (const QModelIndexList &indexes) const { - QList indexList; + QModelIndexList indexList; for (const auto& index : indexes) { - if (index.isValid()) + // only add indexes for first column + if (index.isValid() && index.column() == 0) { indexList.append(index); } } - UBDocumentTreeMimeData* mimeData = new UBDocumentTreeMimeData(); - mimeData->setIndexes(indexList); - - return mimeData; -} - -bool UBDocumentTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) -{ - if (action == Qt::IgnoreAction) { - return false; - } - - if (data->hasFormat(UBApplication::mimeTypeUniboardPage)) { - UBDocumentTreeNode *curNode = nodeFromIndex(index(row - 1, column, parent)); - std::shared_ptr targetDocProxy = curNode->proxyData(); - const UBMimeData *ubMime = qobject_cast (data); - if (!targetDocProxy || !ubMime || !ubMime->items().count()) { - qDebug() << "an error ocured while parsing " << UBApplication::mimeTypeUniboardPage; - return false; - } - - int total = ubMime->items().size(); - - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - - foreach (UBMimeDataItem sourceItem, ubMime->items()) - { - std::shared_ptr fromProxy = sourceItem.documentProxy(); - auto fromDocument = UBDocument::getDocument(fromProxy); - auto targetDocument = UBDocument::getDocument(targetDocProxy); - - int fromIndex = sourceItem.sceneIndex(); - int toIndex = targetDocument->pageCount(); - - fromDocument->copyPage(fromIndex, targetDocument, toIndex); - } - - QApplication::restoreOverrideCursor(); - - UBApplication::showMessage(tr("%1 pages copied", "", total).arg(total), false); - - return true; - } - - const UBDocumentTreeMimeData *mimeData = qobject_cast(data); - if (!mimeData) { - qDebug() << "Incorrect mimeData, only internal one supported"; - return false; - } - - if (!parent.isValid()) { - return false; - } - - UBDocumentTreeNode *newParentNode = nodeFromIndex(parent); - - if (!newParentNode) { - qDebug() << "incorrect incoming parent node;"; - return false; - } - - QList incomingIndexes = mimeData->indexes(); - - foreach (QModelIndex curIndex, incomingIndexes) - { - //Issue N/C - NNE - 20140528 : use just the index on the first column - if(curIndex.column() == 0){ - QModelIndex clonedTopLevel = copyIndexToNewParent(curIndex, parent, action == Qt::MoveAction ? aReference : aContentCopy); - if (nodeFromIndex(curIndex) == mCurrentNode && action == Qt::MoveAction) { - emit currentIndexMoved(clonedTopLevel, curIndex); - } - } - } - - Q_UNUSED(action) - Q_UNUSED(row) - Q_UNUSED(column) - Q_UNUSED(parent) - - return true; + return new UBDocumentTreeMimeData(indexList); } bool UBDocumentTreeModel::removeRows(int row, int count, const QModelIndex &parent) @@ -1610,18 +1532,12 @@ void UBDocumentTreeView::dropEvent(QDropEvent *event) event->setDropAction(Qt::IgnoreAction); UBDocumentTreeModel* docModel{baseModel()}; - //N/C - NNE - 20140408 - UBSortFilterProxyModel *proxy = dynamic_cast(model()); - #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QPoint eventPos = event->position().toPoint(); #else QPoint eventPos = event->pos(); #endif QModelIndex targetIndex = mapIndexToSource(indexAt(eventPos)); - QModelIndexList dropIndex = mapIndexesToSource(selectionModel()->selectedRows(0)); - - bool isUBPage = event->mimeData()->hasFormat(UBApplication::mimeTypeUniboardPage); //issue 1629 - NNE - 20131212 bool targetIsInTrash = docModel && (docModel->inTrash(targetIndex) || docModel->trashIndex() == targetIndex); @@ -1630,7 +1546,7 @@ void UBDocumentTreeView::dropEvent(QDropEvent *event) if (!targetIsInMyDocuments && !targetIsInTrash) return; - if (isUBPage) + if (event->mimeData()->hasFormat(UBApplication::mimeTypeUniboardPage)) { std::shared_ptr targetDocProxy = docModel->proxyData(targetIndex); auto targetDocument = UBDocument::getDocument(targetDocProxy); @@ -1663,20 +1579,24 @@ void UBDocumentTreeView::dropEvent(QDropEvent *event) UBApplication::showMessage(tr("%1 pages copied", "", total).arg(total), false); } - else + else if (event->mimeData()->hasFormat(UBApplication::mimeTypeUniboardDocument)) { - if(targetIsInTrash) + const auto* documentMimeData = dynamic_cast(event->mimeData()); + QModelIndexList dropIndex = documentMimeData->indexes(); + + if (targetIsInTrash) { UBApplication::documentController->moveIndexesToTrash(dropIndex, docModel); - }else{ + } + else + { docModel->moveIndexes(dropIndex, targetIndex); } } + UBSortFilterProxyModel *proxy = dynamic_cast(model()); expand(proxy->mapFromSource(targetIndex)); - QTreeView::dropEvent(event); - UBApplication::documentController->pageSelectionChanged(); } @@ -1723,23 +1643,6 @@ QModelIndex UBDocumentTreeView::mapIndexToSource(const QModelIndex &index) return index; } - -QModelIndexList UBDocumentTreeView::mapIndexesToSource(const QModelIndexList &indexes) -{ - UBSortFilterProxyModel *proxy = dynamic_cast(model()); - - if(proxy){ - QModelIndexList list; - - for(int i = 0; i < indexes.size(); i++){ - list.push_back(proxy->mapToSource(indexes.at(i))); - } - - return list; - } - - return indexes; -} //N/C - NNE - 20140404 : END UBDocumentTreeItemDelegate::UBDocumentTreeItemDelegate(QObject *parent) @@ -3965,3 +3868,14 @@ void UBDocumentController::clearThumbnailsSelection() mDocumentUI->thumbnailWidget->clearSelection(); pageSelectionChanged(); } + +UBDocumentTreeMimeData::UBDocumentTreeMimeData(const QModelIndexList& pIndexes) + : mIndexes{pIndexes} +{ + setData(UBApplication::mimeTypeUniboardDocument, {}); +} + +QModelIndexList UBDocumentTreeMimeData::indexes() const +{ + return mIndexes; +} diff --git a/src/document/UBDocumentController.h b/src/document/UBDocumentController.h index d0444efb9..07513b831 100644 --- a/src/document/UBDocumentController.h +++ b/src/document/UBDocumentController.h @@ -192,14 +192,12 @@ class UBDocumentTreeModel : public QAbstractItemModel { Qt::DropActions supportedDropActions() const {return Qt::MoveAction | Qt::CopyAction;} QStringList mimeTypes() const; QMimeData *mimeData (const QModelIndexList &indexes) const; - bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); bool removeRows(int row, int count, const QModelIndex &parent); bool containsDocuments(const QModelIndex& index); QModelIndex indexForNode(UBDocumentTreeNode *pNode) const; QPersistentModelIndex persistentIndexForNode(UBDocumentTreeNode *pNode); -// bool insertRow(int row, const QModelIndex &parent); QPersistentModelIndex copyIndexToNewParent(const QModelIndex &source, const QModelIndex &newParent, eCopyMode pMode = aReference); @@ -292,12 +290,11 @@ class UBDocumentTreeMimeData : public QMimeData Q_OBJECT public: - UBDocumentTreeMimeData() { setData(UBApplication::mimeTypeUniboardDocument, {}); } - QList indexes() const {return mIndexes;} - void setIndexes (const QList &pIndexes) {mIndexes = pIndexes;} + UBDocumentTreeMimeData(const QModelIndexList& pIndexes); + QModelIndexList indexes() const; private: - QList mIndexes; + QModelIndexList mIndexes; }; class UBDocumentTreeView : public QTreeView @@ -309,7 +306,6 @@ class UBDocumentTreeView : public QTreeView //N/C - NNE - 20140404 QModelIndex mapIndexToSource(const QModelIndex &index); - QModelIndexList mapIndexesToSource(const QModelIndexList &indexes); public slots: void setSelectedAndExpanded(const QModelIndex &pIndex, bool pExpand = true, bool pEdit = false); From 07a854dff2b353ef26d5a40d00fb0fb72419ea72 Mon Sep 17 00:00:00 2001 From: Vekhir Date: Tue, 27 Aug 2024 19:13:04 +0200 Subject: [PATCH 026/133] refactor: Use new permission system in Qt 6.8 Qt 6.8 introduces a new system to manage permissions for websites Building with Qt 6.7 and earlier is unaffected due to extensive preprocessor directives. --- src/web/UBWebController.cpp | 2 ++ src/web/UBWebController.h | 4 +++ src/web/simplebrowser/webpage.cpp | 45 +++++++++++++++++++++++++++++++ src/web/simplebrowser/webpage.h | 7 +++++ 4 files changed, 58 insertions(+) diff --git a/src/web/UBWebController.cpp b/src/web/UBWebController.cpp index 731aad7f8..3d5a006e6 100644 --- a/src/web/UBWebController.cpp +++ b/src/web/UBWebController.cpp @@ -408,6 +408,7 @@ BrowserWindow* UBWebController::browserWindow() const return mCurrentWebBrowser; } +#if (QT_VERSION < QT_VERSION_CHECK(6, 8, 0)) QWebEnginePage::PermissionPolicy UBWebController::hasFeaturePermission(const QUrl &securityOrigin, QWebEnginePage::Feature feature) { QPair featurePermission(securityOrigin, feature); @@ -425,6 +426,7 @@ void UBWebController::setFeaturePermission(const QUrl &securityOrigin, QWebEngin QPair featurePermission(securityOrigin, feature); mFeaturePermissions[featurePermission] = policy; } +#endif // QT_VERSION < QT_VERSION_CHECK(6, 8, 0) void UBWebController::injectScripts(QWebEngineView *view) { diff --git a/src/web/UBWebController.h b/src/web/UBWebController.h index 4cabc9c95..ff671dd4b 100644 --- a/src/web/UBWebController.h +++ b/src/web/UBWebController.h @@ -92,8 +92,10 @@ class UBWebController : public QObject QWebEngineProfile* webProfile() const; QList getEmbeddedContent(const QWebEngineView* view) const; BrowserWindow* browserWindow() const; +#if (QT_VERSION < QT_VERSION_CHECK(6, 8, 0)) QWebEnginePage::PermissionPolicy hasFeaturePermission(const QUrl &securityOrigin, QWebEnginePage::Feature feature); void setFeaturePermission(const QUrl &securityOrigin, QWebEnginePage::Feature feature, QWebEnginePage::PermissionPolicy policy); +#endif static void injectScripts(QWebEngineView* view); @@ -163,7 +165,9 @@ class UBWebController : public QObject QMenu* mHistoryBackMenu; QMenu* mHistoryForwardMenu; +#if (QT_VERSION < QT_VERSION_CHECK(6, 8, 0)) QMap,QWebEnginePage::PermissionPolicy> mFeaturePermissions; +#endif bool cookieAutoDelete; QStringList cookieKeepDomains; diff --git a/src/web/simplebrowser/webpage.cpp b/src/web/simplebrowser/webpage.cpp index efd9c42bb..89e92e4b9 100644 --- a/src/web/simplebrowser/webpage.cpp +++ b/src/web/simplebrowser/webpage.cpp @@ -64,7 +64,11 @@ WebPage::WebPage(QWebEngineProfile *profile, QObject *parent) : QWebEnginePage(profile, parent) { connect(this, &QWebEnginePage::authenticationRequired, this, &WebPage::handleAuthenticationRequired); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)) + connect(this, &QWebEnginePage::permissionRequested, this, &WebPage::handlePermissionRequested); +#else connect(this, &QWebEnginePage::featurePermissionRequested, this, &WebPage::handleFeaturePermissionRequested); +#endif connect(this, &QWebEnginePage::proxyAuthenticationRequired, this, &WebPage::handleProxyAuthenticationRequired); connect(this, &QWebEnginePage::registerProtocolHandlerRequested, this, &WebPage::handleRegisterProtocolHandlerRequested); #if !defined(QT_NO_SSL) || QTWEBENGINEWIDGETS_VERSION >= QT_VERSION_CHECK(5, 12, 0) @@ -170,6 +174,30 @@ void WebPage::handleAuthenticationRequired(const QUrl &requestUrl, QAuthenticato } } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)) +inline QString questionForFeature(QWebEnginePermission::PermissionType permissionType) +{ + switch (permissionType) { + case QWebEnginePermission::PermissionType::MediaAudioCapture: + return WebPage::tr("Allow %1 to access your microphone?"); + case QWebEnginePermission::PermissionType::MediaVideoCapture: + return WebPage::tr("Allow %1 to access your webcam?"); + case QWebEnginePermission::PermissionType::MediaAudioVideoCapture: + return WebPage::tr("Allow %1 to access your microphone and webcam?"); + case QWebEnginePermission::PermissionType::DesktopVideoCapture: + return WebPage::tr("Allow %1 to capture video of your desktop?"); + case QWebEnginePermission::PermissionType::DesktopAudioVideoCapture: + return WebPage::tr("Allow %1 to capture audio and video of your desktop?"); + case QWebEnginePermission::PermissionType::MouseLock: + return WebPage::tr("Allow %1 to lock your mouse cursor?"); + case QWebEnginePermission::PermissionType::Geolocation: + return WebPage::tr("Allow %1 to access your location information?"); + case QWebEnginePermission::PermissionType::Notifications: + return QString(); + } + return QString(); +} +#else inline QString questionForFeature(QWebEnginePage::Feature feature) { switch (feature) { @@ -192,7 +220,23 @@ inline QString questionForFeature(QWebEnginePage::Feature feature) } return QString(); } +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)) +void WebPage::handlePermissionRequested(QWebEnginePermission permission) +{ + if (permission.state() == QWebEnginePermission::State::Ask) + { + QString title = tr("Permission Request"); + QString question = questionForFeature(permission.permissionType()).arg(permission.origin().host()); + if (!question.isEmpty() && QMessageBox::question(UBApplication::mainWindow->centralWidget(), title, question) == QMessageBox::Yes) + permission.grant(); + else + permission.deny(); + } +} +#else void WebPage::handleFeaturePermissionRequested(const QUrl &securityOrigin, Feature feature) { PermissionPolicy policy = UBApplication::webController->hasFeaturePermission(securityOrigin, feature); @@ -212,6 +256,7 @@ void WebPage::handleFeaturePermissionRequested(const QUrl &securityOrigin, Featu setFeaturePermission(securityOrigin, feature, policy); } +#endif void WebPage::handleProxyAuthenticationRequired(const QUrl &, QAuthenticator *auth, const QString &proxyHost) { diff --git a/src/web/simplebrowser/webpage.h b/src/web/simplebrowser/webpage.h index 83b976b69..2b0c647a5 100644 --- a/src/web/simplebrowser/webpage.h +++ b/src/web/simplebrowser/webpage.h @@ -53,6 +53,9 @@ #include #include +#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)) +#include +#endif #include #include @@ -73,7 +76,11 @@ private slots: private slots: void handleAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)) + void handlePermissionRequested(QWebEnginePermission permission); +#else void handleFeaturePermissionRequested(const QUrl &securityOrigin, Feature feature); +#endif void handleProxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth, const QString &proxyHost); void handleRegisterProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest request); #if !defined(QT_NO_SSL) || QTWEBENGINEWIDGETS_VERSION >= QT_VERSION_CHECK(5, 12, 0) From a5141d84ca1b4737b42133395fe6571945a4e7ca Mon Sep 17 00:00:00 2001 From: Vekhir Date: Thu, 21 Aug 2025 23:58:10 +0200 Subject: [PATCH 027/133] refactor: use different setContent overload The old version of setContent returns bool and takes in pointers to allow access to the error information. This was replaced in Qt 6.5 with a ParseResult struct which allows boolean checking and direct access to the information without additional pointers. The old version had separate overloads to specify whether to use namespace processing or not. This, among other options, can now be specified via ParseOptions which were introduced in Qt 6.5 too. --- src/adaptors/UBSvgSubsetAdaptor.cpp | 4 ++++ src/core/UBPersistenceManager.cpp | 12 +++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index 1a71d5b68..bf31e61e2 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -160,7 +160,11 @@ QDomDocument UBSvgSubsetAdaptor::loadSceneDocument(std::shared_ptr= QT_VERSION_CHECK(6, 5, 0)) + doc.setContent(&file, QDomDocument::ParseOption::UseNamespaceProcessing); +#else doc.setContent(&file, true); +#endif file.close(); } diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index 438b4dfcc..755c5921e 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -225,10 +225,16 @@ void UBPersistenceManager::createDocumentProxiesStructure(bool interactive) if (inFile.open(QIODevice::ReadOnly)) { QString domString(inFile.readAll()); - int errorLine = 0; int errorColumn = 0; +#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) + QDomDocument::ParseResult result = xmlDom.setContent(domString); + int errorLine = result.errorLine; + int errorColumn = result.errorColumn; +#else + int errorLine, errorColumn; QString errorStr; - - if (xmlDom.setContent(domString, &errorStr, &errorLine, &errorColumn)) { + bool result = xmlDom.setContent(domString, &errorStr, &errorLine, &errorColumn); +#endif + if (result) { loadFolderTreeFromXml("", xmlDom.firstChildElement()); } else { qDebug() << "Error reading content of " << mFoldersXmlStorageName << '\n' From 0e7a18468a272f0054f8e656ee280a1df0940ff4 Mon Sep 17 00:00:00 2001 From: Vekhir Date: Tue, 27 Aug 2024 20:29:14 +0200 Subject: [PATCH 028/133] refactor: Use QTimeZone instead of Qt::TimeSpec QDateTime::setTimeSpec is deprecated in Qt 6.9 per documentation, but already emits a warning in Qt 6.8. Anyway, use setTimeZone. --- src/frameworks/UBStringUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frameworks/UBStringUtils.cpp b/src/frameworks/UBStringUtils.cpp index 329ccd964..30e0def17 100644 --- a/src/frameworks/UBStringUtils.cpp +++ b/src/frameworks/UBStringUtils.cpp @@ -152,7 +152,7 @@ QDateTime UBStringUtils::fromUtcIsoDate(const QString& dateString) QString nonConstDateString = dateString; nonConstDateString.replace("ZZ", "Z"); QDateTime date = QDateTime::fromString(nonConstDateString, Qt::ISODate); - date.setTimeSpec(Qt::UTC); + date.setTimeZone(QTimeZone::utc()); return date.toLocalTime(); } From 01b57d9e66a4ed06e555c479982e1154710ec694 Mon Sep 17 00:00:00 2001 From: Vekhir Date: Fri, 22 Aug 2025 00:19:51 +0200 Subject: [PATCH 029/133] fix(UBBackgroundLoader): missing header --- src/frameworks/UBBackgroundLoader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frameworks/UBBackgroundLoader.cpp b/src/frameworks/UBBackgroundLoader.cpp index 8a1696f96..a12ef6107 100644 --- a/src/frameworks/UBBackgroundLoader.cpp +++ b/src/frameworks/UBBackgroundLoader.cpp @@ -22,6 +22,7 @@ #include "UBBackgroundLoader.h" +#include #include #include #include From fa401c158c2875ba8af68dc3eb56e33eb3057765 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Wed, 20 Aug 2025 07:40:00 +0200 Subject: [PATCH 030/133] perf: improve import - do not create thumbnail files during import - thumbnail files are created later when populating the thumbnails - do not save the TOC after each imported page - immediately use image after rendering thumbnail instead reading it from the file afterwards - only create a missing thumbnail when needed Signed-off-by: letsfindaway --- src/adaptors/UBThumbnailAdaptor.cpp | 64 +++++++---------------------- src/adaptors/UBThumbnailAdaptor.h | 4 +- src/core/UBDocumentManager.cpp | 16 ++++---- src/document/UBDocument.cpp | 27 ++++++++---- src/document/UBDocument.h | 4 +- src/gui/UBThumbnailScene.cpp | 22 +++++----- src/gui/UBThumbnailScene.h | 2 +- 7 files changed, 57 insertions(+), 82 deletions(-) diff --git a/src/adaptors/UBThumbnailAdaptor.cpp b/src/adaptors/UBThumbnailAdaptor.cpp index 4ea8fdc2c..99f5f589f 100644 --- a/src/adaptors/UBThumbnailAdaptor.cpp +++ b/src/adaptors/UBThumbnailAdaptor.cpp @@ -38,56 +38,20 @@ #include "core/memcheck.h" -void UBThumbnailAdaptor::generateMissingThumbnails(UBDocument* document) -{ - int existingPageCount = document->pageCount(); - - for (int iPageNo = 0; iPageNo < existingPageCount; ++iPageNo) - { - QString thumbFileName = document->thumbnailFile(iPageNo); - - if (!QFile::exists(thumbFileName)) - { - bool displayMessage = (existingPageCount > 5); - - int thumbCount = 0; - - std::shared_ptr scene = document->loadScene(iPageNo); - if (scene) - { - thumbCount++; - - if (displayMessage && thumbCount == 1) - UBApplication::showMessage(tr("Generating preview thumbnails ...")); - - persistScene(document, scene, iPageNo); - } - - if (displayMessage && thumbCount > 0) - UBApplication::showMessage(tr("%1 thumbnails generated ...").arg(thumbCount)); - - } - } -} QPixmap UBThumbnailAdaptor::generateMissingThumbnail(UBDocument* document, int pageIndex) { QString thumbFileName = document->thumbnailFile(pageIndex); - if (!QFile::exists(thumbFileName)) - { - std::shared_ptr scene = document->loadScene(pageIndex); + std::shared_ptr scene = document->loadScene(pageIndex); - if (scene) - { - persistScene(document, scene, pageIndex); - } + if (scene) + { + return persistScene(document, scene, pageIndex); } - QPixmap pix; - pix.load(thumbFileName); - return pix; + return {}; } QPixmap UBThumbnailAdaptor::get(UBDocument* document, int pageIndex) @@ -98,20 +62,15 @@ QPixmap UBThumbnailAdaptor::get(UBDocument* document, int pageIndex) if (!file.exists()) { - generateMissingThumbnails(document); + return generateMissingThumbnail(document, pageIndex); } QPixmap pix; - - if (file.exists()) - { - pix.load(fileName, 0, Qt::AutoColor); - } - + pix.load(fileName, 0, Qt::AutoColor); return pix; } -void UBThumbnailAdaptor::persistScene(UBDocument* document, std::shared_ptr pScene, int pageIndex, bool overrideModified) +QPixmap UBThumbnailAdaptor::persistScene(UBDocument* document, std::shared_ptr pScene, int pageIndex, bool overrideModified) { QString fileName = document->thumbnailFile(pageIndex); @@ -150,8 +109,13 @@ void UBThumbnailAdaptor::persistScene(UBDocument* document, std::shared_ptrsetRenderingContext(UBGraphicsScene::Screen); pScene->setRenderingQuality(UBItem::RenderingQualityNormal, UBItem::CacheAllowed); - thumb.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation).save(fileName, "JPG"); + const auto scaledThumb = thumb.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation); + scaledThumb.save(fileName, "JPG"); + + return QPixmap::fromImage(scaledThumb); } + + return {}; } diff --git a/src/adaptors/UBThumbnailAdaptor.h b/src/adaptors/UBThumbnailAdaptor.h index fbee4bf61..089121302 100644 --- a/src/adaptors/UBThumbnailAdaptor.h +++ b/src/adaptors/UBThumbnailAdaptor.h @@ -42,14 +42,12 @@ class UBThumbnailAdaptor //static class public: static QUrl thumbnailUrl(UBDocument* document, int pageIndex); - static void persistScene(UBDocument* document, std::shared_ptr pScene, int pageIndex, bool overrideModified = false); + static QPixmap persistScene(UBDocument* document, std::shared_ptr pScene, int pageIndex, bool overrideModified = false); static QPixmap get(UBDocument* document, int index); static QPixmap generateMissingThumbnail(UBDocument* document, int pageIndex); private: - static void generateMissingThumbnails(UBDocument* document); - UBThumbnailAdaptor() {} }; diff --git a/src/core/UBDocumentManager.cpp b/src/core/UBDocumentManager.cpp index ea48963bb..a6b501bca 100644 --- a/src/core/UBDocumentManager.cpp +++ b/src/core/UBDocumentManager.cpp @@ -27,9 +27,6 @@ #include "UBDocumentManager.h" -#include "document/UBDocument.h" -#include "frameworks/UBStringUtils.h" - #include "adaptors/UBExportFullPDF.h" #include "adaptors/UBExportDocument.h" #include "adaptors/UBExportWeb.h" @@ -44,8 +41,12 @@ #include "domain/UBGraphicsScene.h" #include "domain/UBMediaAssetItem.h" -#include "document/UBDocumentProxy.h" +#include "document/UBDocument.h" #include "document/UBDocumentController.h" +#include "document/UBDocumentProxy.h" +#include "document/UBDocumentToc.h" + +#include "frameworks/UBStringUtils.h" #include "gui/UBThumbnailScene.h" @@ -218,14 +219,14 @@ std::shared_ptr UBDocumentManager::importFile(const QFile& pFil //Workaround for issue 912 QApplication::processEvents(); #endif - std::shared_ptr scene = doc->createPage(pageIndex); + std::shared_ptr scene = doc->createPage(pageIndex, false); importAdaptor->placeImportedItemToScene(scene, page); - doc->persistPage(scene, pageIndex); + doc->persistPage(scene, pageIndex, false, false, false); pageIndex++; } UBPersistenceManager::persistenceManager()->persistDocumentMetadata(document); - doc->thumbnailScene()->createThumbnails(); + doc->toc()->save(); UBApplication::showMessage(tr("Import successful.")); } } @@ -306,6 +307,7 @@ int UBDocumentManager::addFilesToDocument(std::shared_ptr docum } UBPersistenceManager::persistenceManager()->persistDocumentMetadata(document); + doc->toc()->save(); UBApplication::showMessage(tr("Import of file %1 successful.").arg(file.fileName())); nImportedDocuments++; break; diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index 9bc934ae5..fd74eb233 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -31,6 +31,7 @@ #include "domain/UBMediaAssetItem.h" #include "frameworks/UBBackgroundLoader.h" #include "gui/UBMainWindow.h" +#include "gui/UBThumbnail.h" #include "gui/UBThumbnailScene.h" QList> UBDocument::sDocuments; @@ -172,25 +173,39 @@ void UBDocument::copyPage(int fromIndex, std::shared_ptr to, int toI copyPage(fromIndex, to.get(), toIndex); } -std::shared_ptr UBDocument::createPage(int index, bool useUndoRedoStack) +std::shared_ptr UBDocument::createPage(int index, bool saveToc, bool useUndoRedoStack) { // create a new TOC entry for the page assureLoaderFinished(); auto pageId = mToc->insert(index); auto scene = UBPersistenceManager::persistenceManager()->createDocumentSceneAt(mProxy, pageId, useUndoRedoStack); mToc->setUuid(index, scene->uuid()); - mToc->save(); - thumbnailScene()->insertThumbnail(index, scene); + if (saveToc) + { + mToc->save(); + } + + thumbnailScene()->insertThumbnail(index, false); return scene; } void UBDocument::persistPage(std::shared_ptr scene, int index, bool isAutomaticBackup, - bool forceImmediateSaving) + bool forceImmediateSaving, bool persistThumbnail) { const auto pageId = mToc->pageId(index); - UBThumbnailAdaptor::persistScene(this, scene, index); + + if (persistThumbnail) + { + const auto pixmap = UBThumbnailAdaptor::persistScene(this, scene, index); + + if (!pixmap.isNull()) + { + thumbnailScene()->thumbnailAt(index)->setPixmap(pixmap); + } + } + UBPersistenceManager::persistenceManager()->persistDocumentScene(mProxy, scene, pageId, isAutomaticBackup, forceImmediateSaving); @@ -201,8 +216,6 @@ void UBDocument::persistPage(std::shared_ptr scene, int index, mToc->setAssets(index, assets); mToc->save(); } - - thumbnailScene()->reloadThumbnail(index); } std::shared_ptr UBDocument::loadScene(int index, bool cacheNeighboringScenes) diff --git a/src/document/UBDocument.h b/src/document/UBDocument.h index b750a1515..7405c7781 100644 --- a/src/document/UBDocument.h +++ b/src/document/UBDocument.h @@ -63,9 +63,9 @@ class UBDocument : public std::enable_shared_from_this void duplicatePage(int index); void movePage(int fromIndex, int toIndex); void copyPage(int fromIndex, std::shared_ptr to, int toIndex); - std::shared_ptr createPage(int index, bool useUndoRedoStack = true); + std::shared_ptr createPage(int index, bool saveToc = true, bool useUndoRedoStack = true); void persistPage(std::shared_ptr scene, int index, bool isAutomaticBackup = false, - bool forceImmediateSaving = false); + bool forceImmediateSaving = false, bool persistThumbnail = true); std::shared_ptr loadScene(int index, bool cacheNeighboringScenes = true); std::shared_ptr getScene(int index); QList pageRelativeDependencies(int index); diff --git a/src/gui/UBThumbnailScene.cpp b/src/gui/UBThumbnailScene.cpp index 84f74305a..98477a393 100644 --- a/src/gui/UBThumbnailScene.cpp +++ b/src/gui/UBThumbnailScene.cpp @@ -245,21 +245,14 @@ void UBThumbnailScene::createThumbnails(int startIndex) /** * @brief Insert a thumbnail. * - * Insert a thumbnail at the given index. This function assumes that the thumbnail pixmap files - * are already moved to provide the necessary space. The pixmap for the new thumbnail can either - * be provided in the corresponding pixmap file or it will be created from the scene. + * Insert a thumbnail at the given index. * * @param pageIndex Page index of the scene. - * @param pageScene Optional scene. If this parameter is provided, then the tumbnail pixmap is - * created from the scene. Otherwise it is assumed that the pixmap file already exists. + * @param loadThumbnail If true, load the thumbnail from the file (default). + * If false, only an empty thumbnail is created which will be filled later. */ -void UBThumbnailScene::insertThumbnail(int pageIndex, std::shared_ptr pageScene) +void UBThumbnailScene::insertThumbnail(int pageIndex, bool loadThumbnail) { - if (pageScene) - { - UBThumbnailAdaptor::persistScene(mDocument, pageScene, pageIndex); - } - if (pageIndex <= mThumbnailItems.size()) { if (mThumbnailItems.size() == 1) @@ -269,7 +262,12 @@ void UBThumbnailScene::insertThumbnail(int pageIndex, std::shared_ptrsetPixmap(UBThumbnailAdaptor::get(mDocument, pageIndex)); + if (loadThumbnail) + { + const auto pixmap = UBThumbnailAdaptor::get(mDocument, pageIndex); + thumbnailItem->setPixmap(pixmap); + } + thumbnailItem->setSceneIndex(pageIndex); mThumbnailItems.insert(pageIndex, thumbnailItem); diff --git a/src/gui/UBThumbnailScene.h b/src/gui/UBThumbnailScene.h index c566a08de..b39e70ca6 100644 --- a/src/gui/UBThumbnailScene.h +++ b/src/gui/UBThumbnailScene.h @@ -63,7 +63,7 @@ class UBThumbnailScene : public QGraphicsScene protected: // only to be called from UBDocument friend class UBDocument; - void insertThumbnail(int pageIndex, std::shared_ptr pageScene = nullptr); + void insertThumbnail(int pageIndex, bool loadThumbnail = true); void deleteThumbnail(int pageIndex, bool rearrange = true); void moveThumbnail(int fromIndex, int toIndex); void reloadThumbnail(int pageIndex); From 9c4c49516a8a5eed1c4fb06e073c84177b0ed1d3 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Wed, 20 Aug 2025 11:20:33 +0200 Subject: [PATCH 031/133] fix: use media asset uuid when importing - create media asset uuid in UBPersistenceManager::addFileToDocument - return uuid on success Signed-off-by: letsfindaway --- src/board/UBBoardController.cpp | 12 ++++-------- src/core/UBDocumentManager.cpp | 16 ++++++++-------- src/core/UBDownloadManager.cpp | 2 -- src/core/UBPersistenceManager.cpp | 30 +++++++++++++++--------------- src/core/UBPersistenceManager.h | 2 +- 5 files changed, 28 insertions(+), 34 deletions(-) diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index a8fe9e609..02cb0c489 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -1385,15 +1385,13 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl if (pData.length() > 0) { - QUuid uuid = UBMediaAssetItem::createMediaAssetUuid(pData); QString destFile; - bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(selectedDocument(), + const auto uuid = UBPersistenceManager::persistenceManager()->addFileToDocument(selectedDocument(), sourceUrl.toString(), UBPersistenceManager::videoDirectory, - uuid, destFile, &pData); - if (!b) + if (uuid.isNull()) { UBApplication::showMessage(tr("Add file operation failed: file copying error")); return NULL; @@ -1429,15 +1427,13 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl if (pData.length() > 0) { - QUuid uuid = UBMediaAssetItem::createMediaAssetUuid(pData); QString destFile; - bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(selectedDocument(), + const auto uuid = UBPersistenceManager::persistenceManager()->addFileToDocument(selectedDocument(), sourceUrl.toString(), UBPersistenceManager::audioDirectory, - uuid, destFile, &pData); - if (!b) + if (uuid.isNull()) { UBApplication::showMessage(tr("Add file operation failed: file copying error")); return NULL; diff --git a/src/core/UBDocumentManager.cpp b/src/core/UBDocumentManager.cpp index a6b501bca..fed35a07e 100644 --- a/src/core/UBDocumentManager.cpp +++ b/src/core/UBDocumentManager.cpp @@ -39,7 +39,6 @@ #include "board/UBBoardController.h" #include "domain/UBGraphicsScene.h" -#include "domain/UBMediaAssetItem.h" #include "document/UBDocument.h" #include "document/UBDocumentController.h" @@ -197,18 +196,19 @@ std::shared_ptr UBDocumentManager::importFile(const QFile& pFil if (document) { auto doc = UBDocument::getDocument(document); - QUuid uuid = QUuid::createUuid(); QString filepath = pFile.fileName(); + QUuid uuid; if (importAdaptor->folderToCopy() != "") { - bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(document, pFile.fileName(), importAdaptor->folderToCopy() , uuid, filepath); - if (!b) + uuid = UBPersistenceManager::persistenceManager()->addFileToDocument(document, pFile.fileName(), importAdaptor->folderToCopy(), filepath); + if (uuid.isNull()) { UBApplication::setDisabled(false); return NULL; } } + // NOTE when folderToCopy returns empty string, uuid parameter is not used for import QList pages = importAdaptor->import(uuid, filepath); int pageIndex = 0; @@ -276,25 +276,25 @@ int UBDocumentManager::addFilesToDocument(std::shared_ptr docum UBPageBasedImportAdaptor* importAdaptor = (UBPageBasedImportAdaptor*)adaptor; QByteArray data; - QUuid uuid = QUuid::createUuid(); if (file.open(QFile::ReadOnly)) { data = file.readAll(); file.close(); - uuid = UBMediaAssetItem::createMediaAssetUuid(data); } QString filepath = file.fileName(); + QUuid uuid; if (importAdaptor->folderToCopy() != "") { - bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(document, file.fileName(), importAdaptor->folderToCopy() , uuid, filepath); - if (!b) + uuid = UBPersistenceManager::persistenceManager()->addFileToDocument(document, file.fileName(), importAdaptor->folderToCopy(), filepath); + if (uuid.isNull()) { continue; } } + // NOTE when folderToCopy returns empty string, uuid parameter is not used for import QList pages = importAdaptor->import(uuid, filepath); int nPage = 0; foreach(UBGraphicsItem* page, pages) diff --git a/src/core/UBDownloadManager.cpp b/src/core/UBDownloadManager.cpp index be29da71d..5a8b19361 100644 --- a/src/core/UBDownloadManager.cpp +++ b/src/core/UBDownloadManager.cpp @@ -79,11 +79,9 @@ void UBAsyncLocalFileDownloader::run() if (mDesc.originalSrcUrl.isEmpty()) mDesc.originalSrcUrl = mDesc.srcUrl; - QUuid uuid = QUuid::createUuid(); UBPersistenceManager::persistenceManager()->addFileToDocument(UBApplication::boardController->selectedDocument(), mDesc.srcUrl, destDirectory, - uuid, mTo, NULL); diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index 438b4dfcc..e32b91fe4 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -27,6 +27,7 @@ #include "UBPersistenceManager.h" +#include "domain/UBMediaAssetItem.h" #include "gui/UBMainWindow.h" #include @@ -985,22 +986,21 @@ bool UBPersistenceManager::addDirectoryContentToDocument(const QString& document } -bool UBPersistenceManager::addFileToDocument(std::shared_ptr pDocumentProxy, - QString path, - const QString& subdir, - QUuid objectUuid, - QString& destinationPath, - QByteArray* data) +QUuid UBPersistenceManager::addFileToDocument(std::shared_ptr pDocumentProxy, + QString path, // full path of source file + const QString& subdir, // target subdir in document + QString& destinationPath, // return value for absolute destination path + QByteArray* data) // optional file data { Q_ASSERT(path.length()); QFileInfo fi(path); - if (!pDocumentProxy || objectUuid.isNull()) - return false; + if (!pDocumentProxy) + return {}; if (data == NULL && !fi.exists()) - return false; + return {}; - qDebug() << fi.suffix(); + QUuid objectUuid = data ? UBMediaAssetItem::createMediaAssetUuid(*data) : UBMediaAssetItem::createMediaAssetUuid(path); QString fileName = subdir + "/" + objectUuid.toString() + "." + fi.suffix(); @@ -1011,12 +1011,12 @@ bool UBPersistenceManager::addFileToDocument(std::shared_ptr pD QDir dir; dir.mkdir(pDocumentProxy->persistencePath() + "/" + subdir); if (!QFile::exists(pDocumentProxy->persistencePath() + "/" + subdir)) - return false; + return {}; if (data == NULL) { QFile source(path); - return source.copy(destinationPath); + return source.copy(destinationPath) ? objectUuid : QUuid{}; } else { @@ -1027,17 +1027,17 @@ bool UBPersistenceManager::addFileToDocument(std::shared_ptr pD qint64 n = newFile.write(*data); newFile.flush(); newFile.close(); - return n == data->size(); + return n == data->size() ? objectUuid : QUuid{}; } else { - return false; + return {}; } } } else { - return true; + return objectUuid; } } diff --git a/src/core/UBPersistenceManager.h b/src/core/UBPersistenceManager.h index 0a4f7554c..14dffb190 100644 --- a/src/core/UBPersistenceManager.h +++ b/src/core/UBPersistenceManager.h @@ -142,7 +142,7 @@ class UBPersistenceManager : public QObject } bool addGraphicsWidgetToDocument(std::shared_ptr mDocumentProxy, QString path, QUuid objectUuid, QString& destinationPath); - bool addFileToDocument(std::shared_ptr pDocumentProxy, QString path, const QString& subdir, QUuid objectUuid, QString& destinationPath, QByteArray* data = NULL); + QUuid addFileToDocument(std::shared_ptr pDocumentProxy, QString path, const QString& subdir, QString& destinationPath, QByteArray* data = NULL); bool mayHaveVideo(std::shared_ptr pDocumentProxy); bool mayHaveAudio(std::shared_ptr pDocumentProxy); From e3ac2dc3fa5285c1f439269c89119552f4ec9f9b Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Wed, 20 Aug 2025 11:33:42 +0200 Subject: [PATCH 032/133] perf: avoid repeated check for PDF file - do not check for existence of PDF file when writing SVG - assume file always exists - there is no way to create a PDF item without an existing file - use media assets instead of hardcoded directory strings Signed-off-by: letsfindaway --- src/adaptors/UBSvgSubsetAdaptor.cpp | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index 1a71d5b68..db98af0d6 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -2264,25 +2264,7 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::pdfItemToLinkedPDF(UBGraphicsPDFItem mXmlWriter.writeStartElement("foreignObject"); mXmlWriter.writeAttribute("requiredExtensions", "http://ns.adobe.com/pdf/1.3/"); - QString fileName = UBPersistenceManager::objectDirectory + "/" + pdfItem->fileUuid().toString() + ".pdf"; - - QString path = mDocumentPath + "/" + fileName; - - if (!QFile::exists(path)) - { - QDir dir; - dir.mkdir(mDocumentPath + "/" + UBPersistenceManager::objectDirectory); - - QFile file(path); - if (!file.open(QIODevice::WriteOnly)) - { - qWarning() << "cannot open file for writing embeded pdf content " << path; - return; - } - - file.write(pdfItem->fileData()); - file.close(); - } + const auto fileName = pdfItem->mediaAssets().at(0); mXmlWriter.writeAttribute(nsXLink, "href", fileName + "#page=" + QString::number(pdfItem->pageNumber())); @@ -2328,7 +2310,7 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::audioItemToLinkedAudio(UBGraphicsAud mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "position", QString("%1").arg(pos)); } - QString audioFileHref = "audios/" + audioItem->mediaFileUrl().fileName(); + QString audioFileHref = audioItem->mediaAssets().at(0); mXmlWriter.writeAttribute(nsXLink, "href", audioFileHref); mXmlWriter.writeEndElement(); @@ -2355,7 +2337,7 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::videoItemToLinkedVideo(UBGraphicsVid mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "position", QString("%1").arg(pos)); } - QString videoFileHref = "videos/" + videoItem->mediaFileUrl().fileName(); + QString videoFileHref = videoItem->mediaAssets().at(0); mXmlWriter.writeAttribute(nsXLink, "href", videoFileHref); mXmlWriter.writeEndElement(); From 2a84cf87914327baddaa1fbc968cb0cb646fdefb Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Thu, 21 Aug 2025 15:47:14 +0200 Subject: [PATCH 033/133] perf: improve thumbnail scanning and loading - enable use of uncached scenes - avoid saving the TOC after each page - keep UBDocument alive after import - delay scanning of pages and loading of thumbnails for better user experience - do not scale image to its already correct size Signed-off-by: letsfindaway --- src/adaptors/UBThumbnailAdaptor.cpp | 28 ++++++++++++---- src/adaptors/UBThumbnailAdaptor.h | 2 +- src/core/UBApplicationController.cpp | 3 +- src/core/UBDocumentManager.cpp | 27 +++++++++++---- src/core/UBDocumentManager.h | 3 +- src/core/UBPersistenceManager.cpp | 26 ++++++++++++--- src/core/UBPersistenceManager.h | 5 +-- src/document/UBDocument.cpp | 48 +++++++++++++++++++++------ src/document/UBDocument.h | 6 ++-- src/document/UBDocumentController.cpp | 4 +-- src/gui/UBThumbnailScene.cpp | 44 +++++++++++++++++++----- src/gui/UBThumbnailScene.h | 1 + 12 files changed, 150 insertions(+), 47 deletions(-) diff --git a/src/adaptors/UBThumbnailAdaptor.cpp b/src/adaptors/UBThumbnailAdaptor.cpp index 99f5f589f..d198b2ebe 100644 --- a/src/adaptors/UBThumbnailAdaptor.cpp +++ b/src/adaptors/UBThumbnailAdaptor.cpp @@ -40,15 +40,32 @@ -QPixmap UBThumbnailAdaptor::generateMissingThumbnail(UBDocument* document, int pageIndex) +QPixmap UBThumbnailAdaptor::generateMissingThumbnail(UBDocument* document, int pageIndex, UBGraphicsScene* scene) { QString thumbFileName = document->thumbnailFile(pageIndex); - std::shared_ptr scene = document->loadScene(pageIndex); + if (QFile::exists(thumbFileName)) + { + QPixmap pix; + pix.load(thumbFileName, 0, Qt::AutoColor); + return pix; + } + + std::shared_ptr scenePtr; if (scene) { - return persistScene(document, scene, pageIndex); + scenePtr = scene->shared_from_this(); + } + + if (!scenePtr) + { + scenePtr = document->loadScene(pageIndex, false); + } + + if (scenePtr) + { + return persistScene(document, scenePtr, pageIndex); } return {}; @@ -109,10 +126,9 @@ QPixmap UBThumbnailAdaptor::persistScene(UBDocument* document, std::shared_ptrsetRenderingContext(UBGraphicsScene::Screen); pScene->setRenderingQuality(UBItem::RenderingQualityNormal, UBItem::CacheAllowed); - const auto scaledThumb = thumb.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation); - scaledThumb.save(fileName, "JPG"); + thumb.save(fileName, "JPG"); - return QPixmap::fromImage(scaledThumb); + return QPixmap::fromImage(thumb); } return {}; diff --git a/src/adaptors/UBThumbnailAdaptor.h b/src/adaptors/UBThumbnailAdaptor.h index 089121302..d4b63c714 100644 --- a/src/adaptors/UBThumbnailAdaptor.h +++ b/src/adaptors/UBThumbnailAdaptor.h @@ -45,7 +45,7 @@ class UBThumbnailAdaptor //static class static QPixmap persistScene(UBDocument* document, std::shared_ptr pScene, int pageIndex, bool overrideModified = false); static QPixmap get(UBDocument* document, int index); - static QPixmap generateMissingThumbnail(UBDocument* document, int pageIndex); + static QPixmap generateMissingThumbnail(UBDocument* document, int pageIndex, UBGraphicsScene* scene = {}); private: UBThumbnailAdaptor() {} diff --git a/src/core/UBApplicationController.cpp b/src/core/UBApplicationController.cpp index 782e81f4c..8bf788ea6 100644 --- a/src/core/UBApplicationController.cpp +++ b/src/core/UBApplicationController.cpp @@ -708,7 +708,8 @@ void UBApplicationController::importFile(const QString& pFilePath) bool success = false; - std::shared_ptr document = UBDocumentManager::documentManager()->importFile(fileToOpen, ""); + std::shared_ptr doc = UBDocumentManager::documentManager()->importFile(fileToOpen, ""); + std::shared_ptr document = doc->proxy(); success = (document != 0); diff --git a/src/core/UBDocumentManager.cpp b/src/core/UBDocumentManager.cpp index fed35a07e..963de8065 100644 --- a/src/core/UBDocumentManager.cpp +++ b/src/core/UBDocumentManager.cpp @@ -162,7 +162,7 @@ QFileInfoList UBDocumentManager::importUbx(const QString &Incomingfile, const QS return docSetAdaptor->importData(Incomingfile, destination); } -std::shared_ptr UBDocumentManager::importFile(const QFile& pFile, const QString& pGroup) +std::shared_ptr UBDocumentManager::importFile(const QFile& pFile, const QString& pGroup) { QFileInfo fileInfo(pFile); @@ -171,6 +171,7 @@ std::shared_ptr UBDocumentManager::importFile(const QFile& pFil if (adaptor->supportedExtentions().lastIndexOf(fileInfo.suffix().toLower()) != -1) { std::shared_ptr document; + std::shared_ptr doc; UBApplication::setDisabled(true); if (adaptor->isDocumentBased()) @@ -178,7 +179,7 @@ std::shared_ptr UBDocumentManager::importFile(const QFile& pFil UBDocumentBasedImportAdaptor* importAdaptor = (UBDocumentBasedImportAdaptor*)adaptor; document = importAdaptor->importFile(pFile, pGroup); - + doc = UBDocument::getDocument(document); } else { @@ -195,7 +196,7 @@ std::shared_ptr UBDocumentManager::importFile(const QFile& pFil if (document) { - auto doc = UBDocument::getDocument(document); + doc = UBDocument::getDocument(document); QString filepath = pFile.fileName(); QUuid uuid; if (importAdaptor->folderToCopy() != "") @@ -213,26 +214,38 @@ std::shared_ptr UBDocumentManager::importFile(const QFile& pFil int pageIndex = 0; UBApplication::showMessage(tr("Creating %1 pages. Please wait...").arg(pages.size()), true); + + // create the thumbnail scene before any pages are created + doc->thumbnailScene(false); + foreach(UBGraphicsItem* page, pages) { #ifdef Q_WS_MACX //Workaround for issue 912 QApplication::processEvents(); #endif - std::shared_ptr scene = doc->createPage(pageIndex, false); + std::shared_ptr scene = doc->createPage(pageIndex, false, false); importAdaptor->placeImportedItemToScene(scene, page); - doc->persistPage(scene, pageIndex, false, false, false); + doc->persistPage(scene, pageIndex, false, false, false, false); pageIndex++; } UBPersistenceManager::persistenceManager()->persistDocumentMetadata(document); + + // remove all asset entries to force scanning + for (int index = 0; index < doc->pageCount(); ++index) + { + doc->toc()->unsetAssets(index); + } + doc->toc()->save(); + doc->scanAssets(); UBApplication::showMessage(tr("Import successful.")); } } UBApplication::setDisabled(false); - return document; + return doc; } } @@ -303,7 +316,7 @@ int UBDocumentManager::addFilesToDocument(std::shared_ptr docum int pageIndex = doc->pageCount(); std::shared_ptr scene = doc->createPage(pageIndex); importAdaptor->placeImportedItemToScene(scene, page); - doc->persistPage(scene, pageIndex); + doc->persistPage(scene, pageIndex, false, false, false, false); } UBPersistenceManager::persistenceManager()->persistDocumentMetadata(document); diff --git a/src/core/UBDocumentManager.h b/src/core/UBDocumentManager.h index c4209f4b8..8939392a8 100644 --- a/src/core/UBDocumentManager.h +++ b/src/core/UBDocumentManager.h @@ -34,6 +34,7 @@ class UBExportAdaptor; class UBImportAdaptor; +class UBDocument; class UBDocumentProxy; @@ -51,7 +52,7 @@ class UBDocumentManager : public QObject QStringList importFileExtensions(bool notUbx = false); QFileInfoList importUbx(const QString &Incomingfile, const QString &destination); - std::shared_ptr importFile(const QFile& pFile, const QString& pGroup); + std::shared_ptr importFile(const QFile& pFile, const QString& pGroup); int addFilesToDocument(std::shared_ptr pDocument, QStringList fileNames); diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index e32b91fe4..2338c2856 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -804,16 +804,28 @@ QUuid UBPersistenceManager::copyDocumentScene(std::shared_ptr f } -std::shared_ptr UBPersistenceManager::createDocumentSceneAt(std::shared_ptr proxy, int pageId, bool useUndoRedoStack) +std::shared_ptr UBPersistenceManager::createDocumentSceneAt(std::shared_ptr proxy, int pageId, bool cached, bool useUndoRedoStack) { - std::shared_ptr newScene = mSceneCache.createScene(proxy, pageId, useUndoRedoStack); + std::shared_ptr newScene; + + if (cached) + { + newScene = mSceneCache.createScene(proxy, pageId, useUndoRedoStack); + } + else + { + newScene = std::make_shared(proxy, useUndoRedoStack); + } newScene->setBackground(UBSettings::settings()->isDarkBackground(), UBSettings::settings()->UBSettings::pageBackground()); newScene->setBackgroundGridSize(UBSettings::settings()->crossSize); - persistDocumentScene(proxy, newScene, pageId); + if (cached) + { + persistDocumentScene(proxy, newScene, pageId); + } return newScene; } @@ -868,7 +880,8 @@ void UBPersistenceManager::cleanupMediaAssets(std::shared_ptr p } } -void UBPersistenceManager::persistDocumentScene(std::shared_ptr pDocumentProxy, std::shared_ptr pScene, int pageId, bool isAnAutomaticBackup, bool forceImmediateSaving) +void UBPersistenceManager::persistDocumentScene(std::shared_ptr pDocumentProxy, std::shared_ptr pScene, int pageId, + bool isAnAutomaticBackup, bool forceImmediateSaving, bool addToCache) { checkIfDocumentRepositoryExists(); @@ -895,7 +908,10 @@ void UBPersistenceManager::persistDocumentScene(std::shared_ptr pScene->setModified(false); - mSceneCache.insert(pDocumentProxy, pageId, pScene); + if (addToCache) + { + mSceneCache.insert(pDocumentProxy, pageId, pScene); + } } diff --git a/src/core/UBPersistenceManager.h b/src/core/UBPersistenceManager.h index 14dffb190..f87e309b5 100644 --- a/src/core/UBPersistenceManager.h +++ b/src/core/UBPersistenceManager.h @@ -101,9 +101,10 @@ class UBPersistenceManager : public QObject virtual QUuid copyDocumentScene(std::shared_ptrfrom, int fromPageId, std::shared_ptrto, int toPageId, QList dependencies); - virtual void persistDocumentScene(std::shared_ptr pDocumentProxy, std::shared_ptr pScene, int pageId, bool isAnAutomaticBackup = false, bool forceImmediateSaving = false); + virtual void persistDocumentScene(std::shared_ptr pDocumentProxy, std::shared_ptr pScene, int pageId, + bool isAnAutomaticBackup = false, bool forceImmediateSaving = false, bool addToCache = true); - virtual std::shared_ptr createDocumentSceneAt(std::shared_ptr pDocumentProxy, int pageId, bool useUndoRedoStack = true); + virtual std::shared_ptr createDocumentSceneAt(std::shared_ptr pDocumentProxy, int pageId, bool cached = true, bool useUndoRedoStack = true); virtual std::shared_ptr loadDocumentScene(std::shared_ptr pDocumentProxy, int pageId); std::shared_ptr prepareSceneLoading(std::shared_ptr proxy, int pageId, std::optional xmlContent = {}, bool cached = true); diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index fd74eb233..aa9e3fb7b 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -173,12 +173,12 @@ void UBDocument::copyPage(int fromIndex, std::shared_ptr to, int toI copyPage(fromIndex, to.get(), toIndex); } -std::shared_ptr UBDocument::createPage(int index, bool saveToc, bool useUndoRedoStack) +std::shared_ptr UBDocument::createPage(int index, bool saveToc, bool cached, bool useUndoRedoStack) { // create a new TOC entry for the page assureLoaderFinished(); auto pageId = mToc->insert(index); - auto scene = UBPersistenceManager::persistenceManager()->createDocumentSceneAt(mProxy, pageId, useUndoRedoStack); + auto scene = UBPersistenceManager::persistenceManager()->createDocumentSceneAt(mProxy, pageId, cached, useUndoRedoStack); mToc->setUuid(index, scene->uuid()); if (saveToc) @@ -192,7 +192,7 @@ std::shared_ptr UBDocument::createPage(int index, bool saveToc, } void UBDocument::persistPage(std::shared_ptr scene, int index, bool isAutomaticBackup, - bool forceImmediateSaving, bool persistThumbnail) + bool forceImmediateSaving, bool persistThumbnail, bool addToCache) { const auto pageId = mToc->pageId(index); @@ -207,14 +207,19 @@ void UBDocument::persistPage(std::shared_ptr scene, int index, } UBPersistenceManager::persistenceManager()->persistDocumentScene(mProxy, scene, pageId, isAutomaticBackup, - forceImmediateSaving); + forceImmediateSaving, addToCache); const auto assets = scene->relativeDependencies(); if (assets != mToc->assets(index)) { mToc->setAssets(index, assets); - mToc->save(); + + if (addToCache) + { + // when scene is cached it is also time to save the TOC + mToc->save(); + } } } @@ -267,12 +272,16 @@ QList UBDocument::pageRelativeDependencies(int index) return {}; } -UBThumbnailScene* UBDocument::thumbnailScene() +UBThumbnailScene* UBDocument::thumbnailScene(bool startLoader) { if (!mThumbnailScene) { mThumbnailScene = std::unique_ptr(new UBThumbnailScene(this)); - mThumbnailScene->createThumbnails(); + + if (startLoader) + { + mThumbnailScene->createThumbnails(); + } } return mThumbnailScene.get(); @@ -292,6 +301,18 @@ UBDocumentToc* UBDocument::toc() scan(tocPresent); mToc->save(); } + else + { + // scan assets if missing + for (int index = 0; index < mToc->pageCount(); ++index) + { + if (!mToc->hasAssetsEntry(index)) + { + scanAssets(); + break; + } + } + } } return mToc; @@ -385,11 +406,16 @@ void UBDocument::sceneLoaded(UBGraphicsScene* scene, std::shared_ptr handl persistenceManager->persistDocumentScene(mProxy, scene->shared_from_this(), mToc->pageId(index)); } + // generate and load thumbnail from scene if not already existing and loaded + mThumbnailScene->ensureThumbnail(index, scene); + // prepare next scene - if (mSceneAssetLoader) - { - mSceneAssetLoader->resultProcessed(index); - } + QTimer::singleShot(5, mSceneAssetLoader, [this, index](){ + if (mSceneAssetLoader) + { + mSceneAssetLoader->resultProcessed(index); + } + }); } void UBDocument::scanAssets() diff --git a/src/document/UBDocument.h b/src/document/UBDocument.h index 7405c7781..1d75e3e0c 100644 --- a/src/document/UBDocument.h +++ b/src/document/UBDocument.h @@ -63,13 +63,13 @@ class UBDocument : public std::enable_shared_from_this void duplicatePage(int index); void movePage(int fromIndex, int toIndex); void copyPage(int fromIndex, std::shared_ptr to, int toIndex); - std::shared_ptr createPage(int index, bool saveToc = true, bool useUndoRedoStack = true); + std::shared_ptr createPage(int index, bool saveToc = true, bool cached = true, bool useUndoRedoStack = true); void persistPage(std::shared_ptr scene, int index, bool isAutomaticBackup = false, - bool forceImmediateSaving = false, bool persistThumbnail = true); + bool forceImmediateSaving = false, bool persistThumbnail = true, bool addToCache = true); std::shared_ptr loadScene(int index, bool cacheNeighboringScenes = true); std::shared_ptr getScene(int index); QList pageRelativeDependencies(int index); - UBThumbnailScene* thumbnailScene(); + UBThumbnailScene* thumbnailScene(bool startLoader = true); UBDocumentToc* toc(); int pageCount(); diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index ec4ba3f19..f83844c32 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -3107,7 +3107,7 @@ void UBDocumentController::importFile() if (filePath.length() > 0) { - std::shared_ptr createdDocument = nullptr; + std::shared_ptr createdDocument = nullptr; QApplication::processEvents(); QFile selectedFile(filePath); @@ -3127,7 +3127,7 @@ void UBDocumentController::importFile() createdDocument = docManager->importFile(selectedFile, groupName); if (createdDocument && !multipleFilesImported) { - selectDocument(createdDocument, true, true, true); + selectDocument(createdDocument->proxy(), true, true, true); pageSelectionChanged(); } else { diff --git a/src/gui/UBThumbnailScene.cpp b/src/gui/UBThumbnailScene.cpp index 98477a393..538e27df7 100644 --- a/src/gui/UBThumbnailScene.cpp +++ b/src/gui/UBThumbnailScene.cpp @@ -23,9 +23,8 @@ #include "UBThumbnailScene.h" #include "adaptors/UBThumbnailAdaptor.h" -#include "core/UBApplication.h" #include "document/UBDocument.h" -#include "document/UBDocumentProxy.h" +#include "document/UBDocumentToc.h" #include "frameworks/UBBackgroundLoader.h" #include "gui/UBThumbnail.h" #include "gui/UBThumbnailArranger.h" @@ -204,8 +203,12 @@ void UBThumbnailScene::createThumbnails(int startIndex) for (int index = startIndex; index < mDocument->pageCount(); ++index) { - const auto thumbnailPath = UBThumbnailAdaptor::thumbnailUrl(mDocument, index).toLocalFile(); - paths << std::pair{index, thumbnailPath}; + // only load thumbnails for pages with assets, others are loaded while scanning + if (mDocument->toc()->hasAssetsEntry(index)) + { + const auto thumbnailPath = UBThumbnailAdaptor::thumbnailUrl(mDocument, index).toLocalFile(); + paths << std::pair{index, thumbnailPath}; + } } // start background loading of files @@ -228,10 +231,12 @@ void UBThumbnailScene::createThumbnails(int startIndex) // now create all missing thumbnails for document as they arrive from the loader loadThumbnail(index, data); - if (mLoader) - { - mLoader->resultProcessed(index); - } + QTimer::singleShot(5, this, [this, index](){ + if (mLoader) + { + mLoader->resultProcessed(index); + } + }); }); connect(mLoader, &UBBackgroundLoader::finished, this, [this](){ // delete loader @@ -360,6 +365,29 @@ void UBThumbnailScene::reloadThumbnail(int pageIndex) } } +void UBThumbnailScene::ensureThumbnail(int pageIndex, UBGraphicsScene* scene) +{ + if (pageIndex < mThumbnailItems.size()) + { + auto thumbnailItem = mThumbnailItems.at(pageIndex); + + if (!thumbnailItem || thumbnailItem->pixmap().isNull()) + { + QPixmap pixmap = UBThumbnailAdaptor::generateMissingThumbnail(mDocument, pageIndex, scene); + + thumbnailItem = new UBThumbnail; + + thumbnailItem->setPixmap(pixmap); + thumbnailItem->setSceneIndex(pageIndex); + + mThumbnailItems[pageIndex] = thumbnailItem; + addItem(thumbnailItem); + + arrangeThumbnails(pageIndex, pageIndex + 1); + } + } +} + UBThumbnailArranger* UBThumbnailScene::currentThumbnailArranger() { UBThumbnailArranger* thumbnailArranger{nullptr}; diff --git a/src/gui/UBThumbnailScene.h b/src/gui/UBThumbnailScene.h index b39e70ca6..4c3d0e50d 100644 --- a/src/gui/UBThumbnailScene.h +++ b/src/gui/UBThumbnailScene.h @@ -67,6 +67,7 @@ class UBThumbnailScene : public QGraphicsScene void deleteThumbnail(int pageIndex, bool rearrange = true); void moveThumbnail(int fromIndex, int toIndex); void reloadThumbnail(int pageIndex); + void ensureThumbnail(int pageIndex, UBGraphicsScene* scene); private: friend class UBThumbnail; From e3e78f9462de0179d38a7d2ce3452e71ae5a03e7 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Fri, 22 Aug 2025 14:53:26 +0200 Subject: [PATCH 034/133] feat/fix: creating and loading thumbnails - allow to add a precondition executed before each loader task - use precondition to check for scene file existence - remove unused parameter from resultProcessed - insert placeholder thumbnails when loading document - avoid race condition when keeping copied scenes alive - fix creating initial thumbnail on new document Signed-off-by: letsfindaway --- src/core/UBPersistenceManager.cpp | 3 ++- src/document/UBDocument.cpp | 33 +++++++++++++++++++-------- src/document/UBDocument.h | 3 ++- src/frameworks/UBBackgroundLoader.cpp | 16 +++++++++---- src/frameworks/UBBackgroundLoader.h | 7 +++--- src/frameworks/UBBlockingBuffer.cpp | 2 +- src/frameworks/UBBlockingBuffer.h | 2 +- src/gui/UBThumbnailScene.cpp | 26 ++++++++++++++------- 8 files changed, 62 insertions(+), 30 deletions(-) diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index 2338c2856..ad235aee9 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -900,10 +900,11 @@ void UBPersistenceManager::persistDocumentScene(std::shared_ptr else { std::shared_ptr copiedScene = pScene->sceneDeepCopy(); - mWorker->saveScene(pDocumentProxy, copiedScene.get(), pageId); // keep copiedScene alive until saving is finished mScenesToSave.append(copiedScene); + + mWorker->saveScene(pDocumentProxy, copiedScene.get(), pageId); } pScene->setModified(false); diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index aa9e3fb7b..1f1e777c0 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -413,7 +413,7 @@ void UBDocument::sceneLoaded(UBGraphicsScene* scene, std::shared_ptr handl QTimer::singleShot(5, mSceneAssetLoader, [this, index](){ if (mSceneAssetLoader) { - mSceneAssetLoader->resultProcessed(index); + mSceneAssetLoader->resultProcessed(); } }); } @@ -431,7 +431,7 @@ void UBDocument::scanAssets() if (!mToc->hasAssetsEntry(index)) { int pageId = mToc->pageId(index); - paths.append({index, mProxy->persistencePath() + persistenceManager->sceneFilenameForId(pageId)}); + paths.append({pageId, mProxy->persistencePath() + persistenceManager->sceneFilenameForId(pageId)}); } } @@ -441,13 +441,19 @@ void UBDocument::scanAssets() // load scenes for scanning mSceneAssetLoader = new UBBackgroundLoader; - QObject::connect(mSceneAssetLoader, &UBBackgroundLoader::resultAvailable, mSceneAssetLoader, [this](int index, const QByteArray& data){ - UBApplication::showMessage(UBDocumentController::tr("Scanning page %1 of %2").arg(index).arg(mToc->pageCount()), true); - - const auto pageId = mToc->pageId(index); + QObject::connect(mSceneAssetLoader, &UBBackgroundLoader::resultAvailable, mSceneAssetLoader, [this](int pageId, const QByteArray& data){ + UBApplication::showMessage(UBDocumentController::tr("Scanning page %1 of %2").arg(pageId).arg(mToc->pageCount()), true); if (pageId >= 0 && !data.isEmpty()) { + auto scene = UBPersistenceManager::persistenceManager()->getDocumentScene(mProxy, pageId); + + if (scene) + { + sceneLoaded(scene.get(), nullptr); + return; + } + const auto handle = UBPersistenceManager::persistenceManager()->prepareSceneLoading(mProxy, pageId, data, false); if (handle) @@ -459,7 +465,7 @@ void UBDocument::scanAssets() } // page deleted or already in cache, loading not necessary - mSceneAssetLoader->resultProcessed(index); + mSceneAssetLoader->resultProcessed(); }); QObject::connect(mSceneAssetLoader, &UBBackgroundLoader::finished, mSceneAssetLoader, [this](){ @@ -467,7 +473,14 @@ void UBDocument::scanAssets() qDebug() << "Asset scan completed"; }); - mSceneAssetLoader->load(paths); + mSceneAssetLoader->load(paths, -1, [this](int pageId, QString path){ + // check that the scene file actually exists to avoid a race condition + // with saving scene files during import + while (!QFile::exists(path)) + { + QThread::msleep(10); + } + }); } } @@ -578,7 +591,7 @@ void UBDocument::scan(bool tocPresent) mToc->setPageId(pageProcessed, index); } - loader.resultProcessed(index); + loader.resultProcessed(); }); QObject::connect(&loader, &UBBackgroundLoader::finished, &loader, [&](){ @@ -606,7 +619,7 @@ void UBDocument::scan(bool tocPresent) QObject::connect(mSceneHeaderLoader, &UBBackgroundLoader::resultAvailable, mSceneHeaderLoader, [this](int index, const QByteArray& data){ const auto uuid = UBSvgSubsetAdaptor::sceneUuid(data); mToc->setUuid(index, uuid); - mSceneHeaderLoader->resultProcessed(index); + mSceneHeaderLoader->resultProcessed(); }); QObject::connect(mSceneHeaderLoader, &UBBackgroundLoader::finished, mSceneHeaderLoader, [this](){ diff --git a/src/document/UBDocument.h b/src/document/UBDocument.h index 1d75e3e0c..24938b75f 100644 --- a/src/document/UBDocument.h +++ b/src/document/UBDocument.h @@ -63,7 +63,8 @@ class UBDocument : public std::enable_shared_from_this void duplicatePage(int index); void movePage(int fromIndex, int toIndex); void copyPage(int fromIndex, std::shared_ptr to, int toIndex); - std::shared_ptr createPage(int index, bool saveToc = true, bool cached = true, bool useUndoRedoStack = true); + std::shared_ptr createPage(int index, bool saveToc = true, bool cached = true, + bool useUndoRedoStack = true); void persistPage(std::shared_ptr scene, int index, bool isAutomaticBackup = false, bool forceImmediateSaving = false, bool persistThumbnail = true, bool addToCache = true); std::shared_ptr loadScene(int index, bool cacheNeighboringScenes = true); diff --git a/src/frameworks/UBBackgroundLoader.cpp b/src/frameworks/UBBackgroundLoader.cpp index a12ef6107..ae353894b 100644 --- a/src/frameworks/UBBackgroundLoader.cpp +++ b/src/frameworks/UBBackgroundLoader.cpp @@ -62,7 +62,7 @@ UBBackgroundLoader::~UBBackgroundLoader() delete mWatcher; } -void UBBackgroundLoader::load(const QList>& paths, int maxBytes) +void UBBackgroundLoader::load(const QList>& paths, int maxBytes, std::function preCheck) { #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) mFuture = QtConcurrent::mapped(paths, ReadData{maxBytes}); @@ -70,7 +70,7 @@ void UBBackgroundLoader::load(const QList>& paths, int m // use a separate thread pool for each loader so that tasks are interwoven between loaders auto threadPool = new QThreadPool{this}; threadPool->setMaxThreadCount(4); - mFuture = QtConcurrent::mapped(threadPool, paths, ReadData{maxBytes}); + mFuture = QtConcurrent::mapped(threadPool, paths, ReadData{maxBytes, preCheck}); #endif mWatcher->setFuture(mFuture); @@ -93,18 +93,24 @@ void UBBackgroundLoader::setKeepAlive(std::shared_ptr keepAlive) mKeepAlive = keepAlive; } -void UBBackgroundLoader::resultProcessed(int index) +void UBBackgroundLoader::resultProcessed() { - mBlockingBuffer->resultProcessed(index); + mBlockingBuffer->resultProcessed(); } -UBBackgroundLoader::ReadData::ReadData(int maxBytes) +UBBackgroundLoader::ReadData::ReadData(int maxBytes, std::function preCheck) : mMaxBytes{maxBytes} + , mPreCheck{preCheck} { } UBBackgroundLoader::ReadData::result_type UBBackgroundLoader::ReadData::operator()(const std::pair& path) { + if (mPreCheck) + { + mPreCheck(path.first, path.second); + } + QFile file{path.second}; QByteArray result; diff --git a/src/frameworks/UBBackgroundLoader.h b/src/frameworks/UBBackgroundLoader.h index 07b7df891..a9a261fb2 100644 --- a/src/frameworks/UBBackgroundLoader.h +++ b/src/frameworks/UBBackgroundLoader.h @@ -37,13 +37,13 @@ class UBBackgroundLoader : public QObject UBBackgroundLoader(QObject* parent = nullptr); virtual ~UBBackgroundLoader(); - void load(const QList>& paths, int maxBytes = -1); + void load(const QList>& paths, int maxBytes = -1, std::function preCheck = nullptr); void abort(); void waitForFinished(); void setKeepAlive(std::shared_ptr keepAlive); public slots: - void resultProcessed(int index); + void resultProcessed(); signals: void resultAvailable(int index, const QByteArray& data); @@ -55,11 +55,12 @@ public slots: public: typedef std::pair result_type; - ReadData(int maxBytes); + ReadData(int maxBytes, std::function preCheck); result_type operator()(const std::pair& path); private: const int mMaxBytes{-1}; + std::function mPreCheck{}; }; private: diff --git a/src/frameworks/UBBlockingBuffer.cpp b/src/frameworks/UBBlockingBuffer.cpp index bd7dbfcc9..bfe6e4787 100644 --- a/src/frameworks/UBBlockingBuffer.cpp +++ b/src/frameworks/UBBlockingBuffer.cpp @@ -54,7 +54,7 @@ void UBBlockingBuffer::addResult(int index) } } -void UBBlockingBuffer::resultProcessed(int index) +void UBBlockingBuffer::resultProcessed() { mAvailableSpace.release(); } diff --git a/src/frameworks/UBBlockingBuffer.h b/src/frameworks/UBBlockingBuffer.h index 87c0d8abf..1e4d39364 100644 --- a/src/frameworks/UBBlockingBuffer.h +++ b/src/frameworks/UBBlockingBuffer.h @@ -38,7 +38,7 @@ class UBBlockingBuffer : public QThread public slots: void addResult(int index); - void resultProcessed(int index); + void resultProcessed(); void watcherFinished(); void halt(); diff --git a/src/gui/UBThumbnailScene.cpp b/src/gui/UBThumbnailScene.cpp index 538e27df7..dd0e88b65 100644 --- a/src/gui/UBThumbnailScene.cpp +++ b/src/gui/UBThumbnailScene.cpp @@ -189,11 +189,15 @@ UBThumbnail* UBThumbnailScene::lastSelectedThumbnail() const */ void UBThumbnailScene::createThumbnails(int startIndex) { - // adjust number of thumbnail items - mThumbnailItems.resize(mDocument->pageCount()); + // adjust number of thumbnail items and create empty thumbnails in new items + for (int index = mThumbnailItems.count(); index < mDocument->pageCount(); ++index) + { + insertThumbnail(index, false); + } // skip already loaded thumbnails - while (startIndex < mThumbnailItems.count() && mThumbnailItems.at(startIndex)) + while (startIndex < mThumbnailItems.count() && mThumbnailItems.at(startIndex) + && !mThumbnailItems.at(startIndex)->pixmap().isNull()) { ++startIndex; } @@ -234,7 +238,7 @@ void UBThumbnailScene::createThumbnails(int startIndex) QTimer::singleShot(5, this, [this, index](){ if (mLoader) { - mLoader->resultProcessed(index); + mLoader->resultProcessed(); } }); }); @@ -282,7 +286,7 @@ void UBThumbnailScene::insertThumbnail(int pageIndex, bool loadThumbnail) arrangeThumbnails(pageIndex); } - if (mLoader) + if (mLoader && loadThumbnail) { // restart loading remaining thumbnails createThumbnails(); @@ -375,13 +379,19 @@ void UBThumbnailScene::ensureThumbnail(int pageIndex, UBGraphicsScene* scene) { QPixmap pixmap = UBThumbnailAdaptor::generateMissingThumbnail(mDocument, pageIndex, scene); - thumbnailItem = new UBThumbnail; + if (!thumbnailItem) + { + thumbnailItem = new UBThumbnail; + } thumbnailItem->setPixmap(pixmap); thumbnailItem->setSceneIndex(pageIndex); - mThumbnailItems[pageIndex] = thumbnailItem; - addItem(thumbnailItem); + if (!mThumbnailItems.at(pageIndex)) + { + mThumbnailItems[pageIndex] = thumbnailItem; + addItem(thumbnailItem); + } arrangeThumbnails(pageIndex, pageIndex + 1); } From 0792d51cd62ab63740fad3abb9ccbad3ea638883 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Wed, 24 Sep 2025 19:23:42 +0200 Subject: [PATCH 035/133] fix: handling of default initialized thumbnails - add a default pixmap when creating a UBThumbnail instance - add function to detect whether a thumbnail pixmap is loaded - fix creating and loading thumbnails Signed-off-by: letsfindaway --- src/gui/UBThumbnail.cpp | 20 ++++++++++++++++++ src/gui/UBThumbnail.h | 3 +++ src/gui/UBThumbnailScene.cpp | 40 ++++++++++++++---------------------- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/gui/UBThumbnail.cpp b/src/gui/UBThumbnail.cpp index 3b7b3870b..a78a35b3c 100644 --- a/src/gui/UBThumbnail.cpp +++ b/src/gui/UBThumbnail.cpp @@ -56,13 +56,28 @@ UBThumbnail::UBThumbnail() // smooth transformation mPixmapItem->setTransformationMode(Qt::SmoothTransformation); + // create a reasonably sized empty pixmap, which is later replaced + const auto pageSize = UBSettings::settings()->pageSize->get().toSize(); + const auto pixmapSize = pageSize.scaled(UBSettings::maxThumbnailWidth, 0, Qt::KeepAspectRatioByExpanding); + QPixmap pixmap{pixmapSize}; + pixmap.fill(qApp->palette().color(QPalette::Mid)); + mPixmapItem->setPixmap(pixmap); + // do not draw anything setPen(QPen(QColor(Qt::transparent))); } void UBThumbnail::setPixmap(const QPixmap& pixmap) { + const auto needsAdjust = pixmap.size() != mPixmapItem->pixmap().size(); + mPixmapItem->setPixmap(pixmap); + mLoaded = true; + + if (needsAdjust) + { + adjustThumbnail(); + } } QPixmap UBThumbnail::pixmap() const @@ -70,6 +85,11 @@ QPixmap UBThumbnail::pixmap() const return mPixmapItem->pixmap(); } +bool UBThumbnail::isLoaded() const +{ + return mLoaded; +} + void UBThumbnail::setSceneIndex(int sceneIndex) { mIndex = sceneIndex; diff --git a/src/gui/UBThumbnail.h b/src/gui/UBThumbnail.h index c8acd8923..7cf252cf6 100644 --- a/src/gui/UBThumbnail.h +++ b/src/gui/UBThumbnail.h @@ -44,6 +44,8 @@ class UBThumbnail : public QGraphicsRectItem void setPixmap(const QPixmap& pixmap); QPixmap pixmap() const; + bool isLoaded() const; + void setSceneIndex(int sceneIndex); int sceneIndex() const; void setThumbnailSize(QSizeF size); @@ -75,6 +77,7 @@ class UBThumbnail : public QGraphicsRectItem private: QGraphicsPixmapItem* mPixmapItem{nullptr}; UBThumbnailTextItem* mTextItem{nullptr}; + bool mLoaded{false}; int mIndex{0}; int mColumn{0}; int mRow{0}; diff --git a/src/gui/UBThumbnailScene.cpp b/src/gui/UBThumbnailScene.cpp index dd0e88b65..ac8204e91 100644 --- a/src/gui/UBThumbnailScene.cpp +++ b/src/gui/UBThumbnailScene.cpp @@ -24,7 +24,6 @@ #include "adaptors/UBThumbnailAdaptor.h" #include "document/UBDocument.h" -#include "document/UBDocumentToc.h" #include "frameworks/UBBackgroundLoader.h" #include "gui/UBThumbnail.h" #include "gui/UBThumbnailArranger.h" @@ -197,7 +196,7 @@ void UBThumbnailScene::createThumbnails(int startIndex) // skip already loaded thumbnails while (startIndex < mThumbnailItems.count() && mThumbnailItems.at(startIndex) - && !mThumbnailItems.at(startIndex)->pixmap().isNull()) + && mThumbnailItems.at(startIndex)->isLoaded()) { ++startIndex; } @@ -207,12 +206,8 @@ void UBThumbnailScene::createThumbnails(int startIndex) for (int index = startIndex; index < mDocument->pageCount(); ++index) { - // only load thumbnails for pages with assets, others are loaded while scanning - if (mDocument->toc()->hasAssetsEntry(index)) - { - const auto thumbnailPath = UBThumbnailAdaptor::thumbnailUrl(mDocument, index).toLocalFile(); - paths << std::pair{index, thumbnailPath}; - } + const auto thumbnailPath = UBThumbnailAdaptor::thumbnailUrl(mDocument, index).toLocalFile(); + paths << std::pair{index, thumbnailPath}; } // start background loading of files @@ -375,7 +370,7 @@ void UBThumbnailScene::ensureThumbnail(int pageIndex, UBGraphicsScene* scene) { auto thumbnailItem = mThumbnailItems.at(pageIndex); - if (!thumbnailItem || thumbnailItem->pixmap().isNull()) + if (!thumbnailItem || !thumbnailItem->isLoaded()) { QPixmap pixmap = UBThumbnailAdaptor::generateMissingThumbnail(mDocument, pageIndex, scene); @@ -428,27 +423,22 @@ void UBThumbnailScene::loadThumbnail(int index, const QByteArray& data) if (!thumbnailItem) { - QPixmap pixmap; - - if (data.isEmpty()) - { - pixmap = UBThumbnailAdaptor::generateMissingThumbnail(mDocument, index); - } - else - { - pixmap.loadFromData(data); - } - thumbnailItem = new UBThumbnail; - - thumbnailItem->setPixmap(pixmap); - thumbnailItem->setSceneIndex(index); - mThumbnailItems[index] = thumbnailItem; addItem(thumbnailItem); + } + + QPixmap pixmap; - arrangeThumbnails(index, index + 1); + if (!data.isEmpty()) + { + pixmap.loadFromData(data); + thumbnailItem->setPixmap(pixmap); } + + thumbnailItem->setSceneIndex(index); + + arrangeThumbnails(index, index + 1); } void UBThumbnailScene::renumberThumbnails(int fromIndex, int toIndex) const From 35530fc2df400a2fe9d78ae74f00b96e8329388c Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Thu, 25 Sep 2025 18:32:54 +0200 Subject: [PATCH 036/133] fix: compatibility with Qt 5 - use unordered_set instead of QSet Signed-off-by: letsfindaway --- src/document/UBDocument.cpp | 4 ++-- src/document/UBDocument.h | 4 ++-- src/frameworks/UBBackgroundLoader.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index 1f1e777c0..f5b9f2c15 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -349,7 +349,7 @@ QString UBDocument::thumbnailFile(int index) void UBDocument::sceneLoaded(UBGraphicsScene* scene, std::shared_ptr handle) { - mLoaderHandles.remove(handle); + mLoaderHandles.erase(handle); const auto persistenceManager = UBPersistenceManager::persistenceManager(); auto index = mToc->findUuid(scene->uuid()); @@ -459,7 +459,7 @@ void UBDocument::scanAssets() if (handle) { // loading started, keep handle until finished - mLoaderHandles << handle; + mLoaderHandles.insert(handle); return; } } diff --git a/src/document/UBDocument.h b/src/document/UBDocument.h index 24938b75f..a87d29127 100644 --- a/src/document/UBDocument.h +++ b/src/document/UBDocument.h @@ -24,10 +24,10 @@ #include #include -#include #include #include +#include // forward @@ -98,7 +98,7 @@ class UBDocument : public std::enable_shared_from_this UBBackgroundLoader* mSceneHeaderLoader{nullptr}; UBBackgroundLoader* mSceneAssetLoader{nullptr}; QHash mUuidV5Map{}; - QSet> mLoaderHandles; + std::unordered_set> mLoaderHandles; static QList> sDocuments; }; diff --git a/src/frameworks/UBBackgroundLoader.cpp b/src/frameworks/UBBackgroundLoader.cpp index ae353894b..35eb86d24 100644 --- a/src/frameworks/UBBackgroundLoader.cpp +++ b/src/frameworks/UBBackgroundLoader.cpp @@ -65,7 +65,7 @@ UBBackgroundLoader::~UBBackgroundLoader() void UBBackgroundLoader::load(const QList>& paths, int maxBytes, std::function preCheck) { #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - mFuture = QtConcurrent::mapped(paths, ReadData{maxBytes}); + mFuture = QtConcurrent::mapped(paths, ReadData{maxBytes, preCheck}); #else // use a separate thread pool for each loader so that tasks are interwoven between loaders auto threadPool = new QThreadPool{this}; From 62a3f439efe3d06f26604ac7347b48b8cffea2d9 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Fri, 26 Sep 2025 14:27:33 +0200 Subject: [PATCH 037/133] fix: deleting page before thumbnail is loaded - deleting a page in document mode while the thumbnail loader is still running adds an empty thumbnail at the end - the TOC must be adjusted before deleting the thumbnail Signed-off-by: letsfindaway --- src/document/UBDocument.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index f5b9f2c15..ce9c2784d 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -136,8 +136,8 @@ void UBDocument::deletePages(QList indexes) for (int i = indexes.size() - 1; i >= 0; --i) { - thumbnailScene()->deleteThumbnail(indexes.at(i), false); mToc->remove(indexes.at(i)); + thumbnailScene()->deleteThumbnail(indexes.at(i), false); emit UBPersistenceManager::persistenceManager()->documentSceneDeleted(this, indexes.at(i)); } From 1ef8ddb03cc51c7ec7a653cffcdd181d6369e781 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 28 Sep 2025 11:53:03 +0200 Subject: [PATCH 038/133] perf/fix: improve thumbnail loading and scanning - perf: start asset scanning already in Document mode - fix: this also fixes thumbnail generation after import - perf: move CPU-intensive decoding of thumbnail JPGs to loader threads - perf: background loader can now return plain data or decoded pixmap - perf: delay loading of next thumbnail only every 10th run - fix: remove scan message when scan is aborted Signed-off-by: letsfindaway --- src/document/UBDocument.cpp | 44 +++++++++++++++------------ src/document/UBDocumentController.cpp | 1 - src/frameworks/UBBackgroundLoader.cpp | 38 +++++++++++++++++------ src/frameworks/UBBackgroundLoader.h | 20 ++++++++---- src/frameworks/UBBlockingBuffer.cpp | 8 +++-- src/frameworks/UBBlockingBuffer.h | 8 ++--- src/gui/UBThumbnailScene.cpp | 30 +++++++++++------- src/gui/UBThumbnailScene.h | 2 +- 8 files changed, 96 insertions(+), 55 deletions(-) diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index ce9c2784d..673ac0c2c 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -301,16 +301,14 @@ UBDocumentToc* UBDocument::toc() scan(tocPresent); mToc->save(); } - else + + // scan assets if missing + for (int index = 0; index < mToc->pageCount(); ++index) { - // scan assets if missing - for (int index = 0; index < mToc->pageCount(); ++index) + if (!mToc->hasAssetsEntry(index)) { - if (!mToc->hasAssetsEntry(index)) - { - scanAssets(); - break; - } + scanAssets(); + break; } } } @@ -439,12 +437,12 @@ void UBDocument::scanAssets() { qDebug() << "Scan" << paths.count() << "scenes for assets"; // load scenes for scanning - mSceneAssetLoader = new UBBackgroundLoader; + mSceneAssetLoader = new UBBackgroundLoader{UBBackgroundLoader::ByteArray}; - QObject::connect(mSceneAssetLoader, &UBBackgroundLoader::resultAvailable, mSceneAssetLoader, [this](int pageId, const QByteArray& data){ + QObject::connect(mSceneAssetLoader, &UBBackgroundLoader::resultAvailable, mSceneAssetLoader, [this](int pageId, const QVariant& data){ UBApplication::showMessage(UBDocumentController::tr("Scanning page %1 of %2").arg(pageId).arg(mToc->pageCount()), true); - if (pageId >= 0 && !data.isEmpty()) + if (pageId >= 0 && !data.isNull()) { auto scene = UBPersistenceManager::persistenceManager()->getDocumentScene(mProxy, pageId); @@ -454,7 +452,7 @@ void UBDocument::scanAssets() return; } - const auto handle = UBPersistenceManager::persistenceManager()->prepareSceneLoading(mProxy, pageId, data, false); + const auto handle = UBPersistenceManager::persistenceManager()->prepareSceneLoading(mProxy, pageId, data.toByteArray(), false); if (handle) { @@ -469,8 +467,14 @@ void UBDocument::scanAssets() }); QObject::connect(mSceneAssetLoader, &UBBackgroundLoader::finished, mSceneAssetLoader, [this](){ - UBApplication::showMessage(UBDocumentController::tr("Scan completed")); qDebug() << "Asset scan completed"; + mSceneAssetLoader->deleteLater(); + mSceneAssetLoader = nullptr; + }); + + QObject::connect(mSceneAssetLoader, &QObject::destroyed, [](){ + // loader either completed or aborted + UBApplication::showMessage(UBDocumentController::tr("Scan terminated")); }); mSceneAssetLoader->load(paths, -1, [this](int pageId, QString path){ @@ -554,14 +558,14 @@ void UBDocument::scan(bool tocPresent) } // load the first 300 bytes of each file in background, enough to get version and UUID - UBBackgroundLoader loader; + UBBackgroundLoader loader{UBBackgroundLoader::ByteArray}; int pageProcessed = -1; int currentPage = 0; const auto currentVersion = QVersionNumber::fromString(UBSettings::currentFileVersion); - QObject::connect(&loader, &UBBackgroundLoader::resultAvailable, &loader, [&](int index, const QByteArray& data){ + QObject::connect(&loader, &UBBackgroundLoader::resultAvailable, &loader, [&](int index, const QVariant& data){ UBApplication::showMessage(UBDocumentController::tr("Scanning page %1 of %2").arg(++currentPage).arg(pages.count()), true); - const auto uuid = UBSvgSubsetAdaptor::sceneUuid(data); + const auto uuid = UBSvgSubsetAdaptor::sceneUuid(data.toByteArray()); // Check whether the tocSceneUuids already contains this scene. // If yes, locate and update the TOC entry @@ -575,7 +579,7 @@ void UBDocument::scan(bool tocPresent) tocSceneUuids.remove(uuid); // invalidate assets if scene was modified by an earlier version - if (UBSvgSubsetAdaptor::sceneVersion(data) < currentVersion) + if (UBSvgSubsetAdaptor::sceneVersion(data.toByteArray()) < currentVersion) { mToc->unsetAssets(index); } @@ -613,11 +617,11 @@ void UBDocument::scan(bool tocPresent) else if (!paths.empty()) { // start reading the UUIDs in background, but make sure it is completed when the UBDocument is deleted - mSceneHeaderLoader = new UBBackgroundLoader; + mSceneHeaderLoader = new UBBackgroundLoader{UBBackgroundLoader::ByteArray}; mSceneHeaderLoader->setKeepAlive(shared_from_this()); - QObject::connect(mSceneHeaderLoader, &UBBackgroundLoader::resultAvailable, mSceneHeaderLoader, [this](int index, const QByteArray& data){ - const auto uuid = UBSvgSubsetAdaptor::sceneUuid(data); + QObject::connect(mSceneHeaderLoader, &UBBackgroundLoader::resultAvailable, mSceneHeaderLoader, [this](int index, const QVariant& data){ + const auto uuid = UBSvgSubsetAdaptor::sceneUuid(data.toByteArray()); mToc->setUuid(index, uuid); mSceneHeaderLoader->resultProcessed(); }); diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index f83844c32..b208b64b1 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -3399,7 +3399,6 @@ bool UBDocumentController::isOKToOpenDocument(std::shared_ptr p || docVersion.startsWith("4.3") || docVersion.startsWith("4.4") || docVersion.startsWith("4.5") || docVersion.startsWith("4.6") || docVersion.startsWith("4.8") || docVersion.startsWith("4.9")) { - UBDocument::getDocument(proxy)->scanAssets(); // Invoke widget upgrader widgetUpgradeAdaptor.upgradeWidgets(proxy); return true; diff --git a/src/frameworks/UBBackgroundLoader.cpp b/src/frameworks/UBBackgroundLoader.cpp index 35eb86d24..99909739b 100644 --- a/src/frameworks/UBBackgroundLoader.cpp +++ b/src/frameworks/UBBackgroundLoader.cpp @@ -25,14 +25,16 @@ #include #include #include +#include #include #include "frameworks/UBBlockingBuffer.h" -UBBackgroundLoader::UBBackgroundLoader(QObject* parent) +UBBackgroundLoader::UBBackgroundLoader(ResultType resultType, QObject* parent) : QObject{parent} + , mResultType{resultType} { - mWatcher = new QFutureWatcher>; + mWatcher = new QFutureWatcher>; mWatcher->setPendingResultsLimit(2); mWatcherThread = new QThread{this}; mWatcher->moveToThread(mWatcherThread); @@ -65,12 +67,12 @@ UBBackgroundLoader::~UBBackgroundLoader() void UBBackgroundLoader::load(const QList>& paths, int maxBytes, std::function preCheck) { #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - mFuture = QtConcurrent::mapped(paths, ReadData{maxBytes, preCheck}); + mFuture = QtConcurrent::mapped(paths, ReadData{mResultType, maxBytes, preCheck}); #else // use a separate thread pool for each loader so that tasks are interwoven between loaders auto threadPool = new QThreadPool{this}; threadPool->setMaxThreadCount(4); - mFuture = QtConcurrent::mapped(threadPool, paths, ReadData{maxBytes, preCheck}); + mFuture = QtConcurrent::mapped(threadPool, paths, ReadData{mResultType, maxBytes, preCheck}); #endif mWatcher->setFuture(mFuture); @@ -98,8 +100,9 @@ void UBBackgroundLoader::resultProcessed() mBlockingBuffer->resultProcessed(); } -UBBackgroundLoader::ReadData::ReadData(int maxBytes, std::function preCheck) - : mMaxBytes{maxBytes} +UBBackgroundLoader::ReadData::ReadData(ResultType resultType, int maxBytes, std::function preCheck) + : mResultType{resultType} + , mMaxBytes{maxBytes} , mPreCheck{preCheck} { } @@ -112,20 +115,37 @@ UBBackgroundLoader::ReadData::result_type UBBackgroundLoader::ReadData::operator } QFile file{path.second}; - QByteArray result; + QVariant result; if (file.open(QFile::ReadOnly)) { + QByteArray data; + if (mMaxBytes < 0) { - result = file.readAll(); + data = file.readAll(); } else { - result = file.read(mMaxBytes); + data = file.read(mMaxBytes); } file.close(); + + switch (mResultType) + { + case ByteArray: + result = data; + break; + + case Pixmap: + { + QPixmap pixmap; + pixmap.loadFromData(data); + result = pixmap; + break; + } + } } return {path.first, result}; diff --git a/src/frameworks/UBBackgroundLoader.h b/src/frameworks/UBBackgroundLoader.h index a9a261fb2..94908c68e 100644 --- a/src/frameworks/UBBackgroundLoader.h +++ b/src/frameworks/UBBackgroundLoader.h @@ -24,6 +24,7 @@ #include #include +#include // forward class UBBlockingBuffer; @@ -34,7 +35,12 @@ class UBBackgroundLoader : public QObject Q_OBJECT public: - UBBackgroundLoader(QObject* parent = nullptr); + enum ResultType { + ByteArray, + Pixmap + }; + + UBBackgroundLoader(ResultType resultType, QObject* parent = nullptr); virtual ~UBBackgroundLoader(); void load(const QList>& paths, int maxBytes = -1, std::function preCheck = nullptr); @@ -46,27 +52,29 @@ public slots: void resultProcessed(); signals: - void resultAvailable(int index, const QByteArray& data); + void resultAvailable(int index, const QVariant& data); void finished(); private: class ReadData { public: - typedef std::pair result_type; + typedef std::pair result_type; - ReadData(int maxBytes, std::function preCheck); + ReadData(ResultType resultType, int maxBytes, std::function preCheck); result_type operator()(const std::pair& path); private: + const ResultType mResultType{ByteArray}; const int mMaxBytes{-1}; std::function mPreCheck{}; }; private: - QFuture> mFuture; + const ResultType mResultType{ByteArray}; + QFuture> mFuture; int mIndex{0}; - QFutureWatcher>* mWatcher{nullptr}; + QFutureWatcher>* mWatcher{nullptr}; std::shared_ptr mKeepAlive; UBBlockingBuffer* mBlockingBuffer{nullptr}; QThread* mWatcherThread{nullptr}; diff --git a/src/frameworks/UBBlockingBuffer.cpp b/src/frameworks/UBBlockingBuffer.cpp index bfe6e4787..dc1fb7f2a 100644 --- a/src/frameworks/UBBlockingBuffer.cpp +++ b/src/frameworks/UBBlockingBuffer.cpp @@ -22,18 +22,20 @@ #include "UBBlockingBuffer.h" +#include + UBBlockingBuffer::UBBlockingBuffer(QObject* parent) : QThread{parent} { } -void UBBlockingBuffer::setWatcher(QFutureWatcher>* watcher) +void UBBlockingBuffer::setWatcher(QFutureWatcher>* watcher) { mWatcher = watcher; - connect(mWatcher, &QFutureWatcher>::resultReadyAt, this, &UBBlockingBuffer::addResult, + connect(mWatcher, &QFutureWatcher>::resultReadyAt, this, &UBBlockingBuffer::addResult, Qt::DirectConnection); - connect(mWatcher, &QFutureWatcher>::finished, this, &UBBlockingBuffer::watcherFinished, + connect(mWatcher, &QFutureWatcher>::finished, this, &UBBlockingBuffer::watcherFinished, Qt::DirectConnection); } diff --git a/src/frameworks/UBBlockingBuffer.h b/src/frameworks/UBBlockingBuffer.h index 1e4d39364..d5868864b 100644 --- a/src/frameworks/UBBlockingBuffer.h +++ b/src/frameworks/UBBlockingBuffer.h @@ -34,7 +34,7 @@ class UBBlockingBuffer : public QThread public: UBBlockingBuffer(QObject* parent = nullptr); - void setWatcher(QFutureWatcher>* watcher); + void setWatcher(QFutureWatcher>* watcher); public slots: void addResult(int index); @@ -43,16 +43,16 @@ public slots: void halt(); signals: - void resultAvailable(int index, const QByteArray& data); + void resultAvailable(int index, const QVariant& data); void finished(); protected: void run() override; private: - QFutureWatcher>* mWatcher; + QFutureWatcher>* mWatcher; QSemaphore mAvailableResults; QSemaphore mAvailableSpace{1}; QMutex mMutex; - std::deque> mBuffer; + std::deque> mBuffer; }; diff --git a/src/gui/UBThumbnailScene.cpp b/src/gui/UBThumbnailScene.cpp index ac8204e91..6b2275472 100644 --- a/src/gui/UBThumbnailScene.cpp +++ b/src/gui/UBThumbnailScene.cpp @@ -224,19 +224,29 @@ void UBThumbnailScene::createThumbnails(int startIndex) return; } - mLoader = new UBBackgroundLoader{this}; + mLoader = new UBBackgroundLoader{UBBackgroundLoader::Pixmap, this}; - connect(mLoader, &UBBackgroundLoader::resultAvailable, this, [this](int index, const QByteArray& data){ - // now create all missing thumbnails for document as they arrive from the loader + connect(mLoader, &UBBackgroundLoader::resultAvailable, this, [this](int index, const QVariant& data){ + // now generate all missing thumbnails for document as they arrive from the loader loadThumbnail(index, data); - QTimer::singleShot(5, this, [this, index](){ - if (mLoader) + if (mLoader) + { + // delay next thumbnail processing after a specified number of thumbnails + // to improve user experience when simultaneously interacting with the board + if (index % 10 == 0) + { + QTimer::singleShot(5, this, [this](){ + mLoader->resultProcessed(); + }); + } + else { mLoader->resultProcessed(); } - }); + } }); + connect(mLoader, &UBBackgroundLoader::finished, this, [this](){ // delete loader mLoader->deleteLater(); @@ -417,7 +427,7 @@ UBThumbnailArranger* UBThumbnailScene::currentThumbnailArranger() return thumbnailArranger; } -void UBThumbnailScene::loadThumbnail(int index, const QByteArray& data) +void UBThumbnailScene::loadThumbnail(int index, const QVariant& data) { auto thumbnailItem = mThumbnailItems.at(index); @@ -428,11 +438,9 @@ void UBThumbnailScene::loadThumbnail(int index, const QByteArray& data) addItem(thumbnailItem); } - QPixmap pixmap; - - if (!data.isEmpty()) + if (!data.isNull()) { - pixmap.loadFromData(data); + QPixmap pixmap = data.value(); thumbnailItem->setPixmap(pixmap); } diff --git a/src/gui/UBThumbnailScene.h b/src/gui/UBThumbnailScene.h index 4c3d0e50d..4a453702f 100644 --- a/src/gui/UBThumbnailScene.h +++ b/src/gui/UBThumbnailScene.h @@ -72,7 +72,7 @@ class UBThumbnailScene : public QGraphicsScene private: friend class UBThumbnail; UBThumbnailArranger* currentThumbnailArranger(); - void loadThumbnail(int index, const QByteArray& data); + void loadThumbnail(int index, const QVariant& data); void renumberThumbnails(int fromIndex = 0, int toIndex = -1) const; private: From 446c39a98729eb249bce0ca56cd330e13c4d30e9 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 28 Sep 2025 12:40:55 +0200 Subject: [PATCH 039/133] fix: saving correct scene before copying - persistence manager wrongly used page index to save active scene - use board controller's function to save active scene Signed-off-by: letsfindaway --- src/core/UBPersistenceManager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index ad235aee9..e9cb788ce 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -780,8 +780,7 @@ QUuid UBPersistenceManager::copyDocumentScene(std::shared_ptr f // save modified scene of the same document if (scene && scene->document() == from && scene->isModified()) { - auto page = UBApplication::boardController->activeSceneIndex(); - persistDocumentScene(from, scene, page, false, true); + UBApplication::boardController->persistCurrentScene(false, true); } // copy SVG and thumbnail From 30256cd11548bf62754567027779000406c0d976 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 29 Sep 2025 11:38:16 +0200 Subject: [PATCH 040/133] fix: include QVariant - depending on the compiler and/or Qt version it is necessary to fully define the QVariant class in the header - move #include from UBBlockingBuffer.cpp to .h Signed-off-by: letsfindaway --- src/frameworks/UBBlockingBuffer.cpp | 1 - src/frameworks/UBBlockingBuffer.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frameworks/UBBlockingBuffer.cpp b/src/frameworks/UBBlockingBuffer.cpp index dc1fb7f2a..85f4959ad 100644 --- a/src/frameworks/UBBlockingBuffer.cpp +++ b/src/frameworks/UBBlockingBuffer.cpp @@ -22,7 +22,6 @@ #include "UBBlockingBuffer.h" -#include UBBlockingBuffer::UBBlockingBuffer(QObject* parent) : QThread{parent} diff --git a/src/frameworks/UBBlockingBuffer.h b/src/frameworks/UBBlockingBuffer.h index d5868864b..70b26696b 100644 --- a/src/frameworks/UBBlockingBuffer.h +++ b/src/frameworks/UBBlockingBuffer.h @@ -25,6 +25,7 @@ #include #include #include +#include #include From a143b0bfc339fa09cc95ae9c5a95260917575f6a Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 29 Sep 2025 18:16:31 +0200 Subject: [PATCH 041/133] fix: wait for scenes saved before scanning - there might be unsaved scenes pending in the persistence worker when scanning for assets starts or the applicatioin is terminated - add a function in UBPersistenceWorker waiting for any unsaved data - call this function before asset scanning - call this function when terminating OpenBoard Signed-off-by: letsfindaway --- src/core/UBPersistenceManager.cpp | 8 +++++ src/core/UBPersistenceManager.h | 2 ++ src/core/UBPersistenceWorker.cpp | 52 +++++++++++++++++++++++-------- src/core/UBPersistenceWorker.h | 6 ++++ src/document/UBDocument.cpp | 1 + 5 files changed, 56 insertions(+), 13 deletions(-) diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index e9cb788ce..069c5fe73 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -879,6 +879,14 @@ void UBPersistenceManager::cleanupMediaAssets(std::shared_ptr p } } +void UBPersistenceManager::waitForAllSaved() const +{ + if (mWorker) + { + mWorker->waitForAllSaved(); + } +} + void UBPersistenceManager::persistDocumentScene(std::shared_ptr pDocumentProxy, std::shared_ptr pScene, int pageId, bool isAnAutomaticBackup, bool forceImmediateSaving, bool addToCache) { diff --git a/src/core/UBPersistenceManager.h b/src/core/UBPersistenceManager.h index f87e309b5..d3a7817f9 100644 --- a/src/core/UBPersistenceManager.h +++ b/src/core/UBPersistenceManager.h @@ -113,6 +113,8 @@ class UBPersistenceManager : public QObject bool copyAsset(std::shared_ptr proxy, const QString& fromRelativePath, const QString& toRelativePath); void cleanupMediaAssets(std::shared_ptr proxy, QSet referencedMediaAssets); + void waitForAllSaved() const; + // QList > documentProxies; UBDocumentTreeNode *mDocumentTreeStructure; UBDocumentTreeModel *mDocumentTreeStructureModel; diff --git a/src/core/UBPersistenceWorker.cpp b/src/core/UBPersistenceWorker.cpp index 93476b269..8ca4ba8af 100644 --- a/src/core/UBPersistenceWorker.cpp +++ b/src/core/UBPersistenceWorker.cpp @@ -54,9 +54,20 @@ void UBPersistenceWorker::saveMetadata(std::shared_ptr proxy) mSemaphore.release(); } +void UBPersistenceWorker::waitForAllSaved() +{ + QMutexLocker locker(&mSaving); + + if (!saves.isEmpty()) + { + mNoMoreSaves.wait(&mSaving); + } +} + void UBPersistenceWorker::applicationWillClose() { qDebug() << "application Will close signal received"; + waitForAllSaved(); mReceivedApplicationClosing = true; mSemaphore.release(); } @@ -65,22 +76,37 @@ void UBPersistenceWorker::process() { qDebug() << "process starts"; mSemaphore.acquire(); - do{ - PersistenceInformation info; + + while (!mReceivedApplicationClosing) + { { - QMutexLocker locker(&mMutex); - info = saves.takeFirst(); - } - if(info.action == WriteScene){ - UBSvgSubsetAdaptor::persistScene(info.proxy, info.scene->shared_from_this(), info.sceneIndex); - emit scenePersisted(info.scene); - } - else if (info.action == WriteMetadata) { - UBMetadataDcSubsetAdaptor::persist(info.proxy); - emit metadataPersisted(info.proxy); + QMutexLocker saving(&mSaving); + PersistenceInformation info; + + { + QMutexLocker locker(&mMutex); + info = saves.takeFirst(); + } + + if (info.action == WriteScene) + { + UBSvgSubsetAdaptor::persistScene(info.proxy, info.scene->shared_from_this(), info.sceneIndex); + emit scenePersisted(info.scene); + } + else if (info.action == WriteMetadata) + { + UBMetadataDcSubsetAdaptor::persist(info.proxy); + emit metadataPersisted(info.proxy); + } + + if (saves.isEmpty()) + { + mNoMoreSaves.notify_all(); + } } + mSemaphore.acquire(); - }while(!mReceivedApplicationClosing); + } qDebug() << "process will stop"; emit finished(); } diff --git a/src/core/UBPersistenceWorker.h b/src/core/UBPersistenceWorker.h index 93113b61e..78474fd9e 100644 --- a/src/core/UBPersistenceWorker.h +++ b/src/core/UBPersistenceWorker.h @@ -31,6 +31,8 @@ #include #include +#include + #include "document/UBDocumentProxy.h" #include "domain/UBGraphicsScene.h" @@ -55,6 +57,8 @@ class UBPersistenceWorker : public QObject void saveScene(std::shared_ptr proxy, UBGraphicsScene* scene, const int pageIndex); void saveMetadata(std::shared_ptr proxy); + void waitForAllSaved(); + signals: void finished(); void error(QString string); @@ -69,6 +73,8 @@ public slots: bool mReceivedApplicationClosing; QSemaphore mSemaphore; QMutex mMutex; + QMutex mSaving; + QWaitCondition mNoMoreSaves; QList saves; }; diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index 673ac0c2c..eb140aa10 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -423,6 +423,7 @@ void UBDocument::scanAssets() // create a list of page IDs and paths of pages without asset info for background loading QList> paths; const auto persistenceManager = UBPersistenceManager::persistenceManager(); + persistenceManager->waitForAllSaved(); for (int index = 0; index < mToc->pageCount(); ++index) { From 978d3fd2ee5630717886e9841d469eec39ef1dd1 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Wed, 1 Oct 2025 16:38:12 +0200 Subject: [PATCH 042/133] fix: race condition saving scenes - saving a scene by the UBPersistenceWorker could create a race condition with immediate saving or even deletion of the scene - add a function to UBPersistenceWorker to invalidate entries in the list of pending saves - invoke this function before deleting or immediately saving a scene Signed-off-by: letsfindaway --- src/core/UBPersistenceManager.cpp | 3 +++ src/core/UBPersistenceWorker.cpp | 23 ++++++++++++++++++++--- src/core/UBPersistenceWorker.h | 8 +++++--- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index 069c5fe73..da4718370 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -754,6 +754,8 @@ void UBPersistenceManager::deleteDocumentScenes(std::shared_ptr for (auto pageId : pageIds) { + mWorker->removePendingSaves(proxy, pageId); + QString svgFileName = proxy->persistencePath() + sceneFilenameForId(pageId); QFile::remove(svgFileName); @@ -902,6 +904,7 @@ void UBPersistenceManager::persistDocumentScene(std::shared_ptr if(forceImmediateSaving) { + mWorker->removePendingSaves(pDocumentProxy, pageId); UBSvgSubsetAdaptor::persistScene(pDocumentProxy, pScene, pageId); } else diff --git a/src/core/UBPersistenceWorker.cpp b/src/core/UBPersistenceWorker.cpp index 8ca4ba8af..103757489 100644 --- a/src/core/UBPersistenceWorker.cpp +++ b/src/core/UBPersistenceWorker.cpp @@ -37,9 +37,9 @@ UBPersistenceWorker::UBPersistenceWorker(QObject *parent) : { } -void UBPersistenceWorker::saveScene(std::shared_ptr proxy, UBGraphicsScene *scene, const int pageIndex) +void UBPersistenceWorker::saveScene(std::shared_ptr proxy, UBGraphicsScene *scene, const int pageId) { - PersistenceInformation entry = {WriteScene, proxy, scene, pageIndex}; + PersistenceInformation entry = {WriteScene, proxy, scene, pageId}; QMutexLocker locker(&mMutex); saves.append(entry); @@ -54,6 +54,23 @@ void UBPersistenceWorker::saveMetadata(std::shared_ptr proxy) mSemaphore.release(); } +void UBPersistenceWorker::removePendingSaves(std::shared_ptr proxy, const int pageId) +{ + QMutexLocker savingLocker(&mSaving); + QMutexLocker locker(&mMutex); + + for (auto& info : saves) + { + if (info.action == WriteScene && info.proxy == proxy && info.pageId == pageId) + { + // deactivate entry, release scene + qDebug() << "removed pending save for page id" << pageId; + info.action = Noop; + emit scenePersisted(info.scene); + } + } +} + void UBPersistenceWorker::waitForAllSaved() { QMutexLocker locker(&mSaving); @@ -90,7 +107,7 @@ void UBPersistenceWorker::process() if (info.action == WriteScene) { - UBSvgSubsetAdaptor::persistScene(info.proxy, info.scene->shared_from_this(), info.sceneIndex); + UBSvgSubsetAdaptor::persistScene(info.proxy, info.scene->shared_from_this(), info.pageId); emit scenePersisted(info.scene); } else if (info.action == WriteMetadata) diff --git a/src/core/UBPersistenceWorker.h b/src/core/UBPersistenceWorker.h index 78474fd9e..a14d24f70 100644 --- a/src/core/UBPersistenceWorker.h +++ b/src/core/UBPersistenceWorker.h @@ -37,7 +37,8 @@ #include "domain/UBGraphicsScene.h" typedef enum{ - WriteScene = 0, + Noop, + WriteScene, WriteMetadata }ActionType; @@ -45,7 +46,7 @@ typedef struct{ ActionType action; std::shared_ptr proxy; UBGraphicsScene* scene; - int sceneIndex; + int pageId; }PersistenceInformation; class UBPersistenceWorker : public QObject @@ -54,9 +55,10 @@ class UBPersistenceWorker : public QObject public: explicit UBPersistenceWorker(QObject *parent = 0); - void saveScene(std::shared_ptr proxy, UBGraphicsScene* scene, const int pageIndex); + void saveScene(std::shared_ptr proxy, UBGraphicsScene* scene, const int pageId); void saveMetadata(std::shared_ptr proxy); + void removePendingSaves(std::shared_ptr proxy, const int pageId); void waitForAllSaved(); signals: From 60c2aa340a34898c09fff3625dbab680dbc52c89 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 13 Oct 2025 08:20:03 +0200 Subject: [PATCH 043/133] fix: paste svg image to board - select first mime type containing a known image format - create SVG image if it is a vector image - create bitmap image if it is a raster image --- src/board/UBBoardController.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index a8fe9e609..0e51ac4a7 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -2561,10 +2561,13 @@ void UBBoardController::processMimeData(const QMimeData* pMimeData, const QPoint { const QStringList formats = pMimeData->formats(); QString selectedFormat; + UBMimeType::Enum ubMimeType{UBMimeType::UNKNOWN}; for (const QString& format : formats) - { - if (format.startsWith("image/")) + { + ubMimeType = UBFileSystemUtils::mimeTypeFromString(format); + + if (ubMimeType == UBMimeType::VectorImage || ubMimeType == UBMimeType::RasterImage) { selectedFormat = format; break; @@ -2575,9 +2578,11 @@ void UBBoardController::processMimeData(const QMimeData* pMimeData, const QPoint if (selectedFormat.isEmpty()) { + // should never happen, but just in case // create an image and fill the buffer with PNG data QImage img = qvariant_cast (pMimeData->imageData()); img.save(&buffer, "png"); + ubMimeType = UBMimeType::RasterImage; } else { @@ -2585,12 +2590,20 @@ void UBBoardController::processMimeData(const QMimeData* pMimeData, const QPoint buffer.setData(pMimeData->data(selectedFormat)); } - // validate that the image is really an image, webkit does not fill properly the image mime data - if (!buffer.data().isEmpty()) + if (ubMimeType == UBMimeType::VectorImage) { - mActiveScene->addImage(buffer.data(), NULL, pPos, 1.); + mActiveScene->addSvg({}, pPos, buffer.data()); return; } + else if (ubMimeType == UBMimeType::RasterImage) + { + // validate that the image is really an image, webkit does not fill properly the image mime data + if (!buffer.data().isEmpty()) + { + mActiveScene->addImage(buffer.data(), nullptr, pPos, 1.); + return; + } + } } if (pMimeData->hasText()) From ad7e6004707ec0f0f5ddd1c352485995e02d200d Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 13 Oct 2025 14:20:11 +0200 Subject: [PATCH 044/133] fix: media asset id for web widgets - widget id when creating a web widget with the UBEmbedController - for a full page: use the URL - for an embed snippet: create the UUIDv5 from the snippet data - UUID for the widget - for a full page: create UUIDv5 from the URL - for an embed snippet: use the UUID from the widget id - data used to create UUIDv5 must not change with widget updates See letsfindaway/#227 Signed-off-by: letsfindaway --- src/domain/UBMediaAssetItem.cpp | 32 ++++++++++++++++++++++++-------- src/web/UBEmbedController.cpp | 16 ++++++++++------ src/web/UBEmbedController.h | 2 +- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/domain/UBMediaAssetItem.cpp b/src/domain/UBMediaAssetItem.cpp index 9b2815d34..71ffbd5cb 100644 --- a/src/domain/UBMediaAssetItem.cpp +++ b/src/domain/UBMediaAssetItem.cpp @@ -21,6 +21,7 @@ #include "UBMediaAssetItem.h" +#include #include QUuid UBMediaAssetItem::mediaAssetUuid() const @@ -58,20 +59,35 @@ QUuid UBMediaAssetItem::createMediaAssetUuid(const QString& path) if (fileInfo.isDir()) { - const auto widgetFiles = fileInfo.dir().entryInfoList({"*.xml", "*.html"}, QDir::Files, QDir::Name); - QByteArray data; + // check for a config.xml and read the id + QFile configFile(path + "/config.xml"); - for (const auto fileInfo : widgetFiles) + if (configFile.open(QFile::ReadOnly)) { - QFile file(fileInfo.absoluteFilePath()); + QDomDocument doc; + doc.setContent(configFile.readAll()); + QDomNodeList widgetDomList = doc.elementsByTagName("widget"); - if (file.open(QFile::ReadOnly)) + if (widgetDomList.count() > 0) { - data.append(file.readAll()); + QDomElement widgetElement = widgetDomList.item(0).toElement(); + const auto id = widgetElement.attribute("id", ""); + + if (id.startsWith("urn:uuid:")) + { + const auto uuid = QUuid{id.mid(9)}; + + if (uuid.version() == QUuid::Sha1) + { + return uuid; + } + } + else + { + return createMediaAssetUuid(id.toUtf8()); + } } } - - return createMediaAssetUuid(data); } return {}; diff --git a/src/web/UBEmbedController.cpp b/src/web/UBEmbedController.cpp index 114a986ab..7edc7d9f6 100644 --- a/src/web/UBEmbedController.cpp +++ b/src/web/UBEmbedController.cpp @@ -36,7 +36,7 @@ #include "core/UBApplication.h" -#include "domain/UBGraphicsScene.h" +#include "domain/UBMediaAssetItem.h" #include "frameworks/UBFileSystemUtils.h" @@ -198,15 +198,19 @@ void UBEmbedController::createWidget() widgetDir.mkpath(widgetDir.path()); UBEmbedContent content; + QString widgetId; if (selectedIndex == 0) { generateFullPageHtml(mUrl, widgetDir.path(), true); + widgetId = mUrl.toString(); } else { content = mAvailableContent.at(selectedIndex - 1); - generateHtml(content, widgetDir.path(), true); + const auto data = generateHtml(content, widgetDir.path(), true); + const auto mediaAssertUuid = UBMediaAssetItem::createMediaAssetUuid(data); + widgetId = "urn:uuid:" + mediaAssertUuid.toString(QUuid::WithoutBraces); } generateIcon(widgetDir.path()); @@ -216,11 +220,11 @@ void UBEmbedController::createWidget() if (heigth && width) { - generateConfig(width+20, heigth+20, widgetDir.path()); + generateConfig(widgetId, width+20, heigth+20, widgetDir.path()); } else { - generateConfig(800, 600, widgetDir.path()); + generateConfig(widgetId, 800, 600, widgetDir.path()); } importWidgetInLibrary(widgetDir); @@ -301,7 +305,7 @@ QString UBEmbedController::generateIcon(const QString& pDirPath) const } -void UBEmbedController::generateConfig(int pWidth, int pHeight, const QString& pDestinationPath) const +void UBEmbedController::generateConfig(QString widgetId, int pWidth, int pHeight, const QString& pDestinationPath) const { QFile configFile(pDestinationPath + "/" + "config.xml"); @@ -323,7 +327,7 @@ void UBEmbedController::generateConfig(int pWidth, int pHeight, const QString& p out << "" << '\n'; out << "widgetNameLineEdit->text() << "\"" <<'\n'; + out << " id=\"" << widgetId << "\"" <<'\n'; out << " version=\"2.0\"" << '\n'; out << " width=\"" << pWidth << "\"" << '\n'; diff --git a/src/web/UBEmbedController.h b/src/web/UBEmbedController.h index 7177cc8e4..e64b3a38f 100644 --- a/src/web/UBEmbedController.h +++ b/src/web/UBEmbedController.h @@ -126,7 +126,7 @@ private slots: QString generateFullPageHtml(const QUrl& url, const QString& pDirPath = QString(), bool pGenerateFile = false) const; QString generateHtml(const UBEmbedContent& pObject, const QString& pDirPath = QString(), bool pGenerateFile = false) const; QString generateIcon(const QString& pDirPath) const; - void generateConfig(int pWidth, int pHeight, const QString& pDestinationPath) const; + void generateConfig(QString widgetId, int pWidth, int pHeight, const QString& pDestinationPath) const; QString widgetNameForObject(const UBEmbedContent& pObject) const; From e745eebacd1bd8dbbe31c01b1e26615957d89fbd Mon Sep 17 00:00:00 2001 From: Philippe Mavridis Date: Sat, 27 Sep 2025 14:36:03 +0300 Subject: [PATCH 045/133] Fix input filter in greek and danish translations Signed-off-by: Philippe Mavridis --- resources/i18n/OpenBoard_da.ts | 2 +- resources/i18n/OpenBoard_el.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/i18n/OpenBoard_da.ts b/resources/i18n/OpenBoard_da.ts index 3072677d7..c4ddeada7 100644 --- a/resources/i18n/OpenBoard_da.ts +++ b/resources/i18n/OpenBoard_da.ts @@ -1914,7 +1914,7 @@ Do you wish to override the security check and continue ? All supported files (*.%1) - alle understøttede filer (*%1) + alle understøttede filer (*.%1) diff --git a/resources/i18n/OpenBoard_el.ts b/resources/i18n/OpenBoard_el.ts index c80d24c81..a1194e33a 100644 --- a/resources/i18n/OpenBoard_el.ts +++ b/resources/i18n/OpenBoard_el.ts @@ -1920,7 +1920,7 @@ Do you wish to override the security check and continue ? All supported files (*.%1) - Ολα τα υποστηριζόμενα αρχεία (%1) + Ολα τα υποστηριζόμενα αρχεία (*.%1) From 7b0de3fdb11176246b647567f7571230ac981c0a Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Wed, 15 Oct 2025 08:21:59 +0200 Subject: [PATCH 046/133] fix: wait for end of scene UUID scan - waitForFinished is not sufficient - instead wait until the finished signal has been processed and the loader was deleted Signed-off-by: letsfindaway --- src/document/UBDocument.cpp | 49 +++++++++++++++++---------- src/document/UBDocument.h | 2 +- src/frameworks/UBBackgroundLoader.cpp | 5 --- src/frameworks/UBBackgroundLoader.h | 1 - 4 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index eb140aa10..5845b21f2 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -54,7 +54,7 @@ UBDocument::~UBDocument() { if (mSceneHeaderLoader) { - mSceneHeaderLoader->waitForFinished(); + assureHeaderLoaderFinished(false); delete mSceneHeaderLoader; } @@ -132,7 +132,7 @@ void UBDocument::deletePages(QList indexes) } UBPersistenceManager::persistenceManager()->deleteDocumentScenes(mProxy, pageIds); - assureLoaderFinished(); + assureHeaderLoaderFinished(); for (int i = indexes.size() - 1; i >= 0; --i) { @@ -161,7 +161,7 @@ void UBDocument::movePage(int fromIndex, int toIndex) persistPage(scene, fromIndex); } - assureLoaderFinished(); + assureHeaderLoaderFinished(); thumbnailScene()->moveThumbnail(fromIndex, toIndex); mToc->move(fromIndex, toIndex); mToc->save(); @@ -176,7 +176,7 @@ void UBDocument::copyPage(int fromIndex, std::shared_ptr to, int toI std::shared_ptr UBDocument::createPage(int index, bool saveToc, bool cached, bool useUndoRedoStack) { // create a new TOC entry for the page - assureLoaderFinished(); + assureHeaderLoaderFinished(); auto pageId = mToc->insert(index); auto scene = UBPersistenceManager::persistenceManager()->createDocumentSceneAt(mProxy, pageId, cached, useUndoRedoStack); mToc->setUuid(index, scene->uuid()); @@ -418,7 +418,7 @@ void UBDocument::sceneLoaded(UBGraphicsScene* scene, std::shared_ptr handl void UBDocument::scanAssets() { - assureLoaderFinished(); + assureHeaderLoaderFinished(); // create a list of page IDs and paths of pages without asset info for background loading QList> paths; @@ -559,12 +559,12 @@ void UBDocument::scan(bool tocPresent) } // load the first 300 bytes of each file in background, enough to get version and UUID - UBBackgroundLoader loader{UBBackgroundLoader::ByteArray}; + mSceneHeaderLoader = new UBBackgroundLoader{UBBackgroundLoader::ByteArray}; int pageProcessed = -1; int currentPage = 0; const auto currentVersion = QVersionNumber::fromString(UBSettings::currentFileVersion); - QObject::connect(&loader, &UBBackgroundLoader::resultAvailable, &loader, [&](int index, const QVariant& data){ + QObject::connect(mSceneHeaderLoader, &UBBackgroundLoader::resultAvailable, mSceneHeaderLoader, [&](int index, const QVariant& data){ UBApplication::showMessage(UBDocumentController::tr("Scanning page %1 of %2").arg(++currentPage).arg(pages.count()), true); const auto uuid = UBSvgSubsetAdaptor::sceneUuid(data.toByteArray()); @@ -596,10 +596,10 @@ void UBDocument::scan(bool tocPresent) mToc->setPageId(pageProcessed, index); } - loader.resultProcessed(); + mSceneHeaderLoader->resultProcessed(); }); - QObject::connect(&loader, &UBBackgroundLoader::finished, &loader, [&](){ + QObject::connect(mSceneHeaderLoader, &UBBackgroundLoader::finished, mSceneHeaderLoader, [&](){ // When finished, remove all scenes still in tocSceneUuids from the TOC. // Those scenes might have been deleted using a previous version of OpenBoard. for (const auto uuid : tocSceneUuids) @@ -609,11 +609,13 @@ void UBDocument::scan(bool tocPresent) } UBApplication::showMessage(UBDocumentController::tr("Scan completed")); + mSceneHeaderLoader->deleteLater(); + mSceneHeaderLoader = nullptr; mToc->save(); }); - loader.load(paths, 300); - loader.waitForFinished(); + mSceneHeaderLoader->load(paths, 300); + assureHeaderLoaderFinished(); } else if (!paths.empty()) { @@ -656,7 +658,7 @@ void UBDocument::copyPage(int fromIndex, UBDocument* to, int toIndex) const auto dependencies = pageRelativeDependencies(fromIndex); // copy scene - to->assureLoaderFinished(); + to->assureHeaderLoaderFinished(); const auto pageId = to->mToc->insert(toIndex); const auto uuid = UBPersistenceManager::persistenceManager()->copyDocumentScene(mProxy, mToc->pageId(fromIndex), to->proxy(), pageId, dependencies); @@ -694,15 +696,26 @@ void UBDocument::deleteUnreferencedAssets() UBPersistenceManager::persistenceManager()->cleanupMediaAssets(mProxy, referencedMediaAssets); } -void UBDocument::assureLoaderFinished() +void UBDocument::assureHeaderLoaderFinished(bool visualFeedback) { if (mSceneHeaderLoader) { - UBApplication::setOverrideCursor(Qt::WaitCursor); - UBApplication::showMessage(UBDocumentController::tr("Wait for the document scan to finish"), true); - mSceneHeaderLoader->waitForFinished(); - UBApplication::showMessage(UBDocumentController::tr("Document scan finished")); - UBApplication::restoreOverrideCursor(); + if (visualFeedback) + { + UBApplication::setOverrideCursor(Qt::WaitCursor); + UBApplication::showMessage(UBDocumentController::tr("Wait for the document scan to finish"), true); + } + + while (mSceneHeaderLoader) + { + QApplication::processEvents(QEventLoop::AllEvents, 100); + } + + if (visualFeedback) + { + UBApplication::showMessage(UBDocumentController::tr("Document scan finished")); + UBApplication::restoreOverrideCursor(); + } } } diff --git a/src/document/UBDocument.h b/src/document/UBDocument.h index a87d29127..2956d7d73 100644 --- a/src/document/UBDocument.h +++ b/src/document/UBDocument.h @@ -87,7 +87,7 @@ class UBDocument : public std::enable_shared_from_this void scan(bool tocPresent); void copyPage(int fromIndex, UBDocument* to, int toIndex); void deleteUnreferencedAssets(); - void assureLoaderFinished(); + void assureHeaderLoaderFinished(bool visualFeedback = true); static std::shared_ptr findDocument(std::shared_ptr proxy); diff --git a/src/frameworks/UBBackgroundLoader.cpp b/src/frameworks/UBBackgroundLoader.cpp index 99909739b..fc19b4a2b 100644 --- a/src/frameworks/UBBackgroundLoader.cpp +++ b/src/frameworks/UBBackgroundLoader.cpp @@ -85,11 +85,6 @@ void UBBackgroundLoader::abort() mFuture.cancel(); } -void UBBackgroundLoader::waitForFinished() -{ - mFuture.waitForFinished(); -} - void UBBackgroundLoader::setKeepAlive(std::shared_ptr keepAlive) { mKeepAlive = keepAlive; diff --git a/src/frameworks/UBBackgroundLoader.h b/src/frameworks/UBBackgroundLoader.h index 94908c68e..4b825ebf9 100644 --- a/src/frameworks/UBBackgroundLoader.h +++ b/src/frameworks/UBBackgroundLoader.h @@ -45,7 +45,6 @@ class UBBackgroundLoader : public QObject void load(const QList>& paths, int maxBytes = -1, std::function preCheck = nullptr); void abort(); - void waitForFinished(); void setKeepAlive(std::shared_ptr keepAlive); public slots: From 8a6f6497438ce323ac81e2f2a71ec69b2faf20ee Mon Sep 17 00:00:00 2001 From: "sebastian.vallet" Date: Sat, 19 Oct 2024 02:18:49 +0200 Subject: [PATCH 047/133] First commit of the feature: 'Filtering documents'. --- resources/forms/documents.ui | 31 +++++-------------------- src/document/UBDocumentController.cpp | 7 ++++++ src/document/UBDocumentController.h | 1 + src/document/UBSortFilterProxyModel.cpp | 21 +++++++++++++++++ src/document/UBSortFilterProxyModel.h | 6 ++--- src/gui/UBFeaturesWidget.cpp | 1 + 6 files changed, 39 insertions(+), 28 deletions(-) diff --git a/resources/forms/documents.ui b/resources/forms/documents.ui index 921ca08d5..694a050be 100644 --- a/resources/forms/documents.ui +++ b/resources/forms/documents.ui @@ -102,22 +102,6 @@ - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 10 - 20 - - - - @@ -146,17 +130,14 @@ - - - Qt::Horizontal + + + filter the documents - - - 40 - 20 - + + true - + diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index ec4ba3f19..d2c685833 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -2257,6 +2257,7 @@ void UBDocumentController::setupViews() connect(mDocumentUI->sortKind, SIGNAL(activated(int)), this, SLOT(onSortKindChanged(int))); connect(mDocumentUI->sortOrder, SIGNAL(toggled(bool)), this, SLOT(onSortOrderChanged(bool))); + connect(mDocumentUI->filterText, &QLineEdit::textChanged, this, &UBDocumentController::onFilterTextChanged); connect(mDocumentUI->splitter, SIGNAL(splitterMoved(int,int)), this, SLOT(onSplitterMoved(int, int))); @@ -2361,6 +2362,12 @@ void UBDocumentController::onSortKindChanged(int index) UBSettings::settings()->documentSortKind->setInt(index); } +void UBDocumentController::onFilterTextChanged(const QString& filter) +{ + mSortFilterProxyModel->setFilterCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive); + mSortFilterProxyModel->setFilterRegularExpression(filter); +} + void UBDocumentController::onSplitterMoved(int size, int index) { Q_UNUSED(index); diff --git a/src/document/UBDocumentController.h b/src/document/UBDocumentController.h index bd094bbb0..e0389e31a 100644 --- a/src/document/UBDocumentController.h +++ b/src/document/UBDocumentController.h @@ -506,6 +506,7 @@ class UBDocumentController : public UBDocumentContainer //N/C - NNE - 20140403 void onSortKindChanged(int index); void onSortOrderChanged(bool order); + void onFilterTextChanged(const QString& filter); void onSplitterMoved(int size, int index); void collapseAll(); void expandAll(); diff --git a/src/document/UBSortFilterProxyModel.cpp b/src/document/UBSortFilterProxyModel.cpp index b46465fba..f8ec96a99 100644 --- a/src/document/UBSortFilterProxyModel.cpp +++ b/src/document/UBSortFilterProxyModel.cpp @@ -23,3 +23,24 @@ bool UBSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex return QSortFilterProxyModel::lessThan(left, right); } + +bool UBSortFilterProxyModel::filterAcceptsRow(int sourceRow, + const QModelIndex &sourceParent) const +{ + UBDocumentTreeModel *model = dynamic_cast(sourceModel()); + if(model == nullptr) + { + return false; + } + + if(model->isCatalog(model->index(sourceRow, 0, sourceParent))) + { + // Always show the catalog folders + return true; + } + else + { + // Filter the documents + return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); + } +} diff --git a/src/document/UBSortFilterProxyModel.h b/src/document/UBSortFilterProxyModel.h index 97afba9f6..c4fef8905 100644 --- a/src/document/UBSortFilterProxyModel.h +++ b/src/document/UBSortFilterProxyModel.h @@ -2,14 +2,14 @@ #define UBSORTFILTERPROXYMODEL_H #include -#include "core/UBPersistenceManager.h" class UBSortFilterProxyModel : public QSortFilterProxyModel { public: UBSortFilterProxyModel(); - bool lessThan(const QModelIndex &left, const QModelIndex &right) const; +protected: + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; }; - #endif // UBSORTFILTERPROXYMODEL_H diff --git a/src/gui/UBFeaturesWidget.cpp b/src/gui/UBFeaturesWidget.cpp index 0fb015851..40ad99846 100644 --- a/src/gui/UBFeaturesWidget.cpp +++ b/src/gui/UBFeaturesWidget.cpp @@ -35,6 +35,7 @@ #include "frameworks/UBFileSystemUtils.h" #include "core/UBApplication.h" #include "core/UBDownloadManager.h" +#include "core/UBPersistenceManager.h" #include "globals/UBGlobals.h" #include "board/UBBoardController.h" #include "document/UBDocumentController.h" From 41eceb0509dadd823adaff9fc3eefb3cb91b0c25 Mon Sep 17 00:00:00 2001 From: "sebastian.vallet" Date: Sat, 26 Oct 2024 15:56:14 +0200 Subject: [PATCH 048/133] We clear the filter lineedit if we show again the document mode. --- src/document/UBDocumentController.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index d2c685833..81c32f5a9 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -2413,6 +2413,8 @@ void UBDocumentController::show() if(!mToolsPalette) setupPalettes(); + + mDocumentUI->filterText->clear(); } From e8ed592e9fe580489d3fe655650b501196e798db Mon Sep 17 00:00:00 2001 From: "sebastian.vallet" Date: Wed, 15 Oct 2025 15:58:44 +0200 Subject: [PATCH 049/133] Fixes this review's comment https://github.com/OpenBoard-org/OpenBoard/pull/1142#discussion_r2425604889 --- src/document/UBSortFilterProxyModel.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/document/UBSortFilterProxyModel.cpp b/src/document/UBSortFilterProxyModel.cpp index f8ec96a99..3d7d498c2 100644 --- a/src/document/UBSortFilterProxyModel.cpp +++ b/src/document/UBSortFilterProxyModel.cpp @@ -6,6 +6,7 @@ UBSortFilterProxyModel::UBSortFilterProxyModel(): { setDynamicSortFilter(false); setSortCaseSensitivity(Qt::CaseInsensitive); + setRecursiveFilteringEnabled(true); } bool UBSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const @@ -32,14 +33,18 @@ bool UBSortFilterProxyModel::filterAcceptsRow(int sourceRow, { return false; } - - if(model->isCatalog(model->index(sourceRow, 0, sourceParent))) - { - // Always show the catalog folders - return true; - } else { + QModelIndex idx = model->index(sourceRow, 0, sourceParent); + + if (idx.isValid()) + { + if (idx == model->myDocumentsIndex() || idx == model->trashIndex()) + { + return true; + } + } + // Filter the documents return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); } From 59da559810bd4442fcf6dd86cc191c6c39b8caaf Mon Sep 17 00:00:00 2001 From: "sebastian.vallet" Date: Thu, 16 Oct 2025 23:33:43 +0200 Subject: [PATCH 050/133] Fixes this review's comment https://github.com/OpenBoard-org/OpenBoard/pull/1142/files#r2425684980 --- src/document/UBDocumentController.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index 81c32f5a9..d2a6f4537 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -2366,6 +2366,15 @@ void UBDocumentController::onFilterTextChanged(const QString& filter) { mSortFilterProxyModel->setFilterCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive); mSortFilterProxyModel->setFilterRegularExpression(filter); + + if (filter.isEmpty()) + { + collapseAll(); + } + else + { + expandAll(); + } } void UBDocumentController::onSplitterMoved(int size, int index) From 54ce6a245af7a0aa90b3f7d0e9ea3352fc8e4631 Mon Sep 17 00:00:00 2001 From: "sebastian.vallet" Date: Thu, 16 Oct 2025 23:50:34 +0200 Subject: [PATCH 051/133] Fixes this review's comment https://github.com/OpenBoard-org/OpenBoard/pull/1142/files#r2425728609 --- src/document/UBDocumentController.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index d2a6f4537..2c680f1bd 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -1895,6 +1895,8 @@ UBDocumentController::~UBDocumentController() void UBDocumentController::createNewDocument() { + mDocumentUI->filterText->clear(); + UBPersistenceManager *pManager = UBPersistenceManager::persistenceManager(); UBDocumentTreeModel *docModel = pManager->mDocumentTreeStructureModel; QModelIndex selectedIndex = firstSelectedTreeIndex(); @@ -1953,6 +1955,8 @@ void UBDocumentController::selectDocument(std::shared_ptr proxy void UBDocumentController::createNewDocumentGroup() { + mDocumentUI->filterText->clear(); + UBPersistenceManager *pManager = UBPersistenceManager::persistenceManager(); UBDocumentTreeModel *docModel = pManager->mDocumentTreeStructureModel; QModelIndex selectedIndex = firstSelectedTreeIndex(); @@ -3095,6 +3099,8 @@ void UBDocumentController::documentZoomSliderValueChanged (int value) void UBDocumentController::importFile() { + mDocumentUI->filterText->clear(); + UBDocumentManager *docManager = UBDocumentManager::documentManager(); QString defaultPath = UBSettings::settings()->lastImportFilePath->get().toString(); @@ -3929,6 +3935,8 @@ bool UBDocumentController::firstAndOnlySceneSelected() const void UBDocumentController::createNewDocumentInUntitledFolder() { + mDocumentUI->filterText->clear(); + UBPersistenceManager *pManager = UBPersistenceManager::persistenceManager(); UBDocumentTreeModel *docModel = pManager->mDocumentTreeStructureModel; From 796b5a282eb70f5faa20a7cd3215f38a4bb12175 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Fri, 17 Oct 2025 07:08:31 +0200 Subject: [PATCH 052/133] fix: duplicate items - always duplicate items instead of creating a new item based on data from the original - avoid quality loss when duplicating images - use item UUIDs to distinguish items in ClearUndoStack - remove sourceUrl from UBItem and derived classes as it is no longer used Signed-off-by: letsfindaway --- src/adaptors/UBSvgSubsetAdaptor.cpp | 10 -- src/board/UBBoardController.cpp | 206 +++++++------------------- src/board/UBBoardPaletteManager.cpp | 10 +- src/domain/UBGraphicsItemDelegate.cpp | 8 +- src/domain/UBGraphicsMediaItem.cpp | 6 - src/domain/UBGraphicsMediaItem.h | 1 - src/domain/UBGraphicsPDFItem.cpp | 1 - src/domain/UBGraphicsPixmapItem.cpp | 1 - src/domain/UBGraphicsSvgItem.cpp | 1 - src/domain/UBGraphicsTextItem.cpp | 1 - src/domain/UBGraphicsWidgetItem.cpp | 2 - src/domain/UBItem.h | 14 +- 12 files changed, 59 insertions(+), 202 deletions(-) diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index db98af0d6..96ce24757 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -2488,11 +2488,6 @@ void UBSvgSubsetAdaptor::UBSvgSubsetReader::graphicsItemFromSvg(QGraphicsItem* g ubItem->setUuid(QUuid(ubUuid.toString())); else ubItem->setUuid(QUuid::createUuid()); - - auto ubSource = mXmlReader.attributes().value(mNamespaceUri, "source"); - - if (!ubSource.isNull()) - ubItem->setSourceUrl(QUrl(ubSource.toString())); } auto ubLocked = mXmlReader.attributes().value(mNamespaceUri, "locked"); @@ -2590,11 +2585,6 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::graphicsItemToSvg(QGraphicsItem* ite if (ubItem) { mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "uuid", UBStringUtils::toCanonicalUuid(ubItem->uuid())); - - QUrl sourceUrl = ubItem->sourceUrl(); - - if (!sourceUrl.isEmpty()) - mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "source", sourceUrl.path()); } QVariant layer = item->data(UBGraphicsItemData::ItemLayerType); diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index 02cb0c489..6162b90e6 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -692,104 +692,46 @@ void UBBoardController::duplicateScene() UBGraphicsItem *UBBoardController::duplicateItem(UBItem *item) { if (!item) - return NULL; - - UBGraphicsItem *retItem = NULL; + { + return {}; + } - mLastCreatedItem = NULL; + UBGraphicsItem* retItem{nullptr}; - QUrl sourceUrl; - QByteArray pData; + mLastCreatedItem = nullptr; //common parameters for any item QPointF itemPos; QSizeF itemSize; - QGraphicsItem *commonItem = dynamic_cast(item); + QGraphicsItem* commonItem = dynamic_cast(item); + if (commonItem) { qreal shifting = UBSettings::settings()->objectFrameWidth; itemPos = commonItem->pos() + QPointF(shifting,shifting); itemSize = commonItem->boundingRect().size(); commonItem->setSelected(false); - } - UBMimeType::Enum itemMimeType; - - QString srcFile = item->sourceUrl().toLocalFile(); - if (srcFile.isEmpty()) - srcFile = item->sourceUrl().toString(); - - QString contentTypeHeader; - if (!srcFile.isEmpty()) - contentTypeHeader = UBFileSystemUtils::mimeTypeFromFileName(srcFile); - - if(NULL != qgraphicsitem_cast(commonItem)) - itemMimeType = UBMimeType::Group; - else - itemMimeType = UBFileSystemUtils::mimeTypeFromString(contentTypeHeader); - - switch(static_cast(itemMimeType)) - { - case UBMimeType::AppleWidget: - case UBMimeType::W3CWidget: - { - UBGraphicsWidgetItem *witem = dynamic_cast(item); - if (witem) - { - sourceUrl = witem->getOwnFolder(); - } - }break; - - case UBMimeType::Video: - case UBMimeType::Audio: - { - UBGraphicsMediaItem *mitem = dynamic_cast(item); - if (mitem) - { - sourceUrl = mitem->mediaFileUrl(); - downloadURL(sourceUrl, srcFile, itemPos, QSize(itemSize.width(), itemSize.height()), false, false); - return NULL; // async operation - } - }break; - - case UBMimeType::VectorImage: - { - UBGraphicsSvgItem *viitem = dynamic_cast(item); - if (viitem) - { - pData = viitem->fileData(); - sourceUrl = item->sourceUrl(); - } - }break; - - case UBMimeType::RasterImage: - { - UBGraphicsPixmapItem *pixitem = dynamic_cast(item); - if (pixitem) - { - QBuffer buffer(&pData); - buffer.open(QIODevice::WriteOnly); - QString format = UBFileSystemUtils::extension(item->sourceUrl().toString(QUrl::DecodeReserved)); - pixitem->pixmap().save(&buffer, format.toLatin1()); - } - }break; - - case UBMimeType::Group: + if (commonItem->type() == UBGraphicsItemType::groupContainerType) { UBGraphicsGroupContainerItem* groupItem = dynamic_cast(item); - UBGraphicsGroupContainerItem* duplicatedGroup = NULL; + UBGraphicsGroupContainerItem* duplicatedGroup{nullptr}; QList duplicatedItems; - QList children = groupItem->childItems(); + const QList children = groupItem->childItems(); mActiveScene->setURStackEnable(false); - foreach(QGraphicsItem* pIt, children){ + + for (QGraphicsItem* pIt : children) + { UBItem* pItem = dynamic_cast(pIt); - if(pItem) + + if (pItem) { - QGraphicsItem * itemToGroup = dynamic_cast(duplicateItem(pItem)); + QGraphicsItem* itemToGroup = dynamic_cast(duplicateItem(pItem)); + if (itemToGroup) { itemToGroup->setZValue(pIt->zValue()); @@ -798,70 +740,54 @@ UBGraphicsItem *UBBoardController::duplicateItem(UBItem *item) } } } + duplicatedGroup = mActiveScene->createGroup(duplicatedItems); duplicatedGroup->setTransform(groupItem->transform()); groupItem->copyItemParameters(duplicatedGroup); groupItem->setSelected(false); + mActiveScene->addItem(duplicatedGroup); + duplicatedGroup->setSelected(true); - retItem = dynamic_cast(duplicatedGroup); - - QGraphicsItem * itemToAdd = dynamic_cast(retItem); - if (itemToAdd) - { - mActiveScene->addItem(itemToAdd); - itemToAdd->setSelected(true); - } mActiveScene->setURStackEnable(true); - }break; - case UBMimeType::UNKNOWN: + retItem = duplicatedGroup; + } + else + { + QGraphicsItem *copiedItem = dynamic_cast(item); + QGraphicsItem *gitem = dynamic_cast(item->deepCopy()); + + if (gitem) { - QGraphicsItem *copiedItem = dynamic_cast(item); - QGraphicsItem *gitem = dynamic_cast(item->deepCopy()); - if (gitem) - { - mActiveScene->addItem(gitem); + mActiveScene->addItem(gitem); - if (copiedItem) + if (copiedItem) + { + if (mActiveScene->tools().contains(copiedItem)) { - if (mActiveScene->tools().contains(copiedItem)) - { - mActiveScene->registerTool(gitem); - } + mActiveScene->registerTool(gitem); } - gitem->setPos(itemPos); - - mLastCreatedItem = gitem; - gitem->setSelected(true); } - retItem = dynamic_cast(gitem); - }break; + gitem->setPos(itemPos); + + mLastCreatedItem = gitem; + gitem->setSelected(true); + } + + retItem = dynamic_cast(gitem); } if (retItem) { QGraphicsItem *graphicsRetItem = dynamic_cast(retItem); - if (mActiveScene->isURStackIsEnabled()) { //should be deleted after scene own undo stack implemented + + if (mActiveScene->isURStackIsEnabled()) + { + //should be deleted after scene own undo stack implemented UBGraphicsItemUndoCommand* uc = new UBGraphicsItemUndoCommand(mActiveScene, 0, graphicsRetItem); UBApplication::undoStack->push(uc); } - return retItem; - } - - UBItem *createdItem = downloadFinished(true, sourceUrl, QUrl::fromLocalFile(srcFile), contentTypeHeader, pData, itemPos, QSize(itemSize.width(), itemSize.height()), false); - if (createdItem) - { - createdItem->setSourceUrl(item->sourceUrl()); - item->copyItemParameters(createdItem); - - QGraphicsItem *createdGitem = dynamic_cast(createdItem); - if (createdGitem) - createdGitem->setPos(itemPos); - mLastCreatedItem = dynamic_cast(createdItem); - mLastCreatedItem->setSelected(true); - - retItem = dynamic_cast(createdItem); } return retItem; @@ -1283,20 +1209,6 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl UBGraphicsPixmapItem* pixItem = mActiveScene->addImage(pData, nullptr, pPos, 1.); - if (scheme == "data") - { - // create a shorter, but still unique URL using a hash function - QCryptographicHash hash(QCryptographicHash::Md5); - hash.addData(sourceUrl.toString().toLatin1()); - QByteArray result = hash.result(); - QString hashedUrl = "md5:" + result.toBase64(); - pixItem->setSourceUrl(hashedUrl); - } - else - { - pixItem->setSourceUrl(sourceUrl); - } - if (isBackground) { mActiveScene->setAsBackgroundObject(pixItem, true); @@ -1314,7 +1226,6 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl qDebug() << "accepting mime type" << mimeType << "as vector image"; UBGraphicsSvgItem* svgItem = mActiveScene->addSvg(sourceUrl, pPos, pData); - svgItem->setSourceUrl(sourceUrl); if (isBackground) { @@ -1341,8 +1252,6 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl UBGraphicsWidgetItem* appleWidgetItem = mActiveScene->addAppleWidget(widgetUrl, pPos); - appleWidgetItem->setSourceUrl(sourceUrl); - if (isBackground) { mActiveScene->setAsBackgroundObject(appleWidgetItem); @@ -1407,11 +1316,8 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl mediaVideoItem = addVideo(sourceUrl, false, pPos); } - if(mediaVideoItem){ - if (contentUrl.isEmpty()) - mediaVideoItem->setSourceUrl(sourceUrl); - else - mediaVideoItem->setSourceUrl(contentUrl); + if (mediaVideoItem) + { connect(this, SIGNAL(activeSceneChanged()), mediaVideoItem, SLOT(activeSceneChanged())); } @@ -1448,11 +1354,8 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl audioMediaItem = addAudio(sourceUrl, false, pPos); } - if(audioMediaItem){ - if (contentUrl.isEmpty()) - audioMediaItem->setSourceUrl(sourceUrl); - else - audioMediaItem->setSourceUrl(contentUrl); + if (audioMediaItem) + { connect(this, SIGNAL(activeSceneChanged()), audioMediaItem, SLOT(activeSceneChanged())); } @@ -1489,7 +1392,6 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl { UBGraphicsWidgetItem *widgetItem = mActiveScene->addW3CWidget(QUrl::fromLocalFile(widgetUrl), pPos); widgetItem->setUuid(QUuid::createUuid()); - widgetItem->setSourceUrl(QUrl::fromLocalFile(widgetUrl)); qDebug() << widgetItem->getOwnFolder(); qDebug() << widgetItem->getSnapshotPath(); @@ -1805,14 +1707,14 @@ void UBBoardController::ClearUndoStack() // This ensures that we can cut and paste a media item, widget, etc. from one page to the next. QClipboard *clipboard = QApplication::clipboard(); const QMimeData* data = clipboard->mimeData(); - QList sourceURLs; + QList sourceUUIDs; if (data && data->hasFormat(UBApplication::mimeTypeUniboardPageItem)) { const UBMimeDataGraphicsItem* mimeDataGI = qobject_cast (data); if (mimeDataGI) { foreach (UBItem* sourceItem, mimeDataGI->items()) { - sourceURLs << sourceItem->sourceUrl(); + sourceUUIDs << sourceItem->uuid(); } } } @@ -1830,7 +1732,7 @@ void UBBoardController::ClearUndoStack() bool inClipboard = false; UBItem* ubi = dynamic_cast(item); - if (ubi && sourceURLs.contains(ubi->sourceUrl())) + if (ubi && sourceUUIDs.contains(ubi->uuid())) inClipboard = true; if(!scene && !inClipboard) @@ -2347,7 +2249,6 @@ UBGraphicsMediaItem* UBBoardController::addVideo(const QUrl& pSourceUrl, bool st if (vi) { vi->setUuid(uuid); - vi->setSourceUrl(pSourceUrl); } return vi; @@ -2363,9 +2264,9 @@ UBGraphicsMediaItem* UBBoardController::addAudio(const QUrl& pSourceUrl, bool st QDateTime now = QDateTime::currentDateTime(); selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(now)); - if (ai){ + if (ai) + { ai->setUuid(uuid); - ai->setSourceUrl(pSourceUrl); } return ai; @@ -2394,7 +2295,6 @@ UBGraphicsWidgetItem *UBBoardController::addW3cWidget(const QUrl &pUrl, const QP if (w3cWidgetItem) { w3cWidgetItem->setOwnFolder(newUrl); - w3cWidgetItem->setSourceUrl(pUrl); QString struuid = w3cWidgetItem->uuid().toString(QUuid::WithoutBraces); QString snapshotPath = selectedDocument()->persistencePath() + "/" + UBPersistenceManager::widgetDirectory + "/" + struuid + ".png"; diff --git a/src/board/UBBoardPaletteManager.cpp b/src/board/UBBoardPaletteManager.cpp index 852281ac4..e81bc95a0 100644 --- a/src/board/UBBoardPaletteManager.cpp +++ b/src/board/UBBoardPaletteManager.cpp @@ -874,17 +874,15 @@ void UBBoardPaletteManager::addItemToCurrentPage() { UBApplication::applicationController->showBoard(); mAddItemPalette->hide(); - if(mPixmap.isNull()) + + if (mPixmap.isNull()) + { UBApplication::boardController->downloadURL(mItemUrl); + } else { UBGraphicsPixmapItem* item = UBApplication::boardController->activeScene()->addPixmap(mPixmap, NULL, mPos, mScaleFactor); - QString documentPath = UBApplication::boardController->selectedDocument()->persistencePath(); - QString fileName = UBPersistenceManager::imageDirectory + "/" + item->uuid().toString() + ".png"; - QString path = documentPath + "/" + fileName; - - item->setSourceUrl(QUrl(path)); item->setSelected(true); UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); diff --git a/src/domain/UBGraphicsItemDelegate.cpp b/src/domain/UBGraphicsItemDelegate.cpp index 764861579..846fb20ec 100644 --- a/src/domain/UBGraphicsItemDelegate.cpp +++ b/src/domain/UBGraphicsItemDelegate.cpp @@ -719,13 +719,7 @@ void UBGraphicsItemDelegate::setAsBackground() void UBGraphicsItemDelegate::gotoContentSource() { - UBItem* item = dynamic_cast(mDelegated); - - if(item && !item->sourceUrl().isEmpty()) - { - UBApplication::applicationController->showInternet(); - UBApplication::webController->loadUrl(item->sourceUrl()); - } + // only used in UBGraphicsWidgetItemDelegate } void UBGraphicsItemDelegate::startUndoStep() diff --git a/src/domain/UBGraphicsMediaItem.cpp b/src/domain/UBGraphicsMediaItem.cpp index f5b0cf948..edf39db9d 100644 --- a/src/domain/UBGraphicsMediaItem.cpp +++ b/src/domain/UBGraphicsMediaItem.cpp @@ -354,11 +354,6 @@ void UBGraphicsMediaItem::setSelected(bool selected) QGraphicsRectItem::setSelected(selected); } -void UBGraphicsMediaItem::setSourceUrl(const QUrl &pSourceUrl) -{ - UBItem::setSourceUrl(pSourceUrl); -} - void UBGraphicsMediaItem::toggleMute() { mMuted = !mMuted; @@ -523,7 +518,6 @@ void UBGraphicsMediaItem::copyItemParameters(UBItem *copy) const cp->setData(UBGraphicsItemData::ItemLocked, this->data(UBGraphicsItemData::ItemLocked)); cp->setData(UBGraphicsItemData::ItemIsHiddenOnDisplay, this->data(UBGraphicsItemData::ItemIsHiddenOnDisplay)); cp->setData(UBGraphicsItemData::ItemOwnZValue, this->data(UBGraphicsItemData::ItemOwnZValue)); - cp->setSourceUrl(this->sourceUrl()); cp->setSize(rect().width(), rect().height()); cp->setZValue(this->zValue()); diff --git a/src/domain/UBGraphicsMediaItem.h b/src/domain/UBGraphicsMediaItem.h index ece59f53e..7b2d2ea72 100644 --- a/src/domain/UBGraphicsMediaItem.h +++ b/src/domain/UBGraphicsMediaItem.h @@ -104,7 +104,6 @@ class UBGraphicsMediaItem : public QObject, public UBMediaAssetItem, public UBGr virtual void setMediaFileUrl(QUrl url); void setInitialPos(qint64 p); void setMediaPos(qint64 p); - virtual void setSourceUrl(const QUrl &pSourceUrl) override; void setSelected(bool selected); void setMinimumSize(const QSize& size); diff --git a/src/domain/UBGraphicsPDFItem.cpp b/src/domain/UBGraphicsPDFItem.cpp index 943092048..6dbcd4607 100644 --- a/src/domain/UBGraphicsPDFItem.cpp +++ b/src/domain/UBGraphicsPDFItem.cpp @@ -145,7 +145,6 @@ void UBGraphicsPDFItem::copyItemParameters(UBItem *copy) const cp->setFlag(QGraphicsItem::ItemIsSelectable, true); cp->setData(UBGraphicsItemData::ItemLayerType, this->data(UBGraphicsItemData::ItemLayerType)); cp->setData(UBGraphicsItemData::ItemOwnZValue, this->data(UBGraphicsItemData::ItemOwnZValue)); - cp->setSourceUrl(this->sourceUrl()); cp->setZValue(this->zValue()); } } diff --git a/src/domain/UBGraphicsPixmapItem.cpp b/src/domain/UBGraphicsPixmapItem.cpp index 21f95fd2f..be1683821 100644 --- a/src/domain/UBGraphicsPixmapItem.cpp +++ b/src/domain/UBGraphicsPixmapItem.cpp @@ -173,7 +173,6 @@ void UBGraphicsPixmapItem::copyItemParameters(UBItem *copy) const cp->setData(UBGraphicsItemData::ItemLocked, this->data(UBGraphicsItemData::ItemLocked)); cp->setData(UBGraphicsItemData::ItemIsHiddenOnDisplay, this->data(UBGraphicsItemData::ItemIsHiddenOnDisplay)); cp->setData(UBGraphicsItemData::ItemOwnZValue, this->data(UBGraphicsItemData::ItemOwnZValue)); - cp->setSourceUrl(this->sourceUrl()); cp->setZValue(this->zValue()); cp->mMediaAsset = mMediaAsset; diff --git a/src/domain/UBGraphicsSvgItem.cpp b/src/domain/UBGraphicsSvgItem.cpp index 6cb89af5c..598743070 100644 --- a/src/domain/UBGraphicsSvgItem.cpp +++ b/src/domain/UBGraphicsSvgItem.cpp @@ -196,7 +196,6 @@ void UBGraphicsSvgItem::copyItemParameters(UBItem *copy) const cp->setData(UBGraphicsItemData::ItemLocked, this->data(UBGraphicsItemData::ItemLocked)); cp->setData(UBGraphicsItemData::ItemIsHiddenOnDisplay, this->data(UBGraphicsItemData::ItemIsHiddenOnDisplay)); cp->setData(UBGraphicsItemData::ItemOwnZValue, this->data(UBGraphicsItemData::ItemOwnZValue)); - cp->setSourceUrl(this->sourceUrl()); cp->setZValue(this->zValue()); cp->mMediaAssetUuid = mMediaAssetUuid; } diff --git a/src/domain/UBGraphicsTextItem.cpp b/src/domain/UBGraphicsTextItem.cpp index d83bb3ecd..2043dc36b 100644 --- a/src/domain/UBGraphicsTextItem.cpp +++ b/src/domain/UBGraphicsTextItem.cpp @@ -376,7 +376,6 @@ void UBGraphicsTextItem::copyItemParameters(UBItem *copy) const cp->setTextWidth(this->textWidth()); cp->setTextHeight(this->textHeight()); - cp->setSourceUrl(this->sourceUrl()); cp->setZValue(this->zValue()); } } diff --git a/src/domain/UBGraphicsWidgetItem.cpp b/src/domain/UBGraphicsWidgetItem.cpp index 78bafdb25..1a3417b43 100644 --- a/src/domain/UBGraphicsWidgetItem.cpp +++ b/src/domain/UBGraphicsWidgetItem.cpp @@ -1025,7 +1025,6 @@ void UBGraphicsAppleWidgetItem::copyItemParameters(UBItem *copy) const cp->setDatastoreEntry(key, mDatastore.value(key)); } - cp->setSourceUrl(this->sourceUrl()); cp->setZValue(this->zValue()); } @@ -1496,7 +1495,6 @@ void UBGraphicsW3CWidgetItem::copyItemParameters(UBItem *copy) const cp->setData(UBGraphicsItemData::ItemLocked, this->data(UBGraphicsItemData::ItemLocked)); cp->setData(UBGraphicsItemData::ItemIsHiddenOnDisplay, this->data(UBGraphicsItemData::ItemIsHiddenOnDisplay)); cp->setData(UBGraphicsItemData::ItemOwnZValue, this->data(UBGraphicsItemData::ItemOwnZValue)); - cp->setSourceUrl(this->sourceUrl()); cp->resize(this->size()); diff --git a/src/domain/UBItem.h b/src/domain/UBItem.h index e96ca67ec..23b6416a4 100644 --- a/src/domain/UBItem.h +++ b/src/domain/UBItem.h @@ -31,7 +31,7 @@ #define UBITEM_H #include -#include "core/UB.h" + #include "domain/UBGraphicsItemDelegate.h" class UBGraphicsScene; @@ -92,24 +92,12 @@ class UBItem return 0; } - virtual QUrl sourceUrl() const - { - return mSourceUrl; - } - - virtual void setSourceUrl(const QUrl& pSourceUrl) - { - mSourceUrl = pSourceUrl; - } - protected: QUuid mUuid; RenderingQuality mRenderingQuality; - QUrl mSourceUrl; - CacheBehavior mCacheBehavior; }; From ad894f39963d7bfa5c549926356af11bb630b57d Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 20 Oct 2025 11:41:41 +0200 Subject: [PATCH 053/133] fix: check for existing scene - directly inform UBDocument from UBSceneCacheEntry when scene loading completed - make document proxy accessible from UBSvgReaderContext - remove loadingCompleted from UBGraphicsScene - check for existing scene in UBDocument::sceneLoaded - check for existing scene in PDF export Signed-off-by: letsfindaway --- src/adaptors/UBExportFullPDF.cpp | 12 ++++ src/adaptors/UBExportPDF.cpp | 6 ++ src/adaptors/UBSvgSubsetAdaptor.cpp | 5 ++ src/adaptors/UBSvgSubsetAdaptor.h | 2 + src/core/UBSceneCache.cpp | 8 ++- src/document/UBDocument.cpp | 89 +++++++++++++++-------------- src/domain/UBGraphicsScene.cpp | 6 -- src/domain/UBGraphicsScene.h | 1 - 8 files changed, 77 insertions(+), 52 deletions(-) diff --git a/src/adaptors/UBExportFullPDF.cpp b/src/adaptors/UBExportFullPDF.cpp index c2188b4fa..87f04c74e 100644 --- a/src/adaptors/UBExportFullPDF.cpp +++ b/src/adaptors/UBExportFullPDF.cpp @@ -108,6 +108,12 @@ void UBExportFullPDF::saveOverlayPdf(std::shared_ptr pDocumentP for(int pageIndex = 0 ; pageIndex < document->pageCount(); pageIndex++) { std::shared_ptr scene = document->loadScene(pageIndex); + + if (!scene) + { + continue; + } + // set background according to PDF export settings bool isDark = scene->isDarkBackground(); UBPageBackground pageBackground = scene->pageBackground(); @@ -225,6 +231,12 @@ bool UBExportFullPDF::persistsDocument(std::shared_ptr pDocumen for(int pageIndex = 0 ; pageIndex < existingPageCount; pageIndex++) { std::shared_ptr scene = document->loadScene(pageIndex); + + if (!scene) + { + continue; + } + UBGraphicsPDFItem *pdfItem = qgraphicsitem_cast(scene->backgroundObject()); if (pdfItem) diff --git a/src/adaptors/UBExportPDF.cpp b/src/adaptors/UBExportPDF.cpp index d05797ee8..31263a18d 100644 --- a/src/adaptors/UBExportPDF.cpp +++ b/src/adaptors/UBExportPDF.cpp @@ -100,6 +100,12 @@ bool UBExportPDF::persistsDocument(std::shared_ptr pDocumentPro for(int pageIndex = 0 ; pageIndex < existingPageCount; pageIndex++) { std::shared_ptr scene = document->loadScene(pageIndex); + + if (!scene) + { + continue; + } + UBApplication::showMessage(tr("Exporting page %1 of %2").arg(pageIndex + 1).arg(existingPageCount)); // set background to white, no crossing for PDF output diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index 96ce24757..cbb8c3672 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -3459,3 +3459,8 @@ std::shared_ptr UBSvgSubsetAdaptor::UBSvgReaderContext::scene() { return reader->scene(); } + +std::shared_ptr UBSvgSubsetAdaptor::UBSvgReaderContext::proxy() const +{ + return reader->mProxy; +} diff --git a/src/adaptors/UBSvgSubsetAdaptor.h b/src/adaptors/UBSvgSubsetAdaptor.h index 4ebacd469..b27605453 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.h +++ b/src/adaptors/UBSvgSubsetAdaptor.h @@ -78,6 +78,7 @@ class UBSvgSubsetAdaptor bool isFinished() const; void step(); std::shared_ptr scene() const; + std::shared_ptr proxy() const; private: UBSvgSubsetReader* reader = nullptr; @@ -135,6 +136,7 @@ class UBSvgSubsetAdaptor std::shared_ptr scene(); private: + friend class UBSvgReaderContext; UBGraphicsPolygonItem* polygonItemFromLineSvg(const QColor& pDefaultBrushColor); diff --git a/src/core/UBSceneCache.cpp b/src/core/UBSceneCache.cpp index 90575f552..2d9407fbc 100644 --- a/src/core/UBSceneCache.cpp +++ b/src/core/UBSceneCache.cpp @@ -36,6 +36,7 @@ #include "core/UBSettings.h" #include "core/UBSetting.h" +#include "document/UBDocument.h" #include "document/UBDocumentProxy.h" #include "core/memcheck.h" @@ -257,11 +258,13 @@ void UBSceneCache::SceneCacheEntry::startLoading() if (mContext->isFinished()) { mScene = mContext->scene(); + auto document = UBDocument::getDocument(mContext->proxy()); mContext = nullptr; mTimer->stop(); delete mTimer; mTimer = nullptr; - mScene->loadingCompleted(shared_from_this()); + + document->sceneLoaded(mScene.get(), shared_from_this()); } } }); @@ -292,7 +295,8 @@ std::shared_ptr UBSceneCache::SceneCacheEntry::scene() } mScene = mContext->scene(); - mScene->loadingCompleted(shared_from_this()); + auto document = UBDocument::getDocument(mContext->proxy()); + document->sceneLoaded(mScene.get(), shared_from_this()); mContext = nullptr; } diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index 5845b21f2..299898149 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -349,66 +349,69 @@ void UBDocument::sceneLoaded(UBGraphicsScene* scene, std::shared_ptr handl { mLoaderHandles.erase(handle); - const auto persistenceManager = UBPersistenceManager::persistenceManager(); - auto index = mToc->findUuid(scene->uuid()); - - if (index >= 0 && !mToc->hasAssetsEntry(index)) + if (scene) { - const auto mediaAssetItems = scene->mediaAssetItems(); + const auto persistenceManager = UBPersistenceManager::persistenceManager(); + auto index = mToc->findUuid(scene->uuid()); - for (auto item : mediaAssetItems) + if (index >= 0 && !mToc->hasAssetsEntry(index)) { - // Check the media asset UUIDs. - // Convert it to a SHA-1 based UUIDv5 if needed. Copy the asset file in this case. - QUuid assetUuid = item->mediaAssetUuid(); + const auto mediaAssetItems = scene->mediaAssetItems(); - if (assetUuid.version() != QUuid::Sha1) + for (auto item : mediaAssetItems) { - // lookup UUIDv5 in cache or create from content - const auto source = item->mediaAssets().at(0); - const auto sourcePath = mProxy->persistencePath() + "/" + source; + // Check the media asset UUIDs. + // Convert it to a SHA-1 based UUIDv5 if needed. Copy the asset file in this case. + QUuid assetUuid = item->mediaAssetUuid(); - QUuid assetUuidV5; - bool needsCopy = false; - - if (mUuidV5Map.contains(assetUuid)) - { - assetUuidV5 = mUuidV5Map.value(assetUuid); - } - else + if (assetUuid.version() != QUuid::Sha1) { - assetUuidV5 = UBMediaAssetItem::createMediaAssetUuid(sourcePath); - mUuidV5Map[assetUuid] = assetUuidV5; - needsCopy = true; - } + // lookup UUIDv5 in cache or create from content + const auto source = item->mediaAssets().at(0); + const auto sourcePath = mProxy->persistencePath() + "/" + source; - auto target = source; - target.replace(assetUuid.toString(QUuid::WithoutBraces), assetUuidV5.toString(QUuid::WithoutBraces)); + QUuid assetUuidV5; + bool needsCopy = false; - // copy assets - if (needsCopy) - { - persistenceManager->copyAsset(mProxy, source, target); - } + if (mUuidV5Map.contains(assetUuid)) + { + assetUuidV5 = mUuidV5Map.value(assetUuid); + } + else + { + assetUuidV5 = UBMediaAssetItem::createMediaAssetUuid(sourcePath); + mUuidV5Map[assetUuid] = assetUuidV5; + needsCopy = true; + } + + auto target = source; + target.replace(assetUuid.toString(QUuid::WithoutBraces), assetUuidV5.toString(QUuid::WithoutBraces)); + + // copy assets + if (needsCopy) + { + persistenceManager->copyAsset(mProxy, source, target); + } - item->setMediaAsset(mProxy->persistencePath(), target); - scene->setModified(true); + item->setMediaAsset(mProxy->persistencePath(), target); + scene->setModified(true); + } } + + mToc->setAssets(index, scene->relativeDependencies()); } - mToc->setAssets(index, scene->relativeDependencies()); - } + if (scene->isModified()) + { + persistenceManager->persistDocumentScene(mProxy, scene->shared_from_this(), mToc->pageId(index)); + } - if (scene->isModified()) - { - persistenceManager->persistDocumentScene(mProxy, scene->shared_from_this(), mToc->pageId(index)); + // generate and load thumbnail from scene if not already existing and loaded + mThumbnailScene->ensureThumbnail(index, scene); } - // generate and load thumbnail from scene if not already existing and loaded - mThumbnailScene->ensureThumbnail(index, scene); - // prepare next scene - QTimer::singleShot(5, mSceneAssetLoader, [this, index](){ + QTimer::singleShot(5, mSceneAssetLoader, [this](){ if (mSceneAssetLoader) { mSceneAssetLoader->resultProcessed(); diff --git a/src/domain/UBGraphicsScene.cpp b/src/domain/UBGraphicsScene.cpp index 010d2c741..559bc2d8b 100644 --- a/src/domain/UBGraphicsScene.cpp +++ b/src/domain/UBGraphicsScene.cpp @@ -54,7 +54,6 @@ #include "tools/UBGraphicsCurtainItem.h" #include "tools/UBGraphicsCache.h" -#include "document/UBDocument.h" #include "document/UBDocumentProxy.h" #include "board/UBBoardController.h" @@ -2451,11 +2450,6 @@ void UBGraphicsScene::controlViewportChanged() } } -void UBGraphicsScene::loadingCompleted(std::shared_ptr handle) -{ - UBDocument::getDocument(mDocument)->sceneLoaded(this, handle); -} - void UBGraphicsScene::addCompass(QPointF center) { UBGraphicsCompass* compass = new UBGraphicsCompass(); // mem : owned and destroyed by the scene diff --git a/src/domain/UBGraphicsScene.h b/src/domain/UBGraphicsScene.h index 68d086a0e..bdf41d3fe 100644 --- a/src/domain/UBGraphicsScene.h +++ b/src/domain/UBGraphicsScene.h @@ -379,7 +379,6 @@ public slots: void stylusToolChanged(int tool, int previousTool); void controlViewportChanged(); - void loadingCompleted(std::shared_ptr handle); signals: void zoomChanged(qreal zoomFactor); From 446fab3ac909f0ed38c9afbeca0c149594b11d60 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Wed, 29 Oct 2025 10:34:40 +0100 Subject: [PATCH 054/133] fix: sync thumbnails view with document - calling pureSetDocument leaves the controller in an inconsistent state - remove this function and always use setDocument instead - a guard condition in this function avoids unnecessary work when the document is not changed --- src/core/UBPersistenceManager.cpp | 8 ++++---- src/document/UBDocumentContainer.cpp | 9 ++------- src/document/UBDocumentContainer.h | 1 - 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index 438b4dfcc..897ed927d 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -321,12 +321,12 @@ QDialog::DialogCode UBPersistenceManager::processInteractiveReplacementDialog(st if (UBApplication::documentController->selectedDocument() == replacedProxy) { - UBApplication::documentController->pureSetDocument(pProxy); + UBApplication::documentController->setDocument(pProxy); } if (UBApplication::boardController->selectedDocument() == replacedProxy) { - UBApplication::boardController->pureSetDocument(pProxy); + UBApplication::boardController->setDocument(pProxy); } } else @@ -382,12 +382,12 @@ QDialog::DialogCode UBPersistenceManager::processInteractiveReplacementDialog(st if (UBApplication::documentController->selectedDocument() == replacedProxy) { - UBApplication::documentController->pureSetDocument(pProxy); + UBApplication::documentController->setDocument(pProxy); } if (UBApplication::boardController->selectedDocument() == replacedProxy) { - UBApplication::boardController->pureSetDocument(pProxy); + UBApplication::boardController->setDocument(pProxy); } } else diff --git a/src/document/UBDocumentContainer.cpp b/src/document/UBDocumentContainer.cpp index b7d036d62..04c865c02 100644 --- a/src/document/UBDocumentContainer.cpp +++ b/src/document/UBDocumentContainer.cpp @@ -51,17 +51,12 @@ void UBDocumentContainer::setDocument(std::shared_ptr document, { if (mCurrentDocument != document || forceReload) { - pureSetDocument(document); + mCurrentDocument = document; + mActiveDocument = UBDocument::getDocument(mCurrentDocument); emit documentSet(document); } } -void UBDocumentContainer::pureSetDocument(std::shared_ptr document) -{ - mCurrentDocument = document; - mActiveDocument = UBDocument::getDocument(mCurrentDocument); -} - std::shared_ptr UBDocumentContainer::activeDocument() { return mActiveDocument; diff --git a/src/document/UBDocumentContainer.h b/src/document/UBDocumentContainer.h index 9d9a867cc..bab7598fc 100644 --- a/src/document/UBDocumentContainer.h +++ b/src/document/UBDocumentContainer.h @@ -45,7 +45,6 @@ class UBDocumentContainer : public QObject virtual ~UBDocumentContainer(); void setDocument(std::shared_ptr document, bool forceReload = false); - void pureSetDocument(std::shared_ptr document); std::shared_ptr selectedDocument(){return mCurrentDocument;} std::shared_ptr activeDocument(); From 1c3dfb55f53d7832bea7d55e1056c7c2bfc6a159 Mon Sep 17 00:00:00 2001 From: = <=> Date: Wed, 29 Oct 2025 18:47:36 +0100 Subject: [PATCH 055/133] fix : using no cache strategy for pdf rendering in windows to avoid glitches when a dpi scaling is applied to the screen --- src/domain/UBGraphicsPDFItem.cpp | 6 ++++++ src/pdf/GraphicsPDFItem.cpp | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/domain/UBGraphicsPDFItem.cpp b/src/domain/UBGraphicsPDFItem.cpp index 943092048..714d94708 100644 --- a/src/domain/UBGraphicsPDFItem.cpp +++ b/src/domain/UBGraphicsPDFItem.cpp @@ -154,6 +154,11 @@ void UBGraphicsPDFItem::setRenderingQuality(RenderingQuality pRenderingQuality) { UBItem::setRenderingQuality(pRenderingQuality); + // Using NoCache on Windows to avoid PDF rendering issues when a DPI scaling is applied (e.g. if a 150% scaling is applied to the screen in the OS screen config). +#ifdef Q_OS_WIN + Q_UNUSED(pRenderingQuality); + setCacheMode(QGraphicsItem::NoCache); +#else if (pRenderingQuality == RenderingQualityHigh) { setCacheMode(QGraphicsItem::NoCache); @@ -162,6 +167,7 @@ void UBGraphicsPDFItem::setRenderingQuality(RenderingQuality pRenderingQuality) { setCacheMode(QGraphicsItem::DeviceCoordinateCache); } +#endif } void UBGraphicsPDFItem::setCacheBehavior(UBItem::CacheBehavior cacheBehavior) diff --git a/src/pdf/GraphicsPDFItem.cpp b/src/pdf/GraphicsPDFItem.cpp index cb4b0a198..6901d5a03 100644 --- a/src/pdf/GraphicsPDFItem.cpp +++ b/src/pdf/GraphicsPDFItem.cpp @@ -41,7 +41,12 @@ GraphicsPDFItem::GraphicsPDFItem(PDFRenderer *renderer, int pageNumber, QGraphic , mPageNumber(pageNumber) , mIsCacheAllowed(true) { + // Using NoCache on Windows to avoid PDF rendering issues when a DPI scaling is applied (e.g. if a 150% scaling is applied to the screen in the OS screen config). +#ifdef Q_OS_WIN + setCacheMode(QGraphicsItem::NoCache); +#else setCacheMode(QGraphicsItem::DeviceCoordinateCache); +#endif mRenderer->attach(); connect(mRenderer, SIGNAL(signalUpdateParent()), this, SLOT(OnRequireUpdate())); } From 97486e1d8dd59806899683d2054a76221a97ff96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Wed, 29 Oct 2025 20:44:28 +0100 Subject: [PATCH 056/133] remove useless macro call --- src/domain/UBGraphicsPDFItem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/domain/UBGraphicsPDFItem.cpp b/src/domain/UBGraphicsPDFItem.cpp index 714d94708..79d5fd31e 100644 --- a/src/domain/UBGraphicsPDFItem.cpp +++ b/src/domain/UBGraphicsPDFItem.cpp @@ -156,7 +156,6 @@ void UBGraphicsPDFItem::setRenderingQuality(RenderingQuality pRenderingQuality) // Using NoCache on Windows to avoid PDF rendering issues when a DPI scaling is applied (e.g. if a 150% scaling is applied to the screen in the OS screen config). #ifdef Q_OS_WIN - Q_UNUSED(pRenderingQuality); setCacheMode(QGraphicsItem::NoCache); #else if (pRenderingQuality == RenderingQualityHigh) From d29138cf37f4737fe812f3192fa1c169ed897368 Mon Sep 17 00:00:00 2001 From: Vekhir Date: Wed, 29 Oct 2025 13:02:12 +0100 Subject: [PATCH 057/133] fix(UBFeaturesController): Handle missing file for favorites list --- src/board/UBFeaturesController.cpp | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/board/UBFeaturesController.cpp b/src/board/UBFeaturesController.cpp index c93d9e9ae..dc793eedb 100644 --- a/src/board/UBFeaturesController.cpp +++ b/src/board/UBFeaturesController.cpp @@ -564,9 +564,8 @@ void UBFeaturesController::loadFavoriteList() { favoriteSet = new QSet(); QFile file( UBSettings::userDataDirectory() + "/favorites.dat" ); - if ( file.exists() ) + if ( file.open(QIODevice::ReadOnly) ) { - file.open(QIODevice::ReadOnly); QDataStream in(&file); int elementsNumber; in >> elementsNumber; @@ -577,21 +576,31 @@ void UBFeaturesController::loadFavoriteList() favoriteSet->insert( path ); } } + else + { + qDebug() << "Could not open favorites list"; + } } void UBFeaturesController::saveFavoriteList() { QFile file( UBSettings::userDataDirectory() + "/favorites.dat" ); file.resize(0); - file.open(QIODevice::WriteOnly); - QDataStream out(&file); - int elementsNumber = favoriteSet->size(); - out << elementsNumber; - for ( QSet::iterator it = favoriteSet->begin(); it != favoriteSet->end(); ++it ) + if (file.open(QIODevice::WriteOnly)) + { + QDataStream out(&file); + int elementsNumber = favoriteSet->size(); + out << elementsNumber; + for ( QSet::iterator it = favoriteSet->begin(); it != favoriteSet->end(); ++it ) + { + out << (*it); + } + file.close(); + } + else { - out << (*it); + qDebug() << "Could not write favorites list"; } - file.close(); } QString UBFeaturesController::uniqNameForFeature(const UBFeature &feature, const QString &pName, const QString &pExtention) const From 544007809850ade61de99e0dbae02618bf06faae Mon Sep 17 00:00:00 2001 From: Vekhir Date: Wed, 29 Oct 2025 13:08:24 +0100 Subject: [PATCH 058/133] fix(UBGraphicsWidgetItem.cpp): Handle missing configuration for UBGraphicsW3CWidgetItem --- src/domain/UBGraphicsWidgetItem.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/domain/UBGraphicsWidgetItem.cpp b/src/domain/UBGraphicsWidgetItem.cpp index 78bafdb25..6f49291c7 100644 --- a/src/domain/UBGraphicsWidgetItem.cpp +++ b/src/domain/UBGraphicsWidgetItem.cpp @@ -1058,10 +1058,19 @@ UBGraphicsW3CWidgetItem::UBGraphicsW3CWidgetItem(const QUrl& pWidgetUrl, QGraphi int height = 150; QFile configFile(path + "config.xml"); - configFile.open(QFile::ReadOnly); + QByteArray widgetContent; + if (configFile.open(QFile::ReadOnly)) + { + widgetContent = configFile.readAll(); + configFile.close(); + } + else + { + qDebug() << "Could not open widget configuration at " << configFile.fileName(); + } QDomDocument doc; - doc.setContent(configFile.readAll()); + doc.setContent(widgetContent); QDomNodeList widgetDomList = doc.elementsByTagName("widget"); if (widgetDomList.count() > 0) { From 04598dd12859765d651ecaa88686563fb87afec2 Mon Sep 17 00:00:00 2001 From: Vekhir Date: Wed, 29 Oct 2025 13:46:22 +0100 Subject: [PATCH 059/133] fix(UBFileSystemUtils.cpp): Handle ZIP write failure (file.open) --- src/frameworks/UBFileSystemUtils.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/frameworks/UBFileSystemUtils.cpp b/src/frameworks/UBFileSystemUtils.cpp index ea238237b..348d9dba7 100644 --- a/src/frameworks/UBFileSystemUtils.cpp +++ b/src/frameworks/UBFileSystemUtils.cpp @@ -802,7 +802,11 @@ bool UBFileSystemUtils::expandZipToDir(const QFile& pZipFile, const QDir& pTarge root.mkpath(newFileInfo.absolutePath()); out.setFileName(newFileName); - out.open(QIODevice::WriteOnly); + if (!out.open(QIODevice::WriteOnly)) + { + qWarning() << "ZIP write failed. Cause: file.open(): " << out.fileName(); + return false; + } // Slow like hell (on GNU/Linux at least), but it is not my fault. // Not ZIP/UNZIP package's fault either. From 72dbbe43e7fdc9942350eb65a8fb7f2a3889af93 Mon Sep 17 00:00:00 2001 From: Vekhir Date: Wed, 29 Oct 2025 13:47:19 +0100 Subject: [PATCH 060/133] fix(PDFRenderer.cpp): Handle missing PDF data Return empty PDFRenderer --- src/pdf/PDFRenderer.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/pdf/PDFRenderer.cpp b/src/pdf/PDFRenderer.cpp index 37bc4989e..460de4faa 100644 --- a/src/pdf/PDFRenderer.cpp +++ b/src/pdf/PDFRenderer.cpp @@ -63,9 +63,15 @@ PDFRenderer* PDFRenderer::rendererForUuid(const QUuid &uuid, const QString &file newRenderer->setFileUuid(uuid); QFile file(filename); - file.open(QIODevice::ReadOnly); - newRenderer->setFileData(file.readAll()); - file.close(); + if (file.open(QIODevice::ReadOnly)) + { + newRenderer->setFileData(file.readAll()); + file.close(); + } + else + { + qDebug() << "Could not open PDF at " << file.fileName(); + } sRenderers.insert(newRenderer->fileUuid(), newRenderer); From f5ca5a82f175b29b5880ab46bee2914ecde49a76 Mon Sep 17 00:00:00 2001 From: Vekhir Date: Wed, 29 Oct 2025 13:56:29 +0100 Subject: [PATCH 061/133] fix(UBGraphicsWidgetItem.cpp): Handle missing plist file --- src/domain/UBGraphicsWidgetItem.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/domain/UBGraphicsWidgetItem.cpp b/src/domain/UBGraphicsWidgetItem.cpp index 6f49291c7..6dd887f07 100644 --- a/src/domain/UBGraphicsWidgetItem.cpp +++ b/src/domain/UBGraphicsWidgetItem.cpp @@ -964,10 +964,12 @@ UBGraphicsAppleWidgetItem::UBGraphicsAppleWidgetItem(const QUrl& pWidgetUrl, QGr } QFile plistFile(path + "/Info.plist"); - plistFile.open(QFile::ReadOnly); - - QByteArray plistBin = plistFile.readAll(); - QString plist = QString::fromUtf8(plistBin); + QString plist; + if (plistFile.open(QFile::ReadOnly)) + { + QByteArray plistBin = plistFile.readAll(); + plist = QString::fromUtf8(plistBin); + } int mainHtmlIndex = plist.indexOf("MainHTML"); int mainHtmlIndexStart = plist.indexOf("", mainHtmlIndex); From 627c1dd3b70b95b13a8b4ae6e02f6053ef52f40c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Fri, 31 Oct 2025 13:14:43 +0100 Subject: [PATCH 062/133] fix: use autoAcceptChildRows to make docs appear when a parent folder is matching the filter --- src/document/UBSortFilterProxyModel.cpp | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/document/UBSortFilterProxyModel.cpp b/src/document/UBSortFilterProxyModel.cpp index 3d7d498c2..7c29cb883 100644 --- a/src/document/UBSortFilterProxyModel.cpp +++ b/src/document/UBSortFilterProxyModel.cpp @@ -7,6 +7,7 @@ UBSortFilterProxyModel::UBSortFilterProxyModel(): setDynamicSortFilter(false); setSortCaseSensitivity(Qt::CaseInsensitive); setRecursiveFilteringEnabled(true); + setAutoAcceptChildRows(true); } bool UBSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const @@ -28,24 +29,5 @@ bool UBSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex bool UBSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { - UBDocumentTreeModel *model = dynamic_cast(sourceModel()); - if(model == nullptr) - { - return false; - } - else - { - QModelIndex idx = model->index(sourceRow, 0, sourceParent); - - if (idx.isValid()) - { - if (idx == model->myDocumentsIndex() || idx == model->trashIndex()) - { - return true; - } - } - - // Filter the documents - return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); - } + return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); } From 4cc1c16c86cf9cb42938c6c60b715786e7d88128 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Thu, 23 Oct 2025 14:08:47 +0200 Subject: [PATCH 063/133] cleanup: remove flash related code - remove UBMimeType enum value - remove mime type handling in UBFileSystemUtils - remove handling in UBFeaturesWidget - remove handling in UBFeaturesController - remove handling in UBBoardController - remove related settings in UBSettings and OpenBoard.config - remove a related comment in UBWidgetUniboardAPI Signed-off-by: letsfindaway --- resources/etc/OpenBoard.config | 1 - src/api/UBWidgetUniboardAPI.h | 2 +- src/board/UBBoardController.cpp | 39 ---------------------------- src/board/UBFeaturesController.cpp | 19 +------------- src/board/UBFeaturesController.h | 5 ---- src/core/UB.h | 1 - src/core/UBSettings.cpp | 24 ----------------- src/core/UBSettings.h | 2 -- src/frameworks/UBFileSystemUtils.cpp | 7 ----- src/gui/UBFeaturesWidget.cpp | 5 ---- 10 files changed, 2 insertions(+), 103 deletions(-) diff --git a/resources/etc/OpenBoard.config b/resources/etc/OpenBoard.config index ce77e232e..ffc35de9b 100644 --- a/resources/etc/OpenBoard.config +++ b/resources/etc/OpenBoard.config @@ -104,7 +104,6 @@ PublishToIntranet=false PublishingUrl= [Library] -AnimationsDirectory=./library/animations ApplicationsDirectory=./library/applications AudiosDirectory=./library/audios ImageDirectory=./library/pictures diff --git a/src/api/UBWidgetUniboardAPI.h b/src/api/UBWidgetUniboardAPI.h index b4e2df989..cb1efb1fd 100644 --- a/src/api/UBWidgetUniboardAPI.h +++ b/src/api/UBWidgetUniboardAPI.h @@ -166,7 +166,7 @@ class UBWidgetUniboardAPI : public QObject /** * add any supported objects (pictures/video/widget) centered at scene position x/y. - * width and height may be supplied, this is useful for flash (.swf) objects + * width and height may be supplied * if background is true, the object is not selectable and sits in the lowest z pos possible * */ diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index 2f425aaf5..ac234af83 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -1363,45 +1363,6 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl return audioMediaItem; } - else if (UBMimeType::Flash == itemMimeType) - { - - qDebug() << "accepting mime type" << mimeType << "as flash"; - - QString sUrl = sourceUrl.toString(); - - if (sUrl.startsWith("file://") || sUrl.startsWith("/")) - { - sUrl = sourceUrl.toLocalFile(); - } - - QSize size; - - if (pSize.height() > 0 && pSize.width() > 0) - size = pSize; - else - size = mActiveScene->nominalSize() * .8; - - Q_UNUSED(internalData) - - QString widgetUrl = UBGraphicsW3CWidgetItem::createNPAPIWrapper(sUrl, mimeType, size); - UBFileSystemUtils::deleteFile(sourceUrl.toLocalFile()); - emit npapiWidgetCreated(widgetUrl); - - if (widgetUrl.length() > 0) - { - UBGraphicsWidgetItem *widgetItem = mActiveScene->addW3CWidget(QUrl::fromLocalFile(widgetUrl), pPos); - widgetItem->setUuid(QUuid::createUuid()); - qDebug() << widgetItem->getOwnFolder(); - qDebug() << widgetItem->getSnapshotPath(); - - widgetItem->setSnapshotPath(widgetItem->getOwnFolder()); - - UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); - - return widgetItem; - } - } else if (UBMimeType::PDF == itemMimeType) { qDebug() << "accepting mime type" << mimeType << "as PDF"; diff --git a/src/board/UBFeaturesController.cpp b/src/board/UBFeaturesController.cpp index dc793eedb..7e96cbf08 100644 --- a/src/board/UBFeaturesController.cpp +++ b/src/board/UBFeaturesController.cpp @@ -56,7 +56,6 @@ const QString UBFeaturesController::appPath = rootPath + "/Applications"; const QString UBFeaturesController::audiosPath = rootPath + "/Audios"; const QString UBFeaturesController::moviesPath = rootPath + "/Movies"; const QString UBFeaturesController::picturesPath = rootPath + "/Pictures"; -const QString UBFeaturesController::flashPath = rootPath + "/Animations"; const QString UBFeaturesController::interactPath = rootPath + "/Interactivities"; const QString UBFeaturesController::shapesPath = rootPath + "/Shapes"; const QString UBFeaturesController::trashPath = rootPath + "/Trash"; @@ -299,7 +298,6 @@ bool UBFeature::isDeletable() const || elementType == FEATURE_AUDIO || elementType == FEATURE_VIDEO || elementType == FEATURE_IMAGE - || elementType == FEATURE_FLASH || elementType == FEATURE_INTERACTIVE || elementType == FEATURE_FOLDER //Ilia. Just a hotfix. Permission mechanism for UBFeatures should be reworked @@ -321,12 +319,10 @@ UBFeaturesController::UBFeaturesController(QWidget *pParentWidget) : mUserVideoDirectoryPath = QUrl::fromLocalFile(UBSettings::settings()->userVideoDirectory()); mUserPicturesDirectoryPath = QUrl::fromLocalFile(UBSettings::settings()->userImageDirectory()); mUserInteractiveDirectoryPath = QUrl::fromLocalFile(UBSettings::settings()->userInteractiveDirectory()); - mUserAnimationDirectoryPath = QUrl::fromLocalFile(UBSettings::settings()->userAnimationDirectory()); mLibPicturesDirectoryPath = QUrl::fromLocalFile(UBSettings::settings()->applicationImageLibraryDirectory()); mLibAudiosDirectoryPath = QUrl::fromLocalFile(UBSettings::settings()->applicationAudiosLibraryDirectory()); mLibVideosDirectoryPath = QUrl::fromLocalFile(UBSettings::settings()->applicationVideosLibraryDirectory()); - mLibAnimationsDirectoryPath = QUrl::fromLocalFile(UBSettings::settings()->applicationAnimationsLibraryDirectory()); mLibInteractiveDirectoryPath = QUrl::fromLocalFile(UBSettings::settings()->applicationInteractivesDirectory()); mLibApplicationsDirectoryPath = QUrl::fromLocalFile(UBSettings::settings()->applicationApplicationsLibraryDirectory()); mLibShapesDirectoryPath = QUrl::fromLocalFile(UBSettings::settings()->applicationShapeLibraryDirectory()); @@ -337,7 +333,6 @@ UBFeaturesController::UBFeaturesController(QWidget *pParentWidget) : audiosElement = UBFeature( audiosPath, QImage(":images/libpalette/AudiosCategory.svg"), tr("Audios") , mUserAudioDirectoryPath, FEATURE_CATEGORY); moviesElement = UBFeature( moviesPath, QImage(":images/libpalette/MoviesCategory.svg"), tr("Movies") , mUserVideoDirectoryPath, FEATURE_CATEGORY); picturesElement = UBFeature( picturesPath, QImage(":images/libpalette/PicturesCategory.svg"), tr("Pictures") , mUserPicturesDirectoryPath, FEATURE_CATEGORY); - //flashElement = UBFeature( flashPath, QImage(":images/libpalette/FlashCategory.svg"), tr("Animations") , mUserAnimationDirectoryPath, FEATURE_CATEGORY); interactElement = UBFeature( interactPath, QImage(":images/libpalette/InteractivesCategory.svg"), tr("Interactivities") , mLibInteractiveDirectoryPath, FEATURE_CATEGORY); applicationsElement = UBFeature( appPath, QImage(":images/libpalette/ApplicationsCategory.svg"), tr("Applications") , mUserInteractiveDirectoryPath, FEATURE_CATEGORY); shapesElement = UBFeature( shapesPath, QImage(":images/libpalette/ShapesCategory.svg"), tr("Shapes") , mLibShapesDirectoryPath, FEATURE_CATEGORY ); @@ -385,14 +380,12 @@ void UBFeaturesController::startThread() computingData << QPair(mLibAudiosDirectoryPath, audiosElement) << QPair(mLibVideosDirectoryPath, moviesElement) - << QPair(mLibAnimationsDirectoryPath, flashElement) << QPair(mLibPicturesDirectoryPath, picturesElement) << QPair(mUserInteractiveDirectoryPath, applicationsElement) << QPair(mUserAudioDirectoryPath, audiosElement) << QPair(mUserPicturesDirectoryPath, picturesElement) << QPair(mUserVideoDirectoryPath, moviesElement) - << QPair(mUserAnimationDirectoryPath, flashElement) << QPair(mLibApplicationsDirectoryPath, applicationsElement) << QPair(mLibShapesDirectoryPath, shapesElement) @@ -420,7 +413,6 @@ void UBFeaturesController::scanFS() *featuresList << audiosElement << moviesElement << picturesElement - << flashElement << interactElement << applicationsElement << shapesElement @@ -799,10 +791,6 @@ UBFeatureElementType UBFeaturesController::fileTypeFromUrl(const QString &path) { fileType = FEATURE_SEARCH; } - else if (mimeString.contains("application/x-shockwave-flash")) - { - fileType = FEATURE_FLASH; - } else if (mimeString.contains("application/openboard-document")) { fileType = FEATURE_DOCUMENT; @@ -836,8 +824,6 @@ QImage UBFeaturesController::getIcon(const QString &path, UBFeatureElementType p return QImage(UBGraphicsWidgetItem::iconFilePath(QUrl::fromLocalFile(path))); } else if (pFType == FEATURE_INTERNAL) { return QImage(UBToolsManager::manager()->iconFromToolId(path)); - } else if (pFType == FEATURE_FLASH) { - return QImage(":images/libpalette/FlashIcon.svg"); } else if (pFType == FEATURE_AUDIO) { return QImage(":images/libpalette/soundIcon.svg"); } else if (pFType == FEATURE_VIDEO) { @@ -1026,10 +1012,7 @@ UBFeature UBFeaturesController::getDestinationFeatureForMimeType(const QString & return picturesElement; else if ( pMmimeType.contains("application") ) { - if ( pMmimeType.contains( "x-shockwave-flash") ) - return flashElement; - else - return interactElement; + return interactElement; } return UBFeature(); } diff --git a/src/board/UBFeaturesController.h b/src/board/UBFeaturesController.h index 407b5aa6e..3440d3470 100644 --- a/src/board/UBFeaturesController.h +++ b/src/board/UBFeaturesController.h @@ -108,7 +108,6 @@ enum UBFeatureElementType FEATURE_AUDIO, FEATURE_VIDEO, FEATURE_IMAGE, - FEATURE_FLASH, FEATURE_TRASH, FEATURE_FAVORITE, FEATURE_SEARCH, @@ -230,7 +229,6 @@ Q_OBJECT static const QString moviesPath; static const QString picturesPath; static const QString appPath; - static const QString flashPath; static const QString shapesPath; static const QString interactPath; static const QString trashPath; @@ -278,14 +276,12 @@ private slots: QUrl mUserVideoDirectoryPath; QUrl mUserPicturesDirectoryPath; QUrl mUserInteractiveDirectoryPath; - QUrl mUserAnimationDirectoryPath; QString libraryPath; QUrl mLibPicturesDirectoryPath; QUrl mLibAudiosDirectoryPath; QUrl mLibVideosDirectoryPath; QUrl mLibInteractiveDirectoryPath; - QUrl mLibAnimationsDirectoryPath; QUrl mLibApplicationsDirectoryPath; QUrl mLibShapesDirectoryPath; @@ -304,7 +300,6 @@ private slots: UBFeature picturesElement; UBFeature interactElement; UBFeature applicationsElement; - UBFeature flashElement; UBFeature shapesElement; UBFeature webSearchElement; diff --git a/src/core/UB.h b/src/core/UB.h index c73a1506e..4087f82cd 100644 --- a/src/core/UB.h +++ b/src/core/UB.h @@ -49,7 +49,6 @@ struct UBMimeType W3CWidget, Video, Audio, - Flash, PDF, OpenboardTool, Group, diff --git a/src/core/UBSettings.cpp b/src/core/UBSettings.cpp index a6ebbdceb..7d269261a 100644 --- a/src/core/UBSettings.cpp +++ b/src/core/UBSettings.cpp @@ -1164,16 +1164,6 @@ QString UBSettings::applicationImageLibraryDirectory() } } -QString UBSettings::userAnimationDirectory() -{ - static QString animationDirectory = ""; - if(animationDirectory.isEmpty()){ - animationDirectory = userDataDirectory() + "/animationUserDirectory"; - checkDirectory(animationDirectory); - } - return animationDirectory; -} - QString UBSettings::userInteractiveDirectory() { static QString interactiveDirectory = ""; @@ -1250,20 +1240,6 @@ QString UBSettings::applicationVideosLibraryDirectory() } } -QString UBSettings::applicationAnimationsLibraryDirectory() -{ - QString defaultRelativePath = QString("./library/animations"); - - QString configPath = value("Library/AnimationsDirectory", QVariant(defaultRelativePath)).toString(); - - if (configPath.startsWith(".")) { - return UBPlatformUtils::applicationResourcesDirectory() + configPath.right(configPath.size() - 1); - } - else { - return configPath; - } -} - QString UBSettings::applicationStartupHintsDirectory() { QString defaultRelativePath = QString("./startupHints"); diff --git a/src/core/UBSettings.h b/src/core/UBSettings.h index 53a608833..609a44917 100644 --- a/src/core/UBSettings.h +++ b/src/core/UBSettings.h @@ -140,7 +140,6 @@ class UBSettings : public QObject static QString userVideoDirectory(); static QString userAudioDirectory(); static QString userSearchDirectory(); - static QString userAnimationDirectory(); static QString userInteractiveDirectory(); static QString userInteractiveFavoritesDirectory(); static QString userPodcastRecordingDirectory(); @@ -156,7 +155,6 @@ class UBSettings : public QObject QString applicationCustomFontDirectory(); QString applicationAudiosLibraryDirectory(); QString applicationVideosLibraryDirectory(); - QString applicationAnimationsLibraryDirectory(); QString applicationStartupHintsDirectory(); QNetworkProxy* httpProxy(); diff --git a/src/frameworks/UBFileSystemUtils.cpp b/src/frameworks/UBFileSystemUtils.cpp index 348d9dba7..da4028f29 100644 --- a/src/frameworks/UBFileSystemUtils.cpp +++ b/src/frameworks/UBFileSystemUtils.cpp @@ -475,14 +475,12 @@ QString UBFileSystemUtils::mimeTypeFromFileName(const QString& fileName) if (ext == "wmx") return "video/x-ms-wmx"; if (ext == "avi") return "video/x-msvideo"; if (ext == "ogv") return "video/ogg"; - if (ext == "flv") return "video/x-flv"; // TODO UB 4.x ... we need to be smarter ... flash may need an external plugin :-( if (ext == "m4v") return "video/x-m4v"; // W3C widget if (ext == "wgt") return "application/widget"; if (ext == "wgs") return "application/search"; // Apple widget if (ext == "wdgt") return "application/vnd.apple-widget"; //mime type invented by us :-( // NOTE @letsfindaway obsolete - if (ext == "swf") return "application/x-shockwave-flash"; if (ext == "rdf") return "application/openboard-document"; return ""; @@ -556,7 +554,6 @@ QString UBFileSystemUtils::fileExtensionFromMimeType(const QString& pMimeType) if (pMimeType == "video/x-m4v") return "m4v"; if (pMimeType == "application/widget") return "wgt"; if (pMimeType == "application/vnd.apple-widget") return "wdgt"; //mime type invented by us :-( - if (pMimeType == "application/x-shockwave-flash") return "swf"; return ""; @@ -600,10 +597,6 @@ UBMimeType::Enum UBFileSystemUtils::mimeTypeFromString(const QString& typeString { type = UBMimeType::Audio; } - else if (typeString.startsWith("application/x-shockwave-flash")) - { - type = UBMimeType::Flash; - } else if (typeString.startsWith("application/pdf")) { type = UBMimeType::PDF; diff --git a/src/gui/UBFeaturesWidget.cpp b/src/gui/UBFeaturesWidget.cpp index 40ad99846..96d86e7ea 100644 --- a/src/gui/UBFeaturesWidget.cpp +++ b/src/gui/UBFeaturesWidget.cpp @@ -291,10 +291,6 @@ void UBFeaturesWidget::onDisplayMetadata( QMap metadata ) previewImageUrl = ":images/libpalette/movieIcon.svg"; break; - case UBMimeType::Flash: - previewImageUrl = ":images/libpalette/FlashIcon.svg"; - break; - case UBMimeType::RasterImage: case UBMimeType::VectorImage: previewImageUrl = widgetsUrl; @@ -1424,7 +1420,6 @@ Qt::ItemFlags UBFeaturesModel::flags( const QModelIndex &index ) const || item.getType() == FEATURE_AUDIO || item.getType() == FEATURE_VIDEO || item.getType() == FEATURE_IMAGE - || item.getType() == FEATURE_FLASH || item.getType() == FEATURE_INTERNAL || item.getType() == FEATURE_FOLDER || item.getType() == FEATURE_DOCUMENT) From 79bf01ce783bb277fe478baf8d8d8b9cc8c56abd Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Thu, 23 Oct 2025 14:29:21 +0200 Subject: [PATCH 064/133] cleanup: remove AppleWidget related code - remove UBMimeType enum value - remove mime type handling in UBFileSystemUtils - remove reading and writing in UBSvgSubsetAdaptor - remove handling in UBBoardController - remove handling in UBGraphicsScene - remove class UBGraphicsAppleWidgetItem Signed-off-by: letsfindaway --- src/adaptors/UBSvgSubsetAdaptor.cpp | 60 ------------- src/adaptors/UBSvgSubsetAdaptor.h | 4 - src/board/UBBoardController.cpp | 24 ----- src/core/UB.h | 1 - src/domain/UBGraphicsScene.cpp | 16 +--- src/domain/UBGraphicsScene.h | 2 - src/domain/UBGraphicsWidgetItem.cpp | 127 +-------------------------- src/domain/UBGraphicsWidgetItem.h | 16 +--- src/frameworks/UBFileSystemUtils.cpp | 7 -- 9 files changed, 4 insertions(+), 253 deletions(-) diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index cbb8c3672..7ef040abe 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -919,22 +919,6 @@ void UBSvgSubsetAdaptor::UBSvgSubsetReader::processElement() currentWidget = 0; } } - else if (src.contains(".wdgt")) // NOTE @letsfindaway obsolete - { - UBGraphicsAppleWidgetItem* appleWidgetItem = graphicsAppleWidgetFromSvg(); - if (appleWidgetItem) - { - appleWidgetItem->setFlag(QGraphicsItem::ItemIsSelectable, true); - - appleWidgetItem->resize(foreignObjectWidth, foreignObjectHeight); - - mScene->addItem(appleWidgetItem); - - appleWidgetItem->show(); - - currentWidget = appleWidgetItem; - } - } else if (src.contains(".wgt")) { UBGraphicsW3CWidgetItem* w3cWidgetItem = graphicsW3CWidgetFromSvg(); @@ -1434,14 +1418,6 @@ bool UBSvgSubsetAdaptor::UBSvgSubsetWriter::persistScene(std::shared_ptr (item); - if (appleWidgetItem && appleWidgetItem->isVisible()) - { - graphicsAppleWidgetToSvg(appleWidgetItem); - continue; - } - // Is the item a W3C? UBGraphicsW3CWidgetItem *w3cWidgetItem = qgraphicsitem_cast (item); if (w3cWidgetItem && w3cWidgetItem->isVisible()) @@ -2609,14 +2585,6 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::graphicsItemToSvg(QGraphicsItem* ite } } - - -// NOTE @letsfindaway obsolete -void UBSvgSubsetAdaptor::UBSvgSubsetWriter::graphicsAppleWidgetToSvg(UBGraphicsAppleWidgetItem* item) -{ - graphicsWidgetToSvg(item); -} - void UBSvgSubsetAdaptor::UBSvgSubsetWriter::graphicsW3CWidgetToSvg(UBGraphicsW3CWidgetItem* item) { graphicsWidgetToSvg(item); @@ -2713,34 +2681,6 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::graphicsWidgetToSvg(UBGraphicsWidget mXmlWriter.writeEndElement(); } -// NOTE @letsfindaway obsolete -UBGraphicsAppleWidgetItem* UBSvgSubsetAdaptor::UBSvgSubsetReader::graphicsAppleWidgetFromSvg() -{ - - auto widgetUrl = mXmlReader.attributes().value(mNamespaceUri, "src"); - - if (widgetUrl.isNull()) - { - qWarning() << "cannot make sens of widget src value"; - return 0; - } - - QString href = widgetUrl.toString(); - - QUrl url(href); - - if (url.isRelative()) - { - href = mDocumentPath + "/" + UBFileSystemUtils::normalizeFilePath(widgetUrl.toString()); - } - - UBGraphicsAppleWidgetItem* widgetItem = new UBGraphicsAppleWidgetItem(QUrl::fromLocalFile(href)); - - graphicsItemFromSvg(widgetItem); - - return widgetItem; -} - UBGraphicsW3CWidgetItem* UBSvgSubsetAdaptor::UBSvgSubsetReader::graphicsW3CWidgetFromSvg() { auto widgetUrl = mXmlReader.attributes().value(mNamespaceUri, "src"); diff --git a/src/adaptors/UBSvgSubsetAdaptor.h b/src/adaptors/UBSvgSubsetAdaptor.h index b27605453..f56049782 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.h +++ b/src/adaptors/UBSvgSubsetAdaptor.h @@ -44,7 +44,6 @@ class UBGraphicsWidgetItem; class UBGraphicsMediaItem; class UBGraphicsVideoItem; class UBGraphicsAudioItem; -class UBGraphicsAppleWidgetItem; class UBGraphicsW3CWidgetItem; class UBGraphicsTextItem; class UBGraphicsCurtainItem; @@ -154,8 +153,6 @@ class UBSvgSubsetAdaptor UBGraphicsMediaItem* audioItemFromSvg(); - UBGraphicsAppleWidgetItem* graphicsAppleWidgetFromSvg(); - UBGraphicsW3CWidgetItem* graphicsW3CWidgetFromSvg(); UBGraphicsTextItem* textItemFromSvg(); @@ -270,7 +267,6 @@ class UBSvgSubsetAdaptor void videoItemToLinkedVideo(UBGraphicsVideoItem *videoItem); void audioItemToLinkedAudio(UBGraphicsAudioItem *audioItem); void graphicsItemToSvg(QGraphicsItem *item); - void graphicsAppleWidgetToSvg(UBGraphicsAppleWidgetItem *item); void graphicsW3CWidgetToSvg(UBGraphicsW3CWidgetItem *item); void graphicsWidgetToSvg(UBGraphicsWidgetItem *item); void textItemToSvg(UBGraphicsTextItem *item); diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index ac234af83..b9bc4d569 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -1239,30 +1239,6 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl return svgItem; } - else if (UBMimeType::AppleWidget == itemMimeType) //mime type invented by us :-( - { - qDebug() << "accepting mime type" << mimeType << "as Apple widget"; - - QUrl widgetUrl = sourceUrl; - - if (pData.length() > 0) - { - widgetUrl = expandWidgetToTempDir(pData, "wdgt"); - } - - UBGraphicsWidgetItem* appleWidgetItem = mActiveScene->addAppleWidget(widgetUrl, pPos); - - if (isBackground) - { - mActiveScene->setAsBackgroundObject(appleWidgetItem); - } - else - { - UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); - } - - return appleWidgetItem; - } else if (UBMimeType::W3CWidget == itemMimeType) { qDebug() << "accepting mime type" << mimeType << "as W3C widget"; diff --git a/src/core/UB.h b/src/core/UB.h index 4087f82cd..8ccdc469c 100644 --- a/src/core/UB.h +++ b/src/core/UB.h @@ -45,7 +45,6 @@ struct UBMimeType { RasterImage = 0, VectorImage, - AppleWidget, W3CWidget, Video, Audio, diff --git a/src/domain/UBGraphicsScene.cpp b/src/domain/UBGraphicsScene.cpp index 559bc2d8b..5caa8e1e2 100644 --- a/src/domain/UBGraphicsScene.cpp +++ b/src/domain/UBGraphicsScene.cpp @@ -1715,11 +1715,7 @@ UBGraphicsWidgetItem* UBGraphicsScene::addWidget(const QUrl& pWidgetUrl, const Q { int widgetType = UBGraphicsWidgetItem::widgetType(pWidgetUrl); - if(widgetType == UBWidgetType::Apple) // NOTE @letsfindaway obsolete - { - return addAppleWidget(pWidgetUrl, pPos); - } - else if(widgetType == UBWidgetType::W3C) + if(widgetType == UBWidgetType::W3C) { return addW3CWidget(pWidgetUrl, pPos); } @@ -1730,16 +1726,6 @@ UBGraphicsWidgetItem* UBGraphicsScene::addWidget(const QUrl& pWidgetUrl, const Q } } -// NOTE @letsfindaway obsolete -UBGraphicsAppleWidgetItem* UBGraphicsScene::addAppleWidget(const QUrl& pWidgetUrl, const QPointF& pPos) -{ - UBGraphicsAppleWidgetItem *appleWidget = new UBGraphicsAppleWidgetItem(pWidgetUrl); - - addGraphicsWidget(appleWidget, pPos); - - return appleWidget; -} - UBGraphicsW3CWidgetItem* UBGraphicsScene::addW3CWidget(const QUrl& pWidgetUrl, const QPointF& pPos) { UBGraphicsW3CWidgetItem *w3CWidget = new UBGraphicsW3CWidgetItem(pWidgetUrl, 0); diff --git a/src/domain/UBGraphicsScene.h b/src/domain/UBGraphicsScene.h index bdf41d3fe..54820fd4e 100644 --- a/src/domain/UBGraphicsScene.h +++ b/src/domain/UBGraphicsScene.h @@ -43,7 +43,6 @@ class UBGraphicsPolygonItem; class UBGraphicsMediaItem; class UBGraphicsWidgetItem; class UBGraphicsW3CWidgetItem; -class UBGraphicsAppleWidgetItem; class UBToolWidget; class UBGraphicsPDFItem; class UBGraphicsTextItem; @@ -153,7 +152,6 @@ class UBGraphicsScene: public UBCoreGraphicsScene, public UBItem, public std::en void removeItems(const QSet& item); UBGraphicsWidgetItem* addWidget(const QUrl& pWidgetUrl, const QPointF& pPos = QPointF(0, 0)); - UBGraphicsAppleWidgetItem* addAppleWidget(const QUrl& pWidgetUrl, const QPointF& pPos = QPointF(0, 0)); UBGraphicsW3CWidgetItem* addW3CWidget(const QUrl& pWidgetUrl, const QPointF& pPos = QPointF(0, 0)); void addGraphicsWidget(UBGraphicsWidgetItem* graphicsWidget, const QPointF& pPos = QPointF(0, 0)); diff --git a/src/domain/UBGraphicsWidgetItem.cpp b/src/domain/UBGraphicsWidgetItem.cpp index 9f233c905..861307159 100644 --- a/src/domain/UBGraphicsWidgetItem.cpp +++ b/src/domain/UBGraphicsWidgetItem.cpp @@ -484,9 +484,7 @@ int UBGraphicsWidgetItem::widgetType(const QUrl& pUrl) { QString mime = UBFileSystemUtils::mimeTypeFromFileName(pUrl.toString()); - if (mime == "application/vnd.apple-widget") // NOTE @letsfindaway obsolete - return UBWidgetType::Apple; - else if (mime == "application/widget") + if (mime == "application/widget") return UBWidgetType::W3C; else return UBWidgetType::Other; @@ -497,7 +495,6 @@ QString UBGraphicsWidgetItem::widgetName(const QUrl& widgetPath) QString name; QString version; QFile w3CConfigFile(widgetPath.toLocalFile() + "/config.xml"); - QFile appleConfigFile(widgetPath.toLocalFile() + "/Info.plist"); if (w3CConfigFile.exists() && w3CConfigFile.open(QFile::ReadOnly)) { QDomDocument doc; @@ -511,43 +508,7 @@ QString UBGraphicsWidgetItem::widgetName(const QUrl& widgetPath) } w3CConfigFile.close(); } - else if (appleConfigFile.exists() && appleConfigFile.open(QFile::ReadOnly)) { - QDomDocument doc; - doc.setContent(appleConfigFile.readAll()); - QDomElement root = doc.firstChildElement("plist"); - if (!root.isNull()) { - QDomElement dictElement = root.firstChildElement("dict"); - if (!dictElement.isNull()) { - QDomNodeList childNodes = dictElement.childNodes(); - - /* looking for something like - * .. - * CFBundleDisplayName - * brain scans - * .. - */ - - for(int i = 0; i < childNodes.count() - 1; i++) { - if (childNodes.at(i).isElement()) { - QDomElement elKey = childNodes.at(i).toElement(); - if (elKey.text() == "CFBundleDisplayName") { - if (childNodes.at(i + 1).isElement()) { - QDomElement elValue = childNodes.at(i + 1).toElement(); - name = elValue.text(); - } - } - else if (elKey.text() == "CFBundleShortVersionString") { - if (childNodes.at(i + 1).isElement()) { - QDomElement elValue = childNodes.at(i + 1).toElement(); - version = elValue.text(); - } - } - } - } - } - } - appleConfigFile.close(); - } + QString result; if (name.length() > 0) { @@ -951,90 +912,6 @@ QSizeF UBGraphicsWidgetItem::size() const } -// NOTE @letsfindaway obsolete -UBGraphicsAppleWidgetItem::UBGraphicsAppleWidgetItem(const QUrl& pWidgetUrl, QGraphicsItem *parent) - : UBGraphicsWidgetItem(pWidgetUrl, parent) -{ - QString path = pWidgetUrl.toLocalFile(); - - if (!path.endsWith(".wdgt") && !path.endsWith(".wdgt/")) { - int lastSlashIndex = path.lastIndexOf("/"); - if (lastSlashIndex > 0) - path = path.mid(0, lastSlashIndex + 1); - } - - QFile plistFile(path + "/Info.plist"); - QString plist; - if (plistFile.open(QFile::ReadOnly)) - { - QByteArray plistBin = plistFile.readAll(); - plist = QString::fromUtf8(plistBin); - } - - int mainHtmlIndex = plist.indexOf("MainHTML"); - int mainHtmlIndexStart = plist.indexOf("", mainHtmlIndex); - int mainHtmlIndexEnd = plist.indexOf("", mainHtmlIndexStart); - - if (mainHtmlIndex > -1 && mainHtmlIndexStart > -1 && mainHtmlIndexEnd > -1) - mMainHtmlFileName = plist.mid(mainHtmlIndexStart + 8, mainHtmlIndexEnd - mainHtmlIndexStart - 8); - - mMainHtmlUrl = pWidgetUrl; - mMainHtmlUrl.setPath(pWidgetUrl.path() + "/" + mMainHtmlFileName); - - mWebEngineView->load(mMainHtmlUrl); - - QPixmap defaultPixmap(pWidgetUrl.toLocalFile() + "/Default.png"); - - setMaximumSize(defaultPixmap.size()); - - mNominalSize = defaultPixmap.size(); - - initialize(); -} - - -UBGraphicsAppleWidgetItem::~UBGraphicsAppleWidgetItem() -{ - /* NOOP */ -} - -UBItem* UBGraphicsAppleWidgetItem::deepCopy() const -{ - UBGraphicsAppleWidgetItem *appleWidget = new UBGraphicsAppleWidgetItem(mWebEngineView->url(), parentItem()); - - copyItemParameters(appleWidget); - - return appleWidget; - -} - -void UBGraphicsAppleWidgetItem::setMediaAsset(const QString& documentPath, const QString& mediaAsset) -{ -} - -void UBGraphicsAppleWidgetItem::copyItemParameters(UBItem *copy) const -{ - UBGraphicsAppleWidgetItem *cp = dynamic_cast(copy); - if (cp) - { - foreach(QString key, mPreferences.keys()) - { - cp->setPreference(key, mPreferences.value(key)); - } - - foreach(QString key, mDatastore.keys()) - { - cp->setDatastoreEntry(key, mDatastore.value(key)); - } - - cp->setZValue(this->zValue()); - } - -} - - - - bool UBGraphicsW3CWidgetItem::sTemplateLoaded = false; QString UBGraphicsW3CWidgetItem::sNPAPIWrappperConfigTemplate; QMap UBGraphicsW3CWidgetItem::sNPAPIWrapperTemplates; diff --git a/src/domain/UBGraphicsWidgetItem.h b/src/domain/UBGraphicsWidgetItem.h index 7d77e6419..9757903d9 100644 --- a/src/domain/UBGraphicsWidgetItem.h +++ b/src/domain/UBGraphicsWidgetItem.h @@ -53,7 +53,7 @@ struct UBWidgetType { enum Enum { - W3C = 0, Apple, Other + W3C = 0, Other }; }; @@ -213,20 +213,6 @@ class UBGraphicsWidgetItem : public QGraphicsProxyWidget, public UBMediaAssetIte static QStringList sInlineJavaScripts; }; -// NOTE @letsfindaway obsolete -class UBGraphicsAppleWidgetItem : public UBGraphicsWidgetItem -{ - Q_OBJECT - - public: - UBGraphicsAppleWidgetItem(const QUrl& pWidgetUrl, QGraphicsItem *parent = 0); - ~UBGraphicsAppleWidgetItem(); - - virtual void copyItemParameters(UBItem *copy) const override; - virtual UBItem* deepCopy() const override; - virtual void setMediaAsset(const QString& documentPath, const QString& mediaAsset) override; -}; - class UBGraphicsW3CWidgetItem : public UBGraphicsWidgetItem { Q_OBJECT diff --git a/src/frameworks/UBFileSystemUtils.cpp b/src/frameworks/UBFileSystemUtils.cpp index da4028f29..54e128b9c 100644 --- a/src/frameworks/UBFileSystemUtils.cpp +++ b/src/frameworks/UBFileSystemUtils.cpp @@ -479,8 +479,6 @@ QString UBFileSystemUtils::mimeTypeFromFileName(const QString& fileName) // W3C widget if (ext == "wgt") return "application/widget"; if (ext == "wgs") return "application/search"; - // Apple widget - if (ext == "wdgt") return "application/vnd.apple-widget"; //mime type invented by us :-( // NOTE @letsfindaway obsolete if (ext == "rdf") return "application/openboard-document"; return ""; @@ -553,7 +551,6 @@ QString UBFileSystemUtils::fileExtensionFromMimeType(const QString& pMimeType) if (pMimeType == "video/x-flv") return "flv"; if (pMimeType == "video/x-m4v") return "m4v"; if (pMimeType == "application/widget") return "wgt"; - if (pMimeType == "application/vnd.apple-widget") return "wdgt"; //mime type invented by us :-( return ""; @@ -581,10 +578,6 @@ UBMimeType::Enum UBFileSystemUtils::mimeTypeFromString(const QString& typeString { type = UBMimeType::Html; } - else if (typeString == "application/vnd.apple-widget") - { - type = UBMimeType::AppleWidget; - } else if (typeString == "application/widget") { type = UBMimeType::W3CWidget; From 7b66c4322da554dfdbc819464b73cfc9e27fd621 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Thu, 23 Oct 2025 14:51:45 +0200 Subject: [PATCH 065/133] cleanup: remove NPAPI wrapper support - remove unused signal from UBBoardController - remove related unused slot from UBFeaturesController - remove unused related functions from UBGraphicsW3CWidgetItem - remove obsolete files for npapi-wrapper in resources/etc - remove installation of file from CMakeLists.txt Signed-off-by: letsfindaway --- CMakeLists.txt | 3 +- ...pper.application.x-shockwave-flash.swf.htm | 29 ---- resources/etc/npapi-wrapper.config.xml | 12 -- src/board/UBBoardController.h | 1 - src/board/UBFeaturesController.cpp | 10 -- src/board/UBFeaturesController.h | 1 - src/domain/UBGraphicsWidgetItem.cpp | 146 ------------------ src/domain/UBGraphicsWidgetItem.h | 8 - 8 files changed, 1 insertion(+), 209 deletions(-) delete mode 100644 resources/etc/npapi-wrapper.application.x-shockwave-flash.swf.htm delete mode 100644 resources/etc/npapi-wrapper.config.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index b32a8d84f..7d87fcaee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,8 +67,7 @@ set(OPENBOARD_ETC_FILE ${OPENBOARD_ETC_DIR}/OpenBoard.config ${OPENBOARD_ETC_DIR}/OpenBoard.css ${OPENBOARD_ETC_DIR}/widgets.md5sum) set(OPENBOARD_TEMPLATE_FILE ${OPENBOARD_ETC_DIR}/asyncAPI.js - ${OPENBOARD_ETC_DIR}/intranet-podcast-metadata.template - ${OPENBOARD_ETC_DIR}/npapi-wrapper.config.xml) + ${OPENBOARD_ETC_DIR}/intranet-podcast-metadata.template) set(OPENBOARD_ICON_FILE resources/images/ch.openboard.OpenBoard.svg) set(OPENBOARD_DESKTOP_FILE resources/linux/ch.openboard.OpenBoard.desktop) diff --git a/resources/etc/npapi-wrapper.application.x-shockwave-flash.swf.htm b/resources/etc/npapi-wrapper.application.x-shockwave-flash.swf.htm deleted file mode 100644 index 909d19d1c..000000000 --- a/resources/etc/npapi-wrapper.application.x-shockwave-flash.swf.htm +++ /dev/null @@ -1,29 +0,0 @@ - - - - Flash Widget - - - - - -

- - - - - -
- - diff --git a/resources/etc/npapi-wrapper.config.xml b/resources/etc/npapi-wrapper.config.xml deleted file mode 100644 index dc3d72114..000000000 --- a/resources/etc/npapi-wrapper.config.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - {in.name} - - - diff --git a/src/board/UBBoardController.h b/src/board/UBBoardController.h index 258b48a59..3a3bc6e3f 100644 --- a/src/board/UBBoardController.h +++ b/src/board/UBBoardController.h @@ -268,7 +268,6 @@ class UBBoardController : public UBDocumentContainer void documentReorganized(int index); void displayMetadata(QMap metadata); void pageSelectionChanged(int index); - void npapiWidgetCreated(const QString &Url); protected: void setupViews(); diff --git a/src/board/UBFeaturesController.cpp b/src/board/UBFeaturesController.cpp index 7e96cbf08..40c7f21e0 100644 --- a/src/board/UBFeaturesController.cpp +++ b/src/board/UBFeaturesController.cpp @@ -369,7 +369,6 @@ UBFeaturesController::UBFeaturesController(QWidget *pParentWidget) : connect(&mCThread, SIGNAL(maxFilesCountEvaluated(int)), this, SIGNAL(maxFilesCountEvaluated(int))); connect(&mCThread, SIGNAL(scanCategory(QString)), this, SIGNAL(scanCategory(QString))); connect(&mCThread, SIGNAL(scanPath(QString)), this, SIGNAL(scanPath(QString))); - connect(UBApplication::boardController, SIGNAL(npapiWidgetCreated(QString)), this, SLOT(createNpApiFeature(QString))); QTimer::singleShot(0, this, SLOT(startThread())); } @@ -396,15 +395,6 @@ void UBFeaturesController::startThread() mCThread.compute(computingData, favoriteSet); } -void UBFeaturesController::createNpApiFeature(const QString &str) -{ - Q_ASSERT(QFileInfo(str).exists() && QFileInfo(str).isDir()); - - QString widgetName = QFileInfo(str).fileName(); - - featuresModel->addItem(UBFeature(QString(appPath + "/Web/" + widgetName), QImage(UBGraphicsWidgetItem::iconFilePath(QUrl::fromLocalFile(str))), widgetName, QUrl::fromLocalFile(str), FEATURE_INTERACTIVE)); -} - void UBFeaturesController::scanFS() { featuresList->clear(); diff --git a/src/board/UBFeaturesController.h b/src/board/UBFeaturesController.h index 3440d3470..51f411ff0 100644 --- a/src/board/UBFeaturesController.h +++ b/src/board/UBFeaturesController.h @@ -246,7 +246,6 @@ Q_OBJECT private slots: void addNewFolder(QString name); void startThread(); - void createNpApiFeature(const QString &str); private: diff --git a/src/domain/UBGraphicsWidgetItem.cpp b/src/domain/UBGraphicsWidgetItem.cpp index 861307159..ef13befcb 100644 --- a/src/domain/UBGraphicsWidgetItem.cpp +++ b/src/domain/UBGraphicsWidgetItem.cpp @@ -912,10 +912,6 @@ QSizeF UBGraphicsWidgetItem::size() const } -bool UBGraphicsW3CWidgetItem::sTemplateLoaded = false; -QString UBGraphicsW3CWidgetItem::sNPAPIWrappperConfigTemplate; -QMap UBGraphicsW3CWidgetItem::sNPAPIWrapperTemplates; - UBGraphicsW3CWidgetItem::UBGraphicsW3CWidgetItem(const QUrl& pWidgetUrl, QGraphicsItem *parent) : UBGraphicsWidgetItem(pWidgetUrl, parent) , mW3CWidgetAPI(0) @@ -1118,107 +1114,6 @@ void UBGraphicsW3CWidgetItem::sendJSLeaveEvent() } } -QString UBGraphicsW3CWidgetItem::createNPAPIWrapper(const QString& url, const QString& pMimeType, const QSize& sizeHint, const QString& pName) -{ - const QString userWidgetPath = UBSettings::settings()->userInteractiveDirectory() + "/" + tr("Web"); - QDir userWidgetDir(userWidgetPath); - - return createNPAPIWrapperInDir(url, userWidgetDir, pMimeType, sizeHint, pName); -} - -QString UBGraphicsW3CWidgetItem::createNPAPIWrapperInDir(const QString& pUrl, const QDir& pDir, const QString& pMimeType, const QSize& sizeHint, const QString& pName) -{ - QString url = pUrl; - url = UBFileSystemUtils::removeLocalFilePrefix(url); - QString name = pName; - - QFileInfo fi(url); - - if (name.length() == 0) - name = fi.baseName(); - - if (fi.exists()) - url = fi.fileName(); - - loadNPAPIWrappersTemplates(); - - QString htmlTemplate; - - if (pMimeType.length() > 0 && sNPAPIWrapperTemplates.contains(pMimeType)) - htmlTemplate = sNPAPIWrapperTemplates.value(pMimeType); - else { - QString extension = UBFileSystemUtils::extension(url); - if (sNPAPIWrapperTemplates.contains(extension)) - htmlTemplate = sNPAPIWrapperTemplates.value(extension); - } - - if (htmlTemplate.length() > 0) { - htmlTemplate = htmlTemplate.replace(QString("{in.url}"), url) - .replace(QString("{in.width}"), QString("%1").arg(sizeHint.width())) - .replace(QString("{in.height}"), QString("%1").arg(sizeHint.height())); - - QString configTemplate = sNPAPIWrappperConfigTemplate - .replace(QString("{in.id}"), url) - .replace(QString("{in.width}"), QString("%1").arg(sizeHint.width())) - .replace(QString("{in.height}"), QString("%1").arg(sizeHint.height())) - .replace(QString("{in.name}"), name) - .replace(QString("{in.startFile}"), QString("index.htm")); - - QString dirPath = pDir.path(); - if (!pDir.exists()) - pDir.mkpath(dirPath); - - QString widgetLibraryPath = dirPath + "/" + name + ".wgt"; - QDir widgetLibraryDir(widgetLibraryPath); - - if (widgetLibraryDir.exists()) - if (!UBFileSystemUtils::deleteDir(widgetLibraryDir.path())) - qWarning() << "Cannot delete old widget " << widgetLibraryDir.path(); - - widgetLibraryDir.mkpath(widgetLibraryPath); - if (fi.exists()) { - QString target = widgetLibraryPath + "/" + fi.fileName(); - QString source = pUrl; - source = UBFileSystemUtils::removeLocalFilePrefix(source); - QFile::copy(source, target); - } - - QFile configFile(widgetLibraryPath + "/config.xml"); - - if (!configFile.open(QIODevice::WriteOnly)) { - qWarning() << "Cannot open file " << configFile.fileName(); - return QString(); - } - - QTextStream outConfig(&configFile); -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - outConfig.setCodec("UTF-8"); -#endif - - outConfig << configTemplate; - configFile.close(); - - QFile indexFile(widgetLibraryPath + "/index.htm"); - - if (!indexFile.open(QIODevice::WriteOnly)) { - qWarning() << "Cannot open file " << indexFile.fileName(); - return QString(); - } - - QTextStream outIndex(&indexFile); -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - outIndex.setCodec("UTF-8"); -#endif - - outIndex << htmlTemplate; - indexFile.close(); - - return widgetLibraryPath; - } - else - return QString(); -} - QString UBGraphicsW3CWidgetItem::createHtmlWrapperInDir(const QString& html, const QDir& pDir, const QSize& sizeHint, const QString& pName) { QString widgetPath = pDir.path() + "/" + pName + ".wgt"; @@ -1289,13 +1184,6 @@ QString UBGraphicsW3CWidgetItem::createHtmlWrapperInDir(const QString& html, con return widgetPath; } -bool UBGraphicsW3CWidgetItem::hasNPAPIWrapper(const QString& pMimeType) -{ - loadNPAPIWrappersTemplates(); - - return sNPAPIWrapperTemplates.contains(pMimeType); -} - void UBGraphicsW3CWidgetItem::registerAPI() { UBGraphicsWidgetItem::registerAPI(); @@ -1307,40 +1195,6 @@ void UBGraphicsW3CWidgetItem::registerAPI() } } -void UBGraphicsW3CWidgetItem::loadNPAPIWrappersTemplates() -{ - if (!sTemplateLoaded) { - sNPAPIWrapperTemplates.clear(); - - QString templatePath = UBPlatformUtils::applicationTemplateDirectory(); - - QDir templateDir(templatePath); - - foreach(QString fileName, templateDir.entryList()) { - if (fileName.startsWith("npapi-wrapper") && (fileName.endsWith(".htm") || fileName.endsWith(".html"))) { - - QString htmlContent = UBFileSystemUtils::readTextFile(templatePath + fileName); - - if (htmlContent.length() > 0) { - QStringList tokens = fileName.split("."); - - if (tokens.length() >= 4) { - QString mime = tokens.at(tokens.length() - 4 ); - mime += "/" + tokens.at(tokens.length() - 3); - - QString fileExtension = tokens.at(tokens.length() - 2); - - sNPAPIWrapperTemplates.insert(mime, htmlContent); - sNPAPIWrapperTemplates.insert(fileExtension, htmlContent); - } - } - } - } - sNPAPIWrappperConfigTemplate = UBFileSystemUtils::readTextFile(templatePath + "npapi-wrapper.config.xml"); - sTemplateLoaded = true; - } -} - QString UBGraphicsW3CWidgetItem::textForSubElementByLocale(QDomElement rootElement, QString subTagName, QLocale locale) { QDomNodeList subList = rootElement.elementsByTagName(subTagName); diff --git a/src/domain/UBGraphicsWidgetItem.h b/src/domain/UBGraphicsWidgetItem.h index 9757903d9..92fc1f21f 100644 --- a/src/domain/UBGraphicsWidgetItem.h +++ b/src/domain/UBGraphicsWidgetItem.h @@ -263,10 +263,7 @@ class UBGraphicsW3CWidgetItem : public UBGraphicsWidgetItem virtual void sendJSEnterEvent() override; virtual void sendJSLeaveEvent() override; - static QString createNPAPIWrapper(const QString& url, const QString& pMimeType = QString(), const QSize& sizeHint = QSize(300, 150), const QString& pName = QString()); - static QString createNPAPIWrapperInDir(const QString& url, const QDir& pDir, const QString& pMimeType = QString(), const QSize& sizeHint = QSize(300, 150), const QString& pName = QString()); static QString createHtmlWrapperInDir(const QString& html, const QDir& pDir, const QSize& sizeHint, const QString& pName); - static bool hasNPAPIWrapper(const QString& pMimeType); Metadata mMetadatas; @@ -274,15 +271,10 @@ class UBGraphicsW3CWidgetItem : public UBGraphicsWidgetItem virtual void registerAPI() override; private: - static void loadNPAPIWrappersTemplates(); static QString textForSubElementByLocale(QDomElement rootElement, QString subTagName, QLocale locale); UBW3CWidgetAPI* mW3CWidgetAPI; QMap mPreferences; - - static bool sTemplateLoaded; - static QString sNPAPIWrappperConfigTemplate; - static QMap sNPAPIWrapperTemplates; }; #endif // UBGRAPHICSWIDGETITEM_H From 713c2026fe696be18d036a7c0e7e8129a5293a8c Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Thu, 23 Oct 2025 14:57:37 +0200 Subject: [PATCH 066/133] cleanup: remove and reorder includes - remove unused includes from files modified by previous commits - reorder and sort includes Signed-off-by: letsfindaway --- src/adaptors/UBSvgSubsetAdaptor.cpp | 1 - src/board/UBFeaturesController.cpp | 22 ++++++++++++---------- src/domain/UBGraphicsWidgetItem.cpp | 1 - 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index 7ef040abe..659d2dddd 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -63,7 +63,6 @@ #include "board/UBBoardView.h" #include "board/UBBoardController.h" -#include "board/UBDrawingController.h" #include "board/UBBoardPaletteManager.h" #include "frameworks/UBFileSystemUtils.h" diff --git a/src/board/UBFeaturesController.cpp b/src/board/UBFeaturesController.cpp index 40c7f21e0..c416adfbd 100644 --- a/src/board/UBFeaturesController.cpp +++ b/src/board/UBFeaturesController.cpp @@ -31,24 +31,26 @@ #include #include -#include "core/UBApplication.h" -#include "board/UBBoardController.h" -#include "document/UBDocumentController.h" #include "UBFeaturesController.h" -#include "core/UBSettings.h" -#include "tools/UBToolsManager.h" -#include "frameworks/UBFileSystemUtils.h" -#include "frameworks/UBPlatformUtils.h" -#include "core/UBDownloadManager.h" +#include "board/UBBoardController.h" + +#include "core/UBApplication.h" #include "core/UBPersistenceManager.h" +#include "core/UBSettings.h" + +#include "document/UBDocumentController.h" + #include "domain/UBGraphicsScene.h" -#include "domain/UBGraphicsSvgItem.h" -#include "domain/UBGraphicsPixmapItem.h" #include "domain/UBGraphicsWidgetItem.h" +#include "frameworks/UBFileSystemUtils.h" + #include "gui/UBFeaturesWidget.h" +#include "tools/UBToolsManager.h" + + const QString UBFeaturesController::virtualRootName = "root"; const QString UBFeaturesController::rootPath = "/" + virtualRootName; diff --git a/src/domain/UBGraphicsWidgetItem.cpp b/src/domain/UBGraphicsWidgetItem.cpp index ef13befcb..8edb79d30 100644 --- a/src/domain/UBGraphicsWidgetItem.cpp +++ b/src/domain/UBGraphicsWidgetItem.cpp @@ -52,7 +52,6 @@ #include "core/UBSettings.h" #include "frameworks/UBFileSystemUtils.h" -#include "frameworks/UBPlatformUtils.h" #include "web/UBWebController.h" #include "web/simplebrowser/webpage.h" From 433afd68b34966097556fb99dd2aa2775be1cf56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Tue, 4 Nov 2025 10:25:28 +0100 Subject: [PATCH 067/133] fix: UI buttons could still be triggered despite not being visible + improve thumbnail selection behavior in Ddocuments Mode --- src/gui/UBDocumentThumbnailsView.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/gui/UBDocumentThumbnailsView.cpp b/src/gui/UBDocumentThumbnailsView.cpp index ca9db384a..3c77048d0 100644 --- a/src/gui/UBDocumentThumbnailsView.cpp +++ b/src/gui/UBDocumentThumbnailsView.cpp @@ -148,15 +148,6 @@ void UBDocumentThumbnailsView::mousePressEvent(QMouseEvent *event) mClickTime.restart(); mMousePressPos = event->pos(); - // first ask the thumbnails to process the event for the UI buttons - QGraphicsView::mousePressEvent(event); - - // do not further process event if it was one of the UI buttons - if (event->isAccepted()) - { - return; - } - UBThumbnail* sceneItem = dynamic_cast(itemAt(mMousePressPos)); if (!sceneItem) @@ -187,7 +178,7 @@ void UBDocumentThumbnailsView::mousePressEvent(QMouseEvent *event) } else { - thumbnailScene->hightlightItem(sceneItem->sceneIndex(), false, false); + thumbnailScene->hightlightItem(sceneItem->sceneIndex(), true); } mSelectionSpan = 0; From 97b66dac673f82bbaa6e8a09d5ff190483dad454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Mon, 17 Nov 2025 09:20:55 +0100 Subject: [PATCH 068/133] feat: dark Theme support --- resources/OpenBoard.qrc | 2 + resources/darkTheme.qss | 644 ++++++++++++++++++ resources/etc/OpenBoard.css | 138 ++-- resources/forms/preferences.ui | 176 +++-- resources/lightTheme.qss | 60 ++ resources/startupHints/css/basic.css | 27 +- resources/startupHints/index.html | 46 +- resources/startupHints/locales/de/1.html | 10 +- resources/startupHints/locales/de/10.html | 10 +- resources/startupHints/locales/de/11.html | 10 +- resources/startupHints/locales/de/12.html | 10 +- resources/startupHints/locales/de/2.html | 10 +- resources/startupHints/locales/de/3.html | 10 +- resources/startupHints/locales/de/4.html | 10 +- resources/startupHints/locales/de/5.html | 10 +- resources/startupHints/locales/de/6.html | 10 +- resources/startupHints/locales/de/7.html | 10 +- resources/startupHints/locales/de/8.html | 10 +- resources/startupHints/locales/de/9.html | 10 +- .../startupHints/locales/de/css/dark.css | 8 + .../startupHints/locales/de/css/light.css | 8 + resources/startupHints/locales/de/error.html | 4 +- resources/startupHints/locales/en/1.html | 10 +- resources/startupHints/locales/en/10.html | 10 +- resources/startupHints/locales/en/11.html | 10 +- resources/startupHints/locales/en/12.html | 10 +- resources/startupHints/locales/en/2.html | 10 +- resources/startupHints/locales/en/3.html | 10 +- resources/startupHints/locales/en/4.html | 10 +- resources/startupHints/locales/en/5.html | 10 +- resources/startupHints/locales/en/6.html | 10 +- resources/startupHints/locales/en/7.html | 10 +- resources/startupHints/locales/en/8.html | 10 +- resources/startupHints/locales/en/9.html | 10 +- .../startupHints/locales/en/css/dark.css | 8 + .../startupHints/locales/en/css/light.css | 8 + resources/startupHints/locales/en/error.html | 4 +- resources/startupHints/locales/fr/1.html | 10 +- resources/startupHints/locales/fr/10.html | 10 +- resources/startupHints/locales/fr/11.html | 10 +- resources/startupHints/locales/fr/12.html | 10 +- resources/startupHints/locales/fr/2.html | 10 +- resources/startupHints/locales/fr/3.html | 10 +- resources/startupHints/locales/fr/4.html | 10 +- resources/startupHints/locales/fr/5.html | 10 +- resources/startupHints/locales/fr/6.html | 10 +- resources/startupHints/locales/fr/7.html | 10 +- resources/startupHints/locales/fr/8.html | 10 +- resources/startupHints/locales/fr/9.html | 10 +- .../startupHints/locales/fr/css/dark.css | 8 + .../startupHints/locales/fr/css/light.css | 8 + resources/startupHints/locales/fr/error.html | 4 +- resources/startupHints/locales/hr/1.html | 10 +- resources/startupHints/locales/hr/10.html | 13 +- resources/startupHints/locales/hr/11.html | 13 +- resources/startupHints/locales/hr/12.html | 13 +- resources/startupHints/locales/hr/2.html | 13 +- resources/startupHints/locales/hr/3.html | 13 +- resources/startupHints/locales/hr/4.html | 13 +- resources/startupHints/locales/hr/5.html | 13 +- resources/startupHints/locales/hr/6.html | 13 +- resources/startupHints/locales/hr/7.html | 13 +- resources/startupHints/locales/hr/8.html | 13 +- resources/startupHints/locales/hr/9.html | 13 +- .../startupHints/locales/hr/css/dark.css | 8 + .../startupHints/locales/hr/css/light.css | 8 + resources/startupHints/locales/hr/error.html | 5 +- resources/startupHints/locales/it/1.html | 10 +- resources/startupHints/locales/it/10.html | 13 +- resources/startupHints/locales/it/11.html | 13 +- resources/startupHints/locales/it/12.html | 15 +- resources/startupHints/locales/it/2.html | 13 +- resources/startupHints/locales/it/3.html | 13 +- resources/startupHints/locales/it/4.html | 13 +- resources/startupHints/locales/it/5.html | 10 +- resources/startupHints/locales/it/6.html | 10 +- resources/startupHints/locales/it/7.html | 13 +- resources/startupHints/locales/it/8.html | 13 +- resources/startupHints/locales/it/9.html | 13 +- .../startupHints/locales/it/css/dark.css | 8 + .../startupHints/locales/it/css/light.css | 8 + resources/startupHints/locales/it/error.html | 5 +- resources/style.qss | 143 ++-- src/api/UBWidgetUniboardAPI.cpp | 6 + src/api/UBWidgetUniboardAPI.h | 8 + src/core/CMakeLists.txt | 2 + src/core/UBApplication.cpp | 10 +- src/core/UBPreferencesController.cpp | 7 + src/core/UBSettings.cpp | 1 + src/core/UBSettings.h | 1 + src/core/UBThemeManager.cpp | 355 ++++++++++ src/core/UBThemeManager.h | 184 +++++ src/core/core.pri | 2 + src/desktop/UBDesktopPropertyPalette.cpp | 16 +- src/desktop/UBDesktopPropertyPalette.h | 1 + src/document/UBDocumentController.cpp | 12 +- src/gui/UBDockPalette.cpp | 8 + src/gui/UBFeaturesActionBar.cpp | 5 +- src/gui/UBFeaturesWidget.cpp | 12 +- src/gui/UBFloatingPalette.cpp | 3 +- src/gui/UBMainWindow.cpp | 5 - src/gui/UBStartupHintsPalette.cpp | 5 + 102 files changed, 2225 insertions(+), 418 deletions(-) create mode 100644 resources/darkTheme.qss create mode 100644 resources/lightTheme.qss create mode 100644 resources/startupHints/locales/de/css/dark.css create mode 100644 resources/startupHints/locales/de/css/light.css create mode 100644 resources/startupHints/locales/en/css/dark.css create mode 100644 resources/startupHints/locales/en/css/light.css create mode 100644 resources/startupHints/locales/fr/css/dark.css create mode 100644 resources/startupHints/locales/fr/css/light.css create mode 100644 resources/startupHints/locales/hr/css/dark.css create mode 100644 resources/startupHints/locales/hr/css/light.css create mode 100644 resources/startupHints/locales/it/css/dark.css create mode 100644 resources/startupHints/locales/it/css/light.css create mode 100644 src/core/UBThemeManager.cpp create mode 100644 src/core/UBThemeManager.h diff --git a/resources/OpenBoard.qrc b/resources/OpenBoard.qrc index 6e817b3e6..9b3c12506 100644 --- a/resources/OpenBoard.qrc +++ b/resources/OpenBoard.qrc @@ -226,6 +226,8 @@ images/save.svg images/libpalette/social.png images/navig_arrow.png + darkTheme.qss + lightTheme.qss images/flags/ar.png images/flags/bg.png images/flags/ca.png diff --git a/resources/darkTheme.qss b/resources/darkTheme.qss new file mode 100644 index 000000000..040facc38 --- /dev/null +++ b/resources/darkTheme.qss @@ -0,0 +1,644 @@ +/* + * OpenBoard Dark Theme + */ + +/* Base colors for dark theme */ +QWidget { + background-color: #353535; + color: #ffffff; +} + +QMainWindow { + background-color: #2b2b2b; +} + +/* Dialogs and Windows */ +QDialog, QMessageBox { + background-color: #353535; + color: #ffffff; +} + +/* Text inputs */ +QLineEdit, QTextEdit, QPlainTextEdit { + background-color: #2a2a2a; + color: #ffffff; + border: 1px solid #555555; + border-radius: 3px; + padding: 3px; + selection-background-color: #2a82da; + selection-color: #ffffff; +} + +QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus { + border: 1px solid #2a82da; +} + +QLineEdit:disabled, QTextEdit:disabled, QPlainTextEdit:disabled { + background-color: #404040; + color: #808080; +} + +/* Labels */ +QLabel { + color: #ffffff; + background: transparent; +} + +QLabel:disabled { + color: #808080; +} + +/* Buttons */ +QPushButton { + background-color: #454545; + color: #ffffff; + border: 1px solid #555555; + border-radius: 4px; + padding: 6px 16px; + min-height: 20px; +} + +QPushButton:hover { + background-color: #505050; + border: 1px solid #6a6a6a; +} + +QPushButton:pressed { + background-color: #2a82da; + border: 1px solid #2a82da; +} + +QPushButton:checked { + background-color: #2a82da; +} + +QPushButton:disabled { + background-color: #404040; + color: #808080; + border: 1px solid #404040; +} + +QPushButton:default { + background-color: #2a82da; + border: 2px solid #3d8fd1; +} + +/* Checkboxes and Radio buttons */ +QCheckBox, QRadioButton { + color: #ffffff; + spacing: 5px; +} + +QCheckBox:disabled, QRadioButton:disabled { + color: #808080; +} + +QCheckBox::indicator, QRadioButton::indicator { + width: 16px; + height: 16px; + border: 1px solid #555555; + border-radius: 3px; + background-color: #2a2a2a; +} + +QCheckBox::indicator:hover, QRadioButton::indicator:hover { + border: 1px solid #6a6a6a; +} + +QCheckBox::indicator:checked, QRadioButton::indicator:checked { + background-color: #2a82da; +} + +QRadioButton::indicator { + border-radius: 8px; +} + +/* Combo boxes */ +QComboBox { + background-color: #2a2a2a; + color: #ffffff; + border: 1px solid #555555; + border-radius: 3px; + padding: 4px 8px; + min-height: 20px; +} + +QComboBox:hover { + border: 1px solid #6a6a6a; +} + +QComboBox:focus { + border: 1px solid #2a82da; +} + +QComboBox::drop-down { + border: none; + width: 20px; +} + +QComboBox::down-arrow { + image: url(:/images/down_arrow.png); + width: 12px; + height: 12px; +} + +QComboBox QAbstractItemView { + background-color: #2a2a2a; + color: #ffffff; + border: 1px solid #555555; + selection-background-color: #2a82da; + selection-color: #ffffff; + outline: none; +} + +QComboBox QAbstractItemView::item { + padding: 4px; + min-height: 20px; +} + +QComboBox QAbstractItemView::item:hover { + background-color: #404040; +} + +/* Spin boxes */ +QSpinBox, QDoubleSpinBox { + background-color: #2a2a2a; + color: #ffffff; + border: 1px solid #555555; + border-radius: 3px; + padding: 3px; +} + +QSpinBox:focus, QDoubleSpinBox:focus { + border: 1px solid #2a82da; +} + +QSpinBox::up-button, QDoubleSpinBox::up-button { + background-color: #404040; + border-left: 1px solid #555555; + border-top-right-radius: 3px; +} + +QSpinBox::down-button, QDoubleSpinBox::down-button { + background-color: #404040; + border-left: 1px solid #555555; + border-bottom-right-radius: 3px; +} + +QSpinBox::up-button:hover, QDoubleSpinBox::up-button:hover, +QSpinBox::down-button:hover, QDoubleSpinBox::down-button:hover { + background-color: #505050; +} + +/* Sliders */ +QSlider::groove:horizontal { + background-color: #404040; + height: 8px; + border-radius: 4px; + border: 1px solid #2a2a2a; +} + +QSlider::handle:horizontal { + background-color: #2a82da; + border: 1px solid #3d8fd1; + width: 16px; + margin: -5px 0; + border-radius: 8px; +} + +QSlider::handle:horizontal:hover { + background-color: #3d8fd1; +} + +QSlider::groove:vertical { + background-color: #404040; + width: 8px; + border-radius: 4px; + border: 1px solid #2a2a2a; +} + +QSlider::handle:vertical { + background-color: #2a82da; + border: 1px solid #3d8fd1; + height: 16px; + margin: 0 -5px; + border-radius: 8px; +} + +/* Scrollbars */ +QScrollBar:vertical { + background: #2b2b2b; + width: 14px; + margin: 18px 1px 18px 1px; +} + +QScrollBar::handle:vertical { + background: #555555; + min-height: 30px; + border-radius: 6px; + border: 1px solid #404040; +} + +QScrollBar::handle:vertical:hover { + background: #6a6a6a; +} + +QScrollBar::add-line:vertical { + background: #404040; + height: 16px; + subcontrol-position: bottom; + subcontrol-origin: margin; + border-radius: 6px; + margin: 1px 1px 2px 1px; +} + +QScrollBar::sub-line:vertical { + background: #404040; + height: 16px; + subcontrol-position: top; + subcontrol-origin: margin; + border-radius: 6px; + margin: 2px 1px 1px 1px; +} + +QScrollBar::add-line:vertical:hover, +QScrollBar::sub-line:vertical:hover { + background: #505050; +} + +QScrollBar:horizontal { + background: #2b2b2b; + height: 14px; + margin: 1px 18px 1px 18px; +} + +QScrollBar::handle:horizontal { + background: #555555; + min-width: 30px; + border-radius: 6px; + border: 1px solid #404040; +} + +QScrollBar::handle:horizontal:hover { + background: #6a6a6a; +} + +QScrollBar::add-line:horizontal { + background: #404040; + width: 16px; + subcontrol-position: right; + subcontrol-origin: margin; + border-radius: 6px; + margin: 1px 2px 1px 1px; +} + +QScrollBar::sub-line:horizontal { + background: #404040; + width: 16px; + subcontrol-position: left; + subcontrol-origin: margin; + border-radius: 6px; + margin: 1px 1px 1px 2px; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical, +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { + background: none; +} + +/* Tab widgets */ +QTabWidget::pane { + border: 1px solid #555555; + background-color: #353535; + border-top: none; +} + +QTabBar::tab { + background-color: #2b2b2b; + color: #ffffff; + border: 1px solid #555555; + padding: 6px 12px; + margin-right: 2px; +} + +QTabBar::tab:selected { + background-color: #353535; + border-bottom: none; + color: #ffffff; +} + +QTabBar::tab:hover:!selected { + background-color: #404040; +} + +QTabBar::tab:top { + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} + +/* Group boxes */ +QGroupBox { + color: #ffffff; + border: 1px solid #555555; + border-radius: 5px; + margin-top: 12px; + font-weight: bold; + padding-top: 10px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + padding: 0 5px; + color: #ffffff; + background-color: #353535; +} + +/* Tree and List views */ +QTreeView, QListView, QTableView { + background-color: #2a2a2a; + color: #ffffff; + border: 1px solid #555555; + alternate-background-color: #323232; + selection-background-color: #2a82da; + selection-color: #ffffff; + show-decoration-selected: 1; + outline: none; +} + +QTreeView::item, QListView::item, QTableView::item { + padding: 3px; +} + +QTreeView::item:hover, QListView::item:hover, QTableView::item:hover { + background-color: #404040; +} + +QTreeView::item:selected, QListView::item:selected, QTableView::item:selected { + background-color: #2a82da; + color: #ffffff; +} + +QTreeView::branch { + background-color: #2a2a2a; +} + +QTreeView::branch:hover { + background-color: #404040; +} + +QHeaderView::section { + background-color: #404040; + color: #ffffff; + padding: 4px; + border: 1px solid #555555; + font-weight: bold; +} + +QHeaderView::section:hover { + background-color: #505050; +} + +/* Menus */ +QMenuBar { + background-color: #2b2b2b; + color: #ffffff; + border-bottom: 1px solid #555555; +} + +QMenuBar::item { + background-color: transparent; + padding: 4px 8px; +} + +QMenuBar::item:selected { + background-color: #2a82da; +} + +QMenuBar::item:pressed { + background-color: #2a82da; +} + +QMenu { + background-color: #2a2a2a; + color: #ffffff; + border: 1px solid #555555; + padding: 4px; +} + +QMenu::item { + padding: 6px 30px 6px 30px; + border-radius: 3px; +} + +QMenu::item:selected { + background-color: #2a82da; +} + +QMenu::separator { + height: 1px; + background-color: #555555; + margin: 4px 0px; +} + +/* Toolbars */ +QToolBar { + background-color: #2b2b2b; + border: 1px solid #555555; + spacing: 3px; + padding: 5px; +} + +QToolBar::separator { + background-color: #555555; + width: 1px; + margin: 4px; +} + +QToolButton { + background-color: transparent; + color: #ffffff; + border: 1px solid transparent; + border-radius: 4px; + padding: 5px; + margin: 2px; +} + +QToolButton:hover { + background-color: #404040; + border: 1px solid #555555; +} + +QToolButton:pressed { + background-color: #2a82da; + border: 1px solid #2a82da; +} + +QToolButton:checked { + background-color: #2a82da; +} + +QToolButton[popupMode="1"] { /* only for MenuButtonPopup */ + padding-right: 20px; +} + +QToolButton::menu-button { + border: 1px solid #555555; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + width: 16px; +} + +/* Progress bars */ +QProgressBar { + background-color: #2a2a2a; + border: 1px solid #555555; + border-radius: 4px; + text-align: center; + color: #ffffff; + height: 20px; +} + +QProgressBar::chunk { + background-color: #2a82da; + border-radius: 3px; +} + +/* Status bar */ +QStatusBar { + background-color: #2b2b2b; + color: #ffffff; + border-top: 1px solid #555555; +} + +QStatusBar::item { + border: none; +} + +/* Splitter */ +QSplitter::handle { + background-color: #555555; +} + +QSplitter::handle:horizontal { + width: 2px; +} + +QSplitter::handle:vertical { + height: 2px; +} + +QSplitter::handle:hover { + background-color: #2a82da; +} + +/* Dock widgets */ +QDockWidget { + color: #ffffff; + titlebar-close-icon: url(:/images/close.png); + titlebar-normal-icon: url(:/images/undock.png); +} + +QDockWidget::title { + background-color: #404040; + text-align: left; + padding-left: 5px; + padding-top: 3px; + padding-bottom: 3px; +} + +QDockWidget::close-button, QDockWidget::float-button { + background-color: #404040; + border: none; + padding: 0px; +} + +QDockWidget::close-button:hover, QDockWidget::float-button:hover { + background-color: #505050; +} + +/* Tooltips */ +QToolTip { + background-color: #404040; + color: palette(tooltip-text); + border: 1px solid #555555; + padding: 4px; + border-radius: 3px; +} + +/* Scroll areas */ +QScrollArea { + background-color: #353535; + border: none; +} + +/* Calendar widget */ +QCalendarWidget { + background-color: #2a2a2a; +} + +QCalendarWidget QToolButton { + color: #ffffff; + background-color: #404040; +} + +QCalendarWidget QMenu { + background-color: #2a2a2a; +} + +QCalendarWidget QSpinBox { + background-color: #404040; + color: #ffffff; +} + +QCalendarWidget QWidget#qt_calendar_navigationbar { + background-color: #2b2b2b; +} + +/* Size grip */ +QSizeGrip { + background-color: transparent; +} + +/* Override OpenBoard.css button group styles for dark mode */ +/* Only override colors, preserve the border structure from OpenBoard.css */ +QToolButton#ubButtonGroupLeft, +QToolButton#ubButtonGroupCenter, +QToolButton#ubButtonGroupRight, +QToolButton#desktop-ubButtonGroupLeft, +QToolButton#desktop-ubButtonGroupCenter, +QToolButton#desktop-ubButtonGroupRight +{ + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #505050, stop: 1 #3a3a3a); + color: #ffffff; + border-radius: 0px; /* Reset the global QToolButton border-radius */; + border-left: none; + border-right: none; +} + +QToolButton#ubButtonGroupLeft:hover, +QToolButton#ubButtonGroupCenter:hover, +QToolButton#ubButtonGroupRight:hover, +QToolButton#desktop-ubButtonGroupLeft:hover, +QToolButton#desktop-ubButtonGroupCenter:hover, +QToolButton#desktop-ubButtonGroupRight:hover +{ + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #606060, stop: 1 #4a4a4a); +} + +QToolButton#ubButtonGroupLeft:checked, +QToolButton#ubButtonGroupCenter:checked, +QToolButton#ubButtonGroupRight:checked, +QToolButton#desktop-ubButtonGroupLeft:checked, +QToolButton#desktop-ubButtonGroupCenter:checked, +QToolButton#desktop-ubButtonGroupRight:checked +{ + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #2a82da, stop: 1 #1e5fa0); + border: 1px solid #2a82da; +} + +QWidget#UBFeaturesActionBar QToolButton +{ + padding: 0px; +} + diff --git a/resources/etc/OpenBoard.css b/resources/etc/OpenBoard.css index 92672b44e..db7f4208c 100644 --- a/resources/etc/OpenBoard.css +++ b/resources/etc/OpenBoard.css @@ -1,77 +1,78 @@ QWidget:enabled { - color: #3F3F3F; + color: palette(text); } QWidget:disabled { - color: #777777; + color: palette(disabled, text); } QComboBox, QPushButton, QComboBox QAbstractItemView { - background: #dddddd; + background: palette(button); } QTextEdit, QLineEdit, QComboBox#DockPaletteWidgetComboBox QAbstractItemView { - selection-background-color: lightgreen; - selection-color: black; + selection-background-color: palette(highlight); + selection-color: palette(highlighted-text); } -QProgressBar:horizontal { - border: 1px solid gray; +QProgressBar:horizontal +{ + border: 1px solid palette(mid); border-radius: 3px; - background: white; + background: palette(base); padding: 1px; } -QProgressBar::chunk:horizontal { - /*background: qlineargradient(x1: 0, y1: 0.5, x2: 1, y2: 0.5, stop: 0 green, stop: 1 lightgreen);*/ - background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4); +QProgressBar::chunk:horizontal +{ + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 palette(mid), stop:1 palette(button)); } QMainWindow { - background-color: #F1F1F1; + background-color: palette(window); } QDialog { - background-color: #dddddd; + background-color: palette(button); } QMenu { border: none; font-size: 12px; - background-color: #dddddd; + background-color: palette(button); } QMenu::item { - background-color: #b3b3b3; + background-color: palette(midlight); } QMenu::item:selected { - background-color: #9f9f9f; + background-color: palette(mid); } QMenu::separator { - background-color: #b3b3b3; - border: 1px dotted #888888; + background-color: palette(midlight); + border: 1px dotted palette(dark); } QToolBar { spacing: 0px; - background-color: #b3b3b3; + background-color: palette(midlight); border: none; - border-bottom: 1px solid #888888; + border-bottom: 1px solid palette(dark); } QToolBar::handle @@ -82,7 +83,7 @@ QToolBar::handle QToolBar::separator { - border: 1px dotted #888888; border-left: none; margin-left: 5px; margin-right: 5px; width: 1px; + border: 1px dotted palette(dark); border-left: none; margin-left: 5px; margin-right: 5px; width: 1px; } QToolBar QToolButton @@ -105,101 +106,63 @@ QToolBar QToolButton:pressed border: none; height: 58px; - background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, - fx:0.5, fy:0.5, stop: 0 #d3d3d3, stop: 1 #b3b3b3); + background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop: 0 #d3d3d3, stop: 1 #b3b3b3); } QDialog QToolButton:pressed { - background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, - fx:0.5, fy:0.5, stop: 0 #ffffff, stop: 1 #dddddd); + background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop: 0 #ffffff, stop: 1 #dddddd); } QToolButton#ubButtonGroupLeft, QToolButton#desktop-ubButtonGroupLeft { - background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #d3d3d3, stop: 1 #c4c4c4); margin-top: 1px; margin-right: 0px; padding: 5px; - - border: 1px solid #444444; - border-right: none; - border-top-left-radius : 3px; - border-bottom-left-radius : 3px; height: 14px; } QToolButton#ubButtonGroupCenter, QToolButton#desktop-ubButtonGroupCenter { - background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #d3d3d3, stop: 1 #c4c4c4); margin-top: 1px; margin-right: 0px; margin-left: 0px; padding: 5px; - - border: 1px solid #444444; - border-right: none; - border-left: none; height: 14px; } QToolButton#ubButtonGroupRight, QToolButton#desktop-ubButtonGroupRight { - background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #d3d3d3, stop: 1 #c4c4c4); margin-top: 1px; margin-left: 0px; padding: 5px; - - border: 1px solid #444444; - border-left: none; - border-top-right-radius : 3px; - border-bottom-right-radius : 3px; height: 14px; } -QToolButton#desktop-ubButtonGroupLeft -QToolButton#desktop-ubButtonGroupCenter, -QToolButton#desktop-ubButtonGroupRight -{ - background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #c3c3c3, stop: 1 #ffffff); -} - -QToolButton#desktop-ubButtonGroupLeft:checked, -QToolButton#desktop-ubButtonGroupCenter:checked, -QToolButton#desktop-ubButtonGroupRight:checked -{ - border:1px solid white; - background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #c3c3c3, stop: 1 #ffffff); -} - QToolButton#ubButtonGroupLeft:checked, QToolButton#ubButtonGroupCenter:checked, QToolButton#ubButtonGroupRight:checked { - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #c3c3c3, stop: 1 #b4b4b4); + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 palette(light), stop: 1 palette(midlight)); } QToolButton#ubButtonGroupLeft:checked { - border-right: 1px solid #444444; padding-right: 4px; } QToolButton#ubButtonGroupCenter:checked { - border-left: 1px solid #444444; - border-right: 1px solid #444444; padding-right: 4px; padding-left: 4px; } QToolButton#ubButtonGroupRight:checked { - border-left: 1px solid #444444; padding-left: 4px; } @@ -212,7 +175,7 @@ QToolButton#ubButtonMenu QToolButton#ubButtonMenu:pressed, QToolButton#ubButtonMenu:checked { - background-color: #b3b3b3; + background-color: palette(midlight); } QToolButton#ubActionPaletteButton @@ -237,22 +200,22 @@ QFrame#videoTopLeftFrame, QFrame#toolTopLeftFrame { border: none; - border-right: 1px solid #888888; + border-right: 1px solid palette(dark); } QWidget#topRightFrame { - background-color: #d3d3d3; + background-color: palette(light); } QFrame#toolFrame { - border-top: 1px solid #888888; + border-top: 1px solid palette(dark); } QTreeView { - background-color: rgb(209, 215, 226); + background-color: palette(base); } QTreeView::item:selected:active @@ -298,16 +261,16 @@ QTreeView::branch:open:has-children:has-siblings QSlider::groove:horizontal { - border: 1px solid #999999; + border: 1px solid palette(mid); height: 2px; - background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4); + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 palette(mid), stop:1 palette(button)); margin: 2px 0; } QSlider::handle:horizontal { - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #aaaaaa, stop: 1 #b8b8b8); - border: 1px solid #5c5c5c; + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 palette(midlight), stop: 1 palette(button)); + border: 1px solid palette(dark); width: 18px; margin: -2px 0; @@ -316,14 +279,14 @@ QSlider::handle:horizontal QTabWidget::pane { - border: 1px solid #888888; + border: 1px solid palette(dark); margin-top: -2px; } QTabWidget::pane#libraryTabWidget { border: none; - border-top: 1px solid #888888; + border-top: 1px solid palette(dark); } QTabWidget::tab-bar @@ -333,15 +296,15 @@ QTabWidget::tab-bar QTabWidget::tab-bar#ubWebBrowserTabWidget { - background: #dddddd; + background: palette(button); alignment: left; } QTabBar::tab { - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #d3d3d3, stop: 1 #c4c4c4); + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 palette(light), stop: 1 palette(button)); - border: 1px solid #888888; + border: 1px solid palette(dark); border-bottom: none; @@ -359,51 +322,52 @@ QTabBar::tab QTabBar::tab:first { - border-left: 1px solid #888888; + border-left: 1px solid palette(dark); } QTabBar::tab:last { - border-right: 1px solid #888888; + border-right: 1px solid palette(dark); } QTabBar::tab:selected { - border-right: 1px solid #888888; - border-left: 1px solid #888888; + border-right: 1px solid palette(dark); + border-left: 1px solid palette(dark); border-bottom: none; } QTabBar::tab:first:selected { - border-right: 1px solid #888888; + border-right: 1px solid palette(dark); } QTabBar::tab:last:selected { - border-left: 1px solid #888888; + border-left: 1px solid palette(dark); } QTabBar::tab:selected { - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #aaaaaa, stop: 1 #b8b8b8); + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 palette(midlight), stop: 1 palette(button)); } QTabBar::tab#ubWebBrowserTabBar { - background: #dddddd; + background: palette(button); min-width: 150px; } QTabBar::tab:selected#ubWebBrowserTabBar { - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #b3b3b3, stop: 1 #dddddd); + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 palette(midlight), stop: 1 palette(button)); } QLineEdit#ubWebBrowserLineEdit { - border: 1px solid #888888; + border: 1px solid palette(dark); border-radius: 3px; padding: 2 2px; - background: white; + background: palette(base); } + diff --git a/resources/forms/preferences.ui b/resources/forms/preferences.ui index 45a2fc180..47bb06382 100644 --- a/resources/forms/preferences.ui +++ b/resources/forms/preferences.ui @@ -24,10 +24,10 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Raised + QFrame::Shadow::Raised @@ -52,7 +52,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -82,7 +82,7 @@ - 7 + 0 @@ -98,8 +98,8 @@ 0 - -285 - 1013 + -321 + 1018 765 @@ -113,7 +113,7 @@ 0 - 416 + 426 1011 111 @@ -149,10 +149,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QSizePolicy::Preferred + QSizePolicy::Policy::Preferred @@ -165,7 +165,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -220,10 +220,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QSizePolicy::Preferred + QSizePolicy::Policy::Preferred @@ -236,7 +236,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -252,9 +252,9 @@ 0 - 620 + 650 1011 - 101 + 111 @@ -304,10 +304,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QSizePolicy::Fixed + QSizePolicy::Policy::Fixed @@ -320,7 +320,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -354,10 +354,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QSizePolicy::Expanding + QSizePolicy::Policy::Expanding @@ -395,10 +395,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QSizePolicy::Preferred + QSizePolicy::Policy::Preferred @@ -435,7 +435,7 @@ - QLayout::SetDefaultConstraint + QLayout::SizeConstraint::SetDefaultConstraint @@ -472,7 +472,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -487,10 +487,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QSizePolicy::Preferred + QSizePolicy::Policy::Preferred @@ -503,10 +503,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QSizePolicy::Preferred + QSizePolicy::Policy::Preferred @@ -524,7 +524,7 @@ 0 540 1011 - 71 + 111 @@ -565,10 +565,36 @@ + + + + Theme: + + + + + + + + Auto + + + + + Light + + + + + Dark + + + + - Qt::Horizontal + Qt::Orientation::Horizontal @@ -583,10 +609,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QSizePolicy::Preferred + QSizePolicy::Policy::Preferred @@ -628,10 +654,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QSizePolicy::Preferred + QSizePolicy::Policy::Preferred @@ -651,7 +677,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -679,19 +705,19 @@ true - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Raised + QFrame::Shadow::Raised - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Raised + QFrame::Shadow::Raised @@ -704,7 +730,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -723,10 +749,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -736,16 +762,16 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Raised + QFrame::Shadow::Raised - Qt::Horizontal + Qt::Orientation::Horizontal @@ -774,10 +800,10 @@ 50 - Qt::Horizontal + Qt::Orientation::Horizontal - QSlider::TicksAbove + QSlider::TickPosition::TicksAbove 20 @@ -787,7 +813,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -803,10 +829,10 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Raised + QFrame::Shadow::Raised @@ -819,7 +845,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -838,10 +864,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -851,16 +877,16 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Raised + QFrame::Shadow::Raised - Qt::Horizontal + Qt::Orientation::Horizontal @@ -889,10 +915,10 @@ 50 - Qt::Horizontal + Qt::Orientation::Horizontal - QSlider::TicksAbove + QSlider::TickPosition::TicksAbove 20 @@ -902,7 +928,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -921,7 +947,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -941,10 +967,10 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Raised + QFrame::Shadow::Raised @@ -958,10 +984,10 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Raised + QFrame::Shadow::Raised @@ -1052,7 +1078,7 @@ - QLineEdit::Password + QLineEdit::EchoMode::Password @@ -1064,10 +1090,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QSizePolicy::Preferred + QSizePolicy::Policy::Preferred @@ -1083,7 +1109,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -1255,7 +1281,7 @@ */ - Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::TextSelectableByKeyboard|Qt::TextInteractionFlag::TextSelectableByMouse @@ -1300,7 +1326,7 @@ Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu - Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::TextSelectableByKeyboard|Qt::TextInteractionFlag::TextSelectableByMouse @@ -2012,7 +2038,7 @@ Public License instead of this License. But first, please read --8<---------------cut here---------------end--------------->8--- - Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::TextSelectableByKeyboard|Qt::TextInteractionFlag::TextSelectableByMouse @@ -2382,7 +2408,7 @@ Public License instead of this License. --8<---------------cut here---------------end--------------->8--- - Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::TextSelectableByKeyboard|Qt::TextInteractionFlag::TextSelectableByMouse @@ -3089,7 +3115,7 @@ Public License instead of this License. But first, please read --8<---------------cut here---------------end--------------->8--- - Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::TextSelectableByKeyboard|Qt::TextInteractionFlag::TextSelectableByMouse @@ -3114,6 +3140,8 @@ Public License instead of this License. But first, please read <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } +li.unchecked::marker { content: "\2610"; } +li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:12pt; font-weight:600;">Translations</span><span style=" font-family:'Cantarell'; font-size:10pt;"><br /></span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">A special thanks to:<br /></span></p> @@ -3219,6 +3247,8 @@ hr { height: 1px; border-width: 0; } <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } +li.unchecked::marker { content: "\2610"; } +li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> <table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> <tr> diff --git a/resources/lightTheme.qss b/resources/lightTheme.qss new file mode 100644 index 000000000..716b2237a --- /dev/null +++ b/resources/lightTheme.qss @@ -0,0 +1,60 @@ +/* + * OpenBoard Light Theme + */ + +QToolButton#ubButtonGroupLeft, +QToolButton#ubButtonGroupCenter, +QToolButton#ubButtonGroupRight, +QToolButton#desktop-ubButtonGroupLeft, +QToolButton#desktop-ubButtonGroupCenter, +QToolButton#desktop-ubButtonGroupRight +{ + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #d3d3d3, stop: 1 #c4c4c4); + color: palette(button-text); + border-radius: 0px; + border: 1px solid palette(dark); + border-left: none; + border-right: none; +} + +QToolButton#ubButtonGroupLeft, +QToolButton#desktop-ubButtonGroupLeft +{ + border-left: 1px solid palette(dark); + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; +} + +QToolButton#ubButtonGroupRight, +QToolButton#desktop-ubButtonGroupRight +{ + border-right: 1px solid palette(dark); + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} + +/* Desktop button group variants with lighter gradient */ +QToolButton#desktop-ubButtonGroupLeft, +QToolButton#desktop-ubButtonGroupCenter, +QToolButton#desktop-ubButtonGroupRight +{ + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #c3c3c3, stop: 1 #ffffff); +} + +/* Checked state for desktop buttons */ +QToolButton#desktop-ubButtonGroupLeft:checked, +QToolButton#desktop-ubButtonGroupCenter:checked, +QToolButton#desktop-ubButtonGroupRight:checked +{ + border: 1px solid white; + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #c3c3c3, stop: 1 #ffffff); +} + +/* Checked state for board buttons */ +QToolButton#ubButtonGroupLeft:checked, +QToolButton#ubButtonGroupCenter:checked, +QToolButton#ubButtonGroupRight:checked +{ + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 palette(light), stop: 1 palette(midlight)); + border: 1px solid palette(dark); +} diff --git a/resources/startupHints/css/basic.css b/resources/startupHints/css/basic.css index e6b509beb..2420a0d92 100644 --- a/resources/startupHints/css/basic.css +++ b/resources/startupHints/css/basic.css @@ -1,3 +1,21 @@ +:root { + /* Default light theme colors */ + --bg-outer: #aaaaaa; + --bg-main: #eeeeee; + --border-color: #999999; + --separator-color: #ccc; + --text-color: #000000; +} + +:root[data-theme="dark"] { + /* Dark theme colors */ + --bg-outer: #555555; + --bg-main: #3a3a3a; + --border-color: #666666; + --separator-color: #555; + --text-color: #e0e0e0; +} + html, body{ width: 100%; height: 100%; @@ -8,17 +26,18 @@ html, body{ } body{ - background-color: #aaaaaa; + background-color: var(--bg-outer); } #main{ - background-color: #eeeeee; + background-color: var(--bg-main); + color: var(--text-color); width: 99%; margin: 0px; margin-left:1px; padding: 0px; height: 99%; - border-color:#999999; + border-color: var(--border-color); border-width:2px; border-radius:10px; border-style:solid; @@ -39,7 +58,7 @@ iframe{ #separator{ width: 96%; margin: 0 auto; - border: 2px solid #ccc; + border: 2px solid var(--separator-color); } #controls{ diff --git a/resources/startupHints/index.html b/resources/startupHints/index.html index 6353c7c5a..af26adfe8 100644 --- a/resources/startupHints/index.html +++ b/resources/startupHints/index.html @@ -7,7 +7,33 @@ diff --git a/resources/startupHints/locales/de/1.html b/resources/startupHints/locales/de/1.html index 6319ac5cb..0c89a4ed3 100644 --- a/resources/startupHints/locales/de/1.html +++ b/resources/startupHints/locales/de/1.html @@ -1,9 +1,15 @@ - + Tipps und Tricks - + + + diff --git a/resources/startupHints/locales/de/10.html b/resources/startupHints/locales/de/10.html index c72287117..7d1aa4fdb 100644 --- a/resources/startupHints/locales/de/10.html +++ b/resources/startupHints/locales/de/10.html @@ -1,9 +1,15 @@ - + Applikationen - + + + diff --git a/resources/startupHints/locales/de/11.html b/resources/startupHints/locales/de/11.html index 0fba2fac1..0fc78d7d0 100644 --- a/resources/startupHints/locales/de/11.html +++ b/resources/startupHints/locales/de/11.html @@ -1,9 +1,15 @@ - + Videoaufnahme - + + + diff --git a/resources/startupHints/locales/de/12.html b/resources/startupHints/locales/de/12.html index 66b003714..b2973234d 100644 --- a/resources/startupHints/locales/de/12.html +++ b/resources/startupHints/locales/de/12.html @@ -1,9 +1,15 @@ - + Favoriten-Dokumente - + + + diff --git a/resources/startupHints/locales/de/2.html b/resources/startupHints/locales/de/2.html index ce479061f..5bd485bcb 100644 --- a/resources/startupHints/locales/de/2.html +++ b/resources/startupHints/locales/de/2.html @@ -1,9 +1,15 @@ - + Board-Modus - + + + diff --git a/resources/startupHints/locales/de/3.html b/resources/startupHints/locales/de/3.html index fd31a49f4..43413d282 100644 --- a/resources/startupHints/locales/de/3.html +++ b/resources/startupHints/locales/de/3.html @@ -1,9 +1,15 @@ - + Desktop-Modus - + + + diff --git a/resources/startupHints/locales/de/4.html b/resources/startupHints/locales/de/4.html index 08f334715..37d0e9b0c 100644 --- a/resources/startupHints/locales/de/4.html +++ b/resources/startupHints/locales/de/4.html @@ -1,9 +1,15 @@ - + Dokumenten-Modus - + + + diff --git a/resources/startupHints/locales/de/5.html b/resources/startupHints/locales/de/5.html index bf51f1176..8210b0394 100644 --- a/resources/startupHints/locales/de/5.html +++ b/resources/startupHints/locales/de/5.html @@ -1,9 +1,15 @@ - + Dokumenten-Modus - + + + diff --git a/resources/startupHints/locales/de/6.html b/resources/startupHints/locales/de/6.html index f66431dfc..ae3745e84 100644 --- a/resources/startupHints/locales/de/6.html +++ b/resources/startupHints/locales/de/6.html @@ -1,9 +1,15 @@ - + Internet-Modus - + + + diff --git a/resources/startupHints/locales/de/7.html b/resources/startupHints/locales/de/7.html index ce1ab539d..77209db69 100644 --- a/resources/startupHints/locales/de/7.html +++ b/resources/startupHints/locales/de/7.html @@ -1,9 +1,15 @@ - + Bildschirmaufnahme - + + + diff --git a/resources/startupHints/locales/de/8.html b/resources/startupHints/locales/de/8.html index ab34f00a8..55f84e3de 100644 --- a/resources/startupHints/locales/de/8.html +++ b/resources/startupHints/locales/de/8.html @@ -1,9 +1,15 @@ - + Bilder - + + + diff --git a/resources/startupHints/locales/de/9.html b/resources/startupHints/locales/de/9.html index 8ca9d819d..25dc0b8a8 100644 --- a/resources/startupHints/locales/de/9.html +++ b/resources/startupHints/locales/de/9.html @@ -1,9 +1,15 @@ - + Interaktivitäten - + + + diff --git a/resources/startupHints/locales/de/css/dark.css b/resources/startupHints/locales/de/css/dark.css new file mode 100644 index 000000000..34ded372a --- /dev/null +++ b/resources/startupHints/locales/de/css/dark.css @@ -0,0 +1,8 @@ +body { + background-color: #3a3a3a; + color: #e0e0e0; +} + +.title { + color: #8ba3d7; +} diff --git a/resources/startupHints/locales/de/css/light.css b/resources/startupHints/locales/de/css/light.css new file mode 100644 index 000000000..d40cfaea3 --- /dev/null +++ b/resources/startupHints/locales/de/css/light.css @@ -0,0 +1,8 @@ +body { + background-color: #ffffff; + color: #000000; +} + +.title { + color: #6682b5; +} diff --git a/resources/startupHints/locales/de/error.html b/resources/startupHints/locales/de/error.html index e396c93ee..262f89bd3 100644 --- a/resources/startupHints/locales/de/error.html +++ b/resources/startupHints/locales/de/error.html @@ -1,5 +1,5 @@ - - + + Fehler diff --git a/resources/startupHints/locales/en/1.html b/resources/startupHints/locales/en/1.html index af197854a..291a1b213 100644 --- a/resources/startupHints/locales/en/1.html +++ b/resources/startupHints/locales/en/1.html @@ -1,9 +1,15 @@ - + Hints and tips - + + + diff --git a/resources/startupHints/locales/en/10.html b/resources/startupHints/locales/en/10.html index e6c8eb617..9875372cd 100644 --- a/resources/startupHints/locales/en/10.html +++ b/resources/startupHints/locales/en/10.html @@ -1,9 +1,15 @@ - + Applications - + + + diff --git a/resources/startupHints/locales/en/11.html b/resources/startupHints/locales/en/11.html index 49a409612..fde8f3012 100644 --- a/resources/startupHints/locales/en/11.html +++ b/resources/startupHints/locales/en/11.html @@ -1,9 +1,15 @@ - + Video Capture - + + + diff --git a/resources/startupHints/locales/en/12.html b/resources/startupHints/locales/en/12.html index 00d01f9e7..831c78a02 100644 --- a/resources/startupHints/locales/en/12.html +++ b/resources/startupHints/locales/en/12.html @@ -1,9 +1,15 @@ - + Favorite Documents - + + + diff --git a/resources/startupHints/locales/en/2.html b/resources/startupHints/locales/en/2.html index 4ac62998b..c701e461c 100644 --- a/resources/startupHints/locales/en/2.html +++ b/resources/startupHints/locales/en/2.html @@ -1,9 +1,15 @@ - + Board Mode - + + + diff --git a/resources/startupHints/locales/en/3.html b/resources/startupHints/locales/en/3.html index 16e87b4fc..47e9e3672 100644 --- a/resources/startupHints/locales/en/3.html +++ b/resources/startupHints/locales/en/3.html @@ -1,9 +1,15 @@ - + Desktop Mode - + + + diff --git a/resources/startupHints/locales/en/4.html b/resources/startupHints/locales/en/4.html index dbdf7b61d..f7fc4a577 100644 --- a/resources/startupHints/locales/en/4.html +++ b/resources/startupHints/locales/en/4.html @@ -1,9 +1,15 @@ - + Documents Mode - + + + diff --git a/resources/startupHints/locales/en/5.html b/resources/startupHints/locales/en/5.html index a412ec34b..9c4335bfd 100644 --- a/resources/startupHints/locales/en/5.html +++ b/resources/startupHints/locales/en/5.html @@ -1,9 +1,15 @@ - + Documents Mode - + + + diff --git a/resources/startupHints/locales/en/6.html b/resources/startupHints/locales/en/6.html index 615001a33..7067f41ba 100644 --- a/resources/startupHints/locales/en/6.html +++ b/resources/startupHints/locales/en/6.html @@ -1,9 +1,15 @@ - + Web Mode - + + + diff --git a/resources/startupHints/locales/en/7.html b/resources/startupHints/locales/en/7.html index bdf8e0478..9f415622c 100644 --- a/resources/startupHints/locales/en/7.html +++ b/resources/startupHints/locales/en/7.html @@ -1,9 +1,15 @@ - + Screen Capture - + + + diff --git a/resources/startupHints/locales/en/8.html b/resources/startupHints/locales/en/8.html index 358f17038..c0bdac95b 100644 --- a/resources/startupHints/locales/en/8.html +++ b/resources/startupHints/locales/en/8.html @@ -1,9 +1,15 @@ - + Images - + + + diff --git a/resources/startupHints/locales/en/9.html b/resources/startupHints/locales/en/9.html index f9fee4aee..caf0e3b36 100644 --- a/resources/startupHints/locales/en/9.html +++ b/resources/startupHints/locales/en/9.html @@ -1,9 +1,15 @@ - + Interactivities - + + + diff --git a/resources/startupHints/locales/en/css/dark.css b/resources/startupHints/locales/en/css/dark.css new file mode 100644 index 000000000..34ded372a --- /dev/null +++ b/resources/startupHints/locales/en/css/dark.css @@ -0,0 +1,8 @@ +body { + background-color: #3a3a3a; + color: #e0e0e0; +} + +.title { + color: #8ba3d7; +} diff --git a/resources/startupHints/locales/en/css/light.css b/resources/startupHints/locales/en/css/light.css new file mode 100644 index 000000000..d40cfaea3 --- /dev/null +++ b/resources/startupHints/locales/en/css/light.css @@ -0,0 +1,8 @@ +body { + background-color: #ffffff; + color: #000000; +} + +.title { + color: #6682b5; +} diff --git a/resources/startupHints/locales/en/error.html b/resources/startupHints/locales/en/error.html index f998df943..a456d7cdb 100644 --- a/resources/startupHints/locales/en/error.html +++ b/resources/startupHints/locales/en/error.html @@ -1,5 +1,5 @@ - - + + erreur diff --git a/resources/startupHints/locales/fr/1.html b/resources/startupHints/locales/fr/1.html index a497619ff..a9526a6c0 100644 --- a/resources/startupHints/locales/fr/1.html +++ b/resources/startupHints/locales/fr/1.html @@ -1,9 +1,15 @@ - + Trucs et astuces - + + + diff --git a/resources/startupHints/locales/fr/10.html b/resources/startupHints/locales/fr/10.html index 926cd2566..263709d6a 100644 --- a/resources/startupHints/locales/fr/10.html +++ b/resources/startupHints/locales/fr/10.html @@ -1,9 +1,15 @@ - + Applications - + + + diff --git a/resources/startupHints/locales/fr/11.html b/resources/startupHints/locales/fr/11.html index 6aa7a7f1d..701630fdb 100644 --- a/resources/startupHints/locales/fr/11.html +++ b/resources/startupHints/locales/fr/11.html @@ -1,9 +1,15 @@ - + Capture Vidéo - + + + diff --git a/resources/startupHints/locales/fr/12.html b/resources/startupHints/locales/fr/12.html index ed111ba77..eb5bb7035 100644 --- a/resources/startupHints/locales/fr/12.html +++ b/resources/startupHints/locales/fr/12.html @@ -1,9 +1,15 @@ - + Documents favoris - + + + diff --git a/resources/startupHints/locales/fr/2.html b/resources/startupHints/locales/fr/2.html index 81f24e5c0..980d85e65 100644 --- a/resources/startupHints/locales/fr/2.html +++ b/resources/startupHints/locales/fr/2.html @@ -1,9 +1,15 @@ - + Mode Tableau - + + + diff --git a/resources/startupHints/locales/fr/3.html b/resources/startupHints/locales/fr/3.html index 0921ed8e8..848c2c4f3 100644 --- a/resources/startupHints/locales/fr/3.html +++ b/resources/startupHints/locales/fr/3.html @@ -1,9 +1,15 @@ - + Mode Bureau - + + + diff --git a/resources/startupHints/locales/fr/4.html b/resources/startupHints/locales/fr/4.html index cc87807d7..afb0f2906 100644 --- a/resources/startupHints/locales/fr/4.html +++ b/resources/startupHints/locales/fr/4.html @@ -1,9 +1,15 @@ - + Mode Documents - + + + diff --git a/resources/startupHints/locales/fr/5.html b/resources/startupHints/locales/fr/5.html index d379cad55..c0ae7a888 100644 --- a/resources/startupHints/locales/fr/5.html +++ b/resources/startupHints/locales/fr/5.html @@ -1,9 +1,15 @@ - + Mode Documents - + + + diff --git a/resources/startupHints/locales/fr/6.html b/resources/startupHints/locales/fr/6.html index 4a444dec9..a4919cb4c 100644 --- a/resources/startupHints/locales/fr/6.html +++ b/resources/startupHints/locales/fr/6.html @@ -1,9 +1,15 @@ - + Mode Web - + + + diff --git a/resources/startupHints/locales/fr/7.html b/resources/startupHints/locales/fr/7.html index 3e896b291..56fb927c3 100644 --- a/resources/startupHints/locales/fr/7.html +++ b/resources/startupHints/locales/fr/7.html @@ -1,9 +1,15 @@ - + Capture d'écran - + + + diff --git a/resources/startupHints/locales/fr/8.html b/resources/startupHints/locales/fr/8.html index f37dc684b..a9679ead9 100644 --- a/resources/startupHints/locales/fr/8.html +++ b/resources/startupHints/locales/fr/8.html @@ -1,9 +1,15 @@ - + Images - + + + diff --git a/resources/startupHints/locales/fr/9.html b/resources/startupHints/locales/fr/9.html index 6ff5a7c90..d3a501394 100644 --- a/resources/startupHints/locales/fr/9.html +++ b/resources/startupHints/locales/fr/9.html @@ -1,9 +1,15 @@ - + Interactivités - + + + diff --git a/resources/startupHints/locales/fr/css/dark.css b/resources/startupHints/locales/fr/css/dark.css new file mode 100644 index 000000000..34ded372a --- /dev/null +++ b/resources/startupHints/locales/fr/css/dark.css @@ -0,0 +1,8 @@ +body { + background-color: #3a3a3a; + color: #e0e0e0; +} + +.title { + color: #8ba3d7; +} diff --git a/resources/startupHints/locales/fr/css/light.css b/resources/startupHints/locales/fr/css/light.css new file mode 100644 index 000000000..d40cfaea3 --- /dev/null +++ b/resources/startupHints/locales/fr/css/light.css @@ -0,0 +1,8 @@ +body { + background-color: #ffffff; + color: #000000; +} + +.title { + color: #6682b5; +} diff --git a/resources/startupHints/locales/fr/error.html b/resources/startupHints/locales/fr/error.html index f998df943..a456d7cdb 100644 --- a/resources/startupHints/locales/fr/error.html +++ b/resources/startupHints/locales/fr/error.html @@ -1,5 +1,5 @@ - - + + erreur diff --git a/resources/startupHints/locales/hr/1.html b/resources/startupHints/locales/hr/1.html index 71537c1f4..44eed3250 100644 --- a/resources/startupHints/locales/hr/1.html +++ b/resources/startupHints/locales/hr/1.html @@ -1,9 +1,15 @@ - + Savjeti - + + + diff --git a/resources/startupHints/locales/hr/10.html b/resources/startupHints/locales/hr/10.html index 9c63026a8..68cd1afc4 100644 --- a/resources/startupHints/locales/hr/10.html +++ b/resources/startupHints/locales/hr/10.html @@ -1,9 +1,14 @@ - - - + + Programi - + + + diff --git a/resources/startupHints/locales/hr/11.html b/resources/startupHints/locales/hr/11.html index 60b0268fb..a16f22e42 100644 --- a/resources/startupHints/locales/hr/11.html +++ b/resources/startupHints/locales/hr/11.html @@ -1,9 +1,14 @@ - - - + + Snimanje videa - + + + diff --git a/resources/startupHints/locales/hr/12.html b/resources/startupHints/locales/hr/12.html index 73a9de08c..077f10287 100644 --- a/resources/startupHints/locales/hr/12.html +++ b/resources/startupHints/locales/hr/12.html @@ -1,9 +1,14 @@ - - - + + Favoriti - + + + diff --git a/resources/startupHints/locales/hr/2.html b/resources/startupHints/locales/hr/2.html index 1ab997c6e..8fbf1f853 100644 --- a/resources/startupHints/locales/hr/2.html +++ b/resources/startupHints/locales/hr/2.html @@ -1,9 +1,14 @@ - - - + + Modus ploče - + + + diff --git a/resources/startupHints/locales/hr/3.html b/resources/startupHints/locales/hr/3.html index 16da5b6ee..fe94a11f8 100644 --- a/resources/startupHints/locales/hr/3.html +++ b/resources/startupHints/locales/hr/3.html @@ -1,9 +1,14 @@ - - - + + Modus radne površine - + + + diff --git a/resources/startupHints/locales/hr/4.html b/resources/startupHints/locales/hr/4.html index dbafab821..1ec341090 100644 --- a/resources/startupHints/locales/hr/4.html +++ b/resources/startupHints/locales/hr/4.html @@ -1,9 +1,14 @@ - - - + + Modus dokumenata - + + + diff --git a/resources/startupHints/locales/hr/5.html b/resources/startupHints/locales/hr/5.html index 8b6b7161b..8def374ba 100644 --- a/resources/startupHints/locales/hr/5.html +++ b/resources/startupHints/locales/hr/5.html @@ -1,9 +1,14 @@ - - - + + Modus dokumenata - + + + diff --git a/resources/startupHints/locales/hr/6.html b/resources/startupHints/locales/hr/6.html index 49e5fc24a..6bda41029 100644 --- a/resources/startupHints/locales/hr/6.html +++ b/resources/startupHints/locales/hr/6.html @@ -1,9 +1,14 @@ - - - + + Web modus - + + + diff --git a/resources/startupHints/locales/hr/7.html b/resources/startupHints/locales/hr/7.html index 702dc2e45..7a8a99bc8 100644 --- a/resources/startupHints/locales/hr/7.html +++ b/resources/startupHints/locales/hr/7.html @@ -1,9 +1,14 @@ - - - + + Snimanje ekrana - + + + diff --git a/resources/startupHints/locales/hr/8.html b/resources/startupHints/locales/hr/8.html index d1c36c50f..d55ad7908 100644 --- a/resources/startupHints/locales/hr/8.html +++ b/resources/startupHints/locales/hr/8.html @@ -1,9 +1,14 @@ - - - + + Slike - + + + diff --git a/resources/startupHints/locales/hr/9.html b/resources/startupHints/locales/hr/9.html index 03fc2b937..ab8576bcf 100644 --- a/resources/startupHints/locales/hr/9.html +++ b/resources/startupHints/locales/hr/9.html @@ -1,9 +1,14 @@ - - - + + Interaktivnosti - + + + diff --git a/resources/startupHints/locales/hr/css/dark.css b/resources/startupHints/locales/hr/css/dark.css new file mode 100644 index 000000000..34ded372a --- /dev/null +++ b/resources/startupHints/locales/hr/css/dark.css @@ -0,0 +1,8 @@ +body { + background-color: #3a3a3a; + color: #e0e0e0; +} + +.title { + color: #8ba3d7; +} diff --git a/resources/startupHints/locales/hr/css/light.css b/resources/startupHints/locales/hr/css/light.css new file mode 100644 index 000000000..d40cfaea3 --- /dev/null +++ b/resources/startupHints/locales/hr/css/light.css @@ -0,0 +1,8 @@ +body { + background-color: #ffffff; + color: #000000; +} + +.title { + color: #6682b5; +} diff --git a/resources/startupHints/locales/hr/error.html b/resources/startupHints/locales/hr/error.html index 525043180..b5ad0101c 100644 --- a/resources/startupHints/locales/hr/error.html +++ b/resources/startupHints/locales/hr/error.html @@ -1,6 +1,5 @@ - - - + + erreur diff --git a/resources/startupHints/locales/it/1.html b/resources/startupHints/locales/it/1.html index 03a739b0d..54e811ba3 100644 --- a/resources/startupHints/locales/it/1.html +++ b/resources/startupHints/locales/it/1.html @@ -1,9 +1,15 @@ - + Suggerimenti e consigli - + + + diff --git a/resources/startupHints/locales/it/10.html b/resources/startupHints/locales/it/10.html index 3ceabe0b8..dc63883da 100644 --- a/resources/startupHints/locales/it/10.html +++ b/resources/startupHints/locales/it/10.html @@ -1,9 +1,14 @@ - - - + + Applicazioni - + + + diff --git a/resources/startupHints/locales/it/11.html b/resources/startupHints/locales/it/11.html index 86ef8f83b..059441372 100644 --- a/resources/startupHints/locales/it/11.html +++ b/resources/startupHints/locales/it/11.html @@ -1,9 +1,14 @@ - - - + + Registrazione Video - + + + diff --git a/resources/startupHints/locales/it/12.html b/resources/startupHints/locales/it/12.html index 5d621a416..a70c76dd9 100644 --- a/resources/startupHints/locales/it/12.html +++ b/resources/startupHints/locales/it/12.html @@ -1,10 +1,15 @@ - - - + + Documenti Preferiti - - + + + + diff --git a/resources/startupHints/locales/it/2.html b/resources/startupHints/locales/it/2.html index cc5e8b1c6..1536900a7 100644 --- a/resources/startupHints/locales/it/2.html +++ b/resources/startupHints/locales/it/2.html @@ -1,10 +1,15 @@ - - - + + Modalità Lavagna + - + + diff --git a/resources/startupHints/locales/it/3.html b/resources/startupHints/locales/it/3.html index fef4192ba..fd141ba58 100644 --- a/resources/startupHints/locales/it/3.html +++ b/resources/startupHints/locales/it/3.html @@ -1,10 +1,15 @@ - - - + + Modalità Desktop + - + + diff --git a/resources/startupHints/locales/it/4.html b/resources/startupHints/locales/it/4.html index c12820ed1..867d8ec1f 100644 --- a/resources/startupHints/locales/it/4.html +++ b/resources/startupHints/locales/it/4.html @@ -1,10 +1,15 @@ - - - + + Modalità Documenti + - + + diff --git a/resources/startupHints/locales/it/5.html b/resources/startupHints/locales/it/5.html index 145fa7b6d..18b5dc4ec 100644 --- a/resources/startupHints/locales/it/5.html +++ b/resources/startupHints/locales/it/5.html @@ -1,10 +1,16 @@ - + Modalità Documenti + - + + diff --git a/resources/startupHints/locales/it/6.html b/resources/startupHints/locales/it/6.html index 29d400c2b..d9700dbb7 100644 --- a/resources/startupHints/locales/it/6.html +++ b/resources/startupHints/locales/it/6.html @@ -1,9 +1,15 @@ - + Modalità Web - + + + diff --git a/resources/startupHints/locales/it/7.html b/resources/startupHints/locales/it/7.html index f5f9484b7..ad3a67a17 100644 --- a/resources/startupHints/locales/it/7.html +++ b/resources/startupHints/locales/it/7.html @@ -1,10 +1,15 @@ - - - + + Cattura Schermo + - + + diff --git a/resources/startupHints/locales/it/8.html b/resources/startupHints/locales/it/8.html index 5f40e7f21..9f7ddcc66 100644 --- a/resources/startupHints/locales/it/8.html +++ b/resources/startupHints/locales/it/8.html @@ -1,9 +1,14 @@ - - - + + Immagini - + + + diff --git a/resources/startupHints/locales/it/9.html b/resources/startupHints/locales/it/9.html index 62545121c..3a426ea95 100644 --- a/resources/startupHints/locales/it/9.html +++ b/resources/startupHints/locales/it/9.html @@ -1,9 +1,14 @@ - - - + + Interattività - + + + diff --git a/resources/startupHints/locales/it/css/dark.css b/resources/startupHints/locales/it/css/dark.css new file mode 100644 index 000000000..34ded372a --- /dev/null +++ b/resources/startupHints/locales/it/css/dark.css @@ -0,0 +1,8 @@ +body { + background-color: #3a3a3a; + color: #e0e0e0; +} + +.title { + color: #8ba3d7; +} diff --git a/resources/startupHints/locales/it/css/light.css b/resources/startupHints/locales/it/css/light.css new file mode 100644 index 000000000..d40cfaea3 --- /dev/null +++ b/resources/startupHints/locales/it/css/light.css @@ -0,0 +1,8 @@ +body { + background-color: #ffffff; + color: #000000; +} + +.title { + color: #6682b5; +} diff --git a/resources/startupHints/locales/it/error.html b/resources/startupHints/locales/it/error.html index 05ddb6b3a..9c6aa4e39 100644 --- a/resources/startupHints/locales/it/error.html +++ b/resources/startupHints/locales/it/error.html @@ -1,6 +1,5 @@ - - - + + errore diff --git a/resources/style.qss b/resources/style.qss index 92bd8d6b5..3f984fc18 100644 --- a/resources/style.qss +++ b/resources/style.qss @@ -9,24 +9,29 @@ QWidget#UBFeaturesNavigatorWidget, QWidget#PathList, QWidget#UBFeaturesCentralWidget { - background: #EEEEEE; + background: palette(window); border-radius: 10px; - border: 2px solid #999999; + border: 2px solid palette(mid); + color: palette(window-text); } QTextEdit, QLineEdit, QComboBox#DockPaletteWidgetComboBox QAbstractItemView { - selection-background-color: lightgreen; - selection-color: black; + selection-background-color: palette(highlight); + selection-color: palette(highlighted-text); + background-color: palette(base); + color: palette(text); } QWidget#mAdditionalDataContainer { border-radius: 10px; - border: 2px solid #999999; + border: 2px solid palette(mid); + background: palette(window); + color: palette(window-text); } QWidget#UBMediaVideoContainer @@ -38,9 +43,10 @@ QWidget#UBMediaVideoContainer QWidget#UBLibWebView { - background: #EEEEEE; + background: palette(window); border-radius : 10px; - border: 2px solid #999999; + border: 2px solid palette(mid); + color: palette(window-text); } QListView @@ -55,17 +61,19 @@ QWidget#UBFeatureProperties QWebView#SearchEngineView { - background:white; + background: palette(base); + color: palette(text); } QColorDialog { - background: #EEEEEE; + background: palette(window); + color: palette(window-text); } QLabel#DockPaletteWidgetTitle { - color: #FFFFFF; + color: palette(bright-text); font-size : 18px; font-weight:bold; } @@ -73,22 +81,24 @@ QLabel#DockPaletteWidgetTitle QLineEdit#UBTGLineEdit, QLabel#UBTGMediaDropMeLabel { - background: white; - border: 1 solid #999999; + background: palette(base); + color: palette(text); + border: 1 solid palette(mid); border-radius : 10px; padding: 2px; } QComboBox#DockPaletteWidgetComboBox { - background: white; + background: palette(base); + color: palette(text); border-radius : 10px; padding: 2px; } QComboBox#DockPaletteWidgetComboBox:drop-down { - background: white; + background: palette(base); width:1px; height:1px; margin: 9px 5px 0px 0px; @@ -97,8 +107,8 @@ QComboBox#DockPaletteWidgetComboBox:drop-down QComboBox#DockPaletteWidgetComboBox::down-arrow { image:url(:/images/down_arrow.png); - background:#BBBBBB; - border: 2px solid #999999; + background: palette(button); + border: 2px solid palette(mid); height:16px; width:16px; padding: 0px 0px 0px 0px; @@ -108,8 +118,8 @@ QComboBox#DockPaletteWidgetComboBox::down-arrow QPushButton#DockPaletteWidgetButton { - background-color : #DDDDDD; - color : #555555; + background-color : palette(button); + color : palette(button-text); border-radius : 6px; padding : 5px; font-weight : bold; @@ -118,14 +128,15 @@ QPushButton#DockPaletteWidgetButton QTextEdit#TeacherStudentBox { - background: white; - border: 2px solid #999999; + background: palette(base); + color: palette(text); + border: 2px solid palette(mid); border-radius: 10px; } QPushButton#DockPaletteWidgetButton::checked { - background-color: #BBBBBB; + background-color: palette(light); } QScrollBar::vertical @@ -136,9 +147,9 @@ QScrollBar::vertical QScrollBar::handle:vertical { - border: 2px solid #999999; + border: 2px solid palette(mid); border-radius:6px; - background:#BBBBBB; + background: palette(button); min-height:40px; } @@ -146,8 +157,8 @@ QScrollBar::add-line:vertical { image:url(:/images/down_arrow.png); height:16px; - background:#BBBBBB; - border:2px solid #999999; + background: palette(button); + border: 2px solid palette(mid); border-radius:6px; margin: 1px 1px 4px 1px; subcontrol-position:bottom; @@ -158,8 +169,8 @@ QScrollBar::sub-line:vertical { image:url(:/images/up_arrow.png); height:16px; - background:#BBBBBB; - border:2px solid #999999; + background: palette(button); + border: 2px solid palette(mid); border-radius:6px; margin: 2px 1px 1px 1px; subcontrol-position:top; @@ -179,9 +190,9 @@ QScrollBar::horizontal QScrollBar::handle:horizontal { - border: 2px solid #999999; + border: 2px solid palette(mid); border-radius:6px; - background:#BBBBBB; + background: palette(button); min-width:40px; } @@ -189,8 +200,8 @@ QScrollBar::add-line:horizontal { image:url(:/images/right_arrow.png); width:16px; - background:#BBBBBB; - border:2px solid #999999; + background: palette(button); + border: 2px solid palette(mid); border-radius:6px; margin: 1px 1px 1px 4px; subcontrol-position:right; @@ -201,8 +212,8 @@ QScrollBar::sub-line:horizontal { image:url(:/images/left_arrow.png); width:16px; - background:#BBBBBB; - border:2px solid #999999; + background: palette(button); + border: 2px solid palette(mid); border-radius:6px; margin: 1px 2px 1px 1px; subcontrol-position:left; @@ -216,40 +227,40 @@ QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal QSlider::handle::horizontal { - background-color:#EEEEEE; + background-color: palette(button); margin-top:-5px; margin-bottom:-5px; height:20px; width:18px; border-radius:10px; - border:1px solid #555555; + border: 1px solid palette(dark); } QSlider::groove::horizontal { - background-color:#999999; + background-color: palette(mid); height:10px; border-radius:5px; - border:1px solid #555555; + border: 1px solid palette(dark); } QLabel#UBTGEditionDocumentTitle { - color: black; + color: palette(text); font-size : 14px; font-weight:bold; } QLabel#UBTGPresentationDocumentTitle { - color: black; + color: palette(text); font-size : 12px; font-weight:bold; } QLabel#UBTGPageNumberLabel { - color: black; + color: palette(text); font-size : 12px; font-weight:bold; } @@ -257,13 +268,13 @@ QLabel#UBTGPageNumberLabel UBTGAdaptableText#UBTGEditionPageTitle, UBTGAdaptableText#UBTGEditionComment { - color: black; + color: palette(text); font-size : 12px; } UBTGAdaptableText#UBTGPresentationPageTitle { - color: black; + color: palette(text); font-size:16px; font-weight:bold; border : none; @@ -271,19 +282,59 @@ UBTGAdaptableText#UBTGPresentationPageTitle UBTGAdaptableText#UBTGPresentationComment { - color: black; + color: palette(text); font-size:12px; border : none; } QFrame#UBTGSeparator { - background-color: #cccccc; + background-color: palette(mid); } UBTGAdaptableText { - background-color: white; - border:1 solid #999999; + background-color: palette(base); + color: palette(text); + border: 1 solid palette(mid); border-radius : 10px; padding: 2px; } + +/* Features Action Bar and Widgets */ +QWidget#UBFeaturesActionBar { + background: palette(window); + border-radius: 10px; + border: 2px solid palette(mid); +} + +QLineEdit#FeaturesSearchBar { + background-color: palette(base); + color: palette(text); + border-radius: 10px; + padding: 2px; + border: 1px solid palette(mid); +} + +QPushButton#UBFeatureItemButton { + background-color: palette(button); + color: palette(button-text); + border-radius: 6px; + padding: 5px; + font-weight: bold; + font-size: 12px; + border: 1px solid palette(mid); +} + +QLabel#UBFeatureInfoLabel { + color: palette(mid); + font-size: 18px; + font-weight: bold; +} + +QLineEdit[invalid="true"] { + background: #FFB3C8; +} + +QLineEdit[invalid="false"] { + background: palette(base); +} diff --git a/src/api/UBWidgetUniboardAPI.cpp b/src/api/UBWidgetUniboardAPI.cpp index fade7ce31..bffa6e82e 100644 --- a/src/api/UBWidgetUniboardAPI.cpp +++ b/src/api/UBWidgetUniboardAPI.cpp @@ -35,6 +35,7 @@ #include "core/UB.h" #include "core/UBApplication.h" #include "core/UBSettings.h" +#include "core/UBThemeManager.h" #include "document/UBDocument.h" #include "document/UBDocumentProxy.h" @@ -480,6 +481,11 @@ QString UBWidgetUniboardAPI::lang() const return lang; } +bool UBWidgetUniboardAPI::isDarkMode() const +{ + return UBThemeManager::instance()->isDarkMode(); +} + void UBWidgetUniboardAPI::sendFileMetadata(QString metaData) { // Build the QMap of metadata and send it to application diff --git a/src/api/UBWidgetUniboardAPI.h b/src/api/UBWidgetUniboardAPI.h index b4e2df989..e84b1049a 100644 --- a/src/api/UBWidgetUniboardAPI.h +++ b/src/api/UBWidgetUniboardAPI.h @@ -87,6 +87,11 @@ class UBWidgetUniboardAPI : public QObject Q_PROPERTY(QString dropData MEMBER mDropData WRITE setDropData NOTIFY dropDataChanged SCRIPTABLE true) + /** + * Returns true if the application is currently in dark mode + */ + Q_PROPERTY(bool isDarkMode READ isDarkMode NOTIFY themeChanged SCRIPTABLE true) + public: UBWidgetUniboardAPI(std::shared_ptr pScene, UBGraphicsWidgetItem *widget = 0); ~UBWidgetUniboardAPI(); @@ -264,6 +269,7 @@ class UBWidgetUniboardAPI : public QObject signals: void dropDataChanged(const QString& data); + void themeChanged(bool isDark); private slots: void onDownloadFinished(bool pSuccess, sDownloadFileDesc desc, QByteArray pData); @@ -276,6 +282,8 @@ private slots: QString lang() const; + bool isDarkMode() const; + void setDropData(const QString& data); QString getObjDir(); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6bbca8173..7342c4828 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -33,4 +33,6 @@ target_sources(${PROJECT_NAME} PRIVATE UBShortcutManager.h UBTextTools.cpp UBTextTools.h + UBThemeManager.cpp + UBThemeManager.h ) diff --git a/src/core/UBApplication.cpp b/src/core/UBApplication.cpp index fef848639..4ecbf62bf 100644 --- a/src/core/UBApplication.cpp +++ b/src/core/UBApplication.cpp @@ -46,6 +46,7 @@ #include "UBIdleTimer.h" #include "UBApplicationController.h" #include "UBShortcutManager.h" +#include "UBThemeManager.h" #include "board/UBBoardController.h" #include "board/UBDrawingController.h" @@ -143,9 +144,11 @@ UBApplication::UBApplication(const QString &id, int &argc, char **argv) : Single setStyle("fusion"); - QString css = UBFileSystemUtils::readTextFile(UBPlatformUtils::applicationEtcDirectory() + "/"+ qApp->applicationName()+".css"); - if (css.length() > 0) - setStyleSheet(css); + UBThemeManager::instance()->applyUserThemePreference(); + +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, UBThemeManager::instance(), &UBThemeManager::onColorSchemeChanged); +#endif QApplication::setStartDragDistance(8); // default is 4, and is a bit small for tablets @@ -782,3 +785,4 @@ bool UBApplication::isFromWeb(QString url) return res; } + diff --git a/src/core/UBPreferencesController.cpp b/src/core/UBPreferencesController.cpp index ed0e393d8..c78d9fabe 100644 --- a/src/core/UBPreferencesController.cpp +++ b/src/core/UBPreferencesController.cpp @@ -37,6 +37,7 @@ #include "core/UBSetting.h" #include "core/UBApplicationController.h" #include "core/UBDisplayManager.h" +#include "core/UBThemeManager.h" #include "frameworks/UBStringUtils.h" @@ -191,6 +192,11 @@ void UBPreferencesController::wire() }); connect(mPreferencesUI->startModeComboBox, SIGNAL(currentIndexChanged(int)), settings->appStartMode, SLOT(setInt(int))); + connect(mPreferencesUI->themeComboBox, qOverload(&QComboBox::currentIndexChanged), this, [=](int index) { + settings->appThemeMode->setInt(index); + UBThemeManager::instance()->applyUserThemePreference(); + }); + connect(mPreferencesUI->useExternalBrowserCheckBox, SIGNAL(clicked(bool)), settings->webUseExternalBrowser, SLOT(setBool(bool))); connect(mPreferencesUI->displayBrowserPageCheckBox, SIGNAL(clicked(bool)), settings->webShowPageImmediatelyOnMirroredScreen, SLOT(setBool(bool))); @@ -320,6 +326,7 @@ void UBPreferencesController::init() mPreferencesUI->emptyTrashDaysValue->setValue(settings->emptyTrashDaysValue->get().toInt()); mPreferencesUI->startModeComboBox->setCurrentIndex(settings->appStartMode->get().toInt()); + mPreferencesUI->themeComboBox->setCurrentIndex(settings->appThemeMode->get().toInt()); mPreferencesUI->useExternalBrowserCheckBox->setChecked(settings->webUseExternalBrowser->get().toBool()); mPreferencesUI->displayBrowserPageCheckBox->setChecked(settings->webShowPageImmediatelyOnMirroredScreen->get().toBool()); diff --git a/src/core/UBSettings.cpp b/src/core/UBSettings.cpp index a6ebbdceb..d241c7188 100644 --- a/src/core/UBSettings.cpp +++ b/src/core/UBSettings.cpp @@ -247,6 +247,7 @@ void UBSettings::init() appHideCheckForSoftwareUpdate = new UBSetting(this, "App", "HideCheckForSoftwareUpdate", false); appToolBarOrientationVertical = new UBSetting(this, "App", "ToolBarOrientationVertical", false); appPreferredLanguage = new UBSetting(this,"App","PreferredLanguage", ""); + appThemeMode = new UBSetting(this, "App", "ThemeMode", 0); // removed in version 1.7.0 mUserSettings->remove("App/HideSwapDisplayScreens"); diff --git a/src/core/UBSettings.h b/src/core/UBSettings.h index 53a608833..7bbadbe9b 100644 --- a/src/core/UBSettings.h +++ b/src/core/UBSettings.h @@ -263,6 +263,7 @@ class UBSettings : public QObject UBSetting* appHideCheckForSoftwareUpdate; UBSetting* appToolBarOrientationVertical; UBSetting* appPreferredLanguage; + UBSetting* appThemeMode; UBSetting* appRunInWindow; UBSetting* appIsInSoftwareUpdateProcess; diff --git a/src/core/UBThemeManager.cpp b/src/core/UBThemeManager.cpp new file mode 100644 index 000000000..83b08f861 --- /dev/null +++ b/src/core/UBThemeManager.cpp @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) + * + * Copyright (C) 2013 Open Education Foundation + * + * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour + * l'Education Numérique en Afrique (GIP ENA) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + +#include "UBThemeManager.h" +#include "UBApplication.h" +#include "UBSettings.h" +#include "UBApplicationController.h" +#include "frameworks/UBFileSystemUtils.h" +#include "frameworks/UBPlatformUtils.h" +#include "board/UBBoardController.h" +#include "board/UBBoardPaletteManager.h" +#include "gui/UBMainWindow.h" +#include "gui/UBFloatingPalette.h" +#include "gui/UBStartupHintsPalette.h" +#include "desktop/UBDesktopPropertyPalette.h" +#include "desktop/UBDesktopAnnotationController.h" +#include "desktop/UBDesktopPalette.h" + +#include +#include +#include +#include + +#ifdef Q_OS_WIN +#include +#endif + +UBThemeManager* UBThemeManager::sInstance = nullptr; + +UBThemeManager::UBThemeManager() + : QObject(nullptr) + , mIsDarkMode(false) +{ +} + +UBThemeManager::~UBThemeManager() +{ +} + +UBThemeManager* UBThemeManager::instance() +{ + if (!sInstance) + { + sInstance = new UBThemeManager(); + } + return sInstance; +} + +void UBThemeManager::applyUserThemePreference() +{ + int themeMode = UBSettings::settings()->appThemeMode->get().toInt(); + + bool isDarkMode = false; + + if (themeMode == 0) // Auto - detect from system + { +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + // Qt 6.5+: Use the new colorScheme API + Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); + isDarkMode = (colorScheme == Qt::ColorScheme::Dark); + + qDebug() << "Theme detection using Qt 6.5+ API:" << (isDarkMode ? "Dark" : "Light"); +#else + // Fallback for Qt 6.0-6.4: platform-specific detection + #ifdef Q_OS_WIN + // Windows: Check registry for dark mode + QSettings windowsSettings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", QSettings::NativeFormat); + isDarkMode = (windowsSettings.value("AppsUseLightTheme", 1).toInt() == 0); + qDebug() << "Theme detection (Windows registry):" << (isDarkMode ? "Dark" : "Light"); + #elif defined(Q_OS_MACOS) + // macOS: Check system appearance using palette lightness + isDarkMode = (QApplication::palette().color(QPalette::Window).lightness() < 128); + qDebug() << "Theme detection (macOS palette):" << (isDarkMode ? "Dark" : "Light"); + #elif defined(Q_OS_LINUX) + // Linux: Check if current palette suggests dark theme + isDarkMode = (QApplication::palette().color(QPalette::Window).lightness() < 128); + qDebug() << "Theme detection (Linux palette):" << (isDarkMode ? "Dark" : "Light"); + #endif +#endif + } + else if (themeMode == 1) // Light + { + isDarkMode = false; + qDebug() << "Theme: User preference - Light"; + } + else if (themeMode == 2) // Dark + { + isDarkMode = true; + qDebug() << "Theme: User preference - Dark"; + } + + applyTheme(isDarkMode); +} + +void UBThemeManager::applyTheme(bool isDark) +{ + bool hasThemeChanged = (mIsDarkMode != isDark); + mIsDarkMode = isDark; + + if (mIsDarkMode) + { + setupDarkPalette(); + } + else + { + setupLightPalette(); + } + + loadStylesheets(); + + updateWidgets(); + + if (hasThemeChanged) + { + emit themeChanged(mIsDarkMode); + } +} + +void UBThemeManager::setupDarkPalette() +{ + QPalette darkPalette; + + // Base colors + darkPalette.setColor(QPalette::Window, UBTheme::Dark::Window); + darkPalette.setColor(QPalette::WindowText, UBTheme::Dark::WindowText); + darkPalette.setColor(QPalette::Base, UBTheme::Dark::Base); + darkPalette.setColor(QPalette::AlternateBase, UBTheme::Dark::AlternateBase); + darkPalette.setColor(QPalette::ToolTipBase, UBTheme::Dark::ToolTipBase); + darkPalette.setColor(QPalette::ToolTipText, UBTheme::Dark::ToolTipText); + darkPalette.setColor(QPalette::Text, UBTheme::Dark::Text); + darkPalette.setColor(QPalette::Button, UBTheme::Dark::Button); + darkPalette.setColor(QPalette::ButtonText, UBTheme::Dark::ButtonText); + darkPalette.setColor(QPalette::BrightText, UBTheme::Dark::BrightText); + darkPalette.setColor(QPalette::Link, UBTheme::Dark::Link); + darkPalette.setColor(QPalette::Highlight, UBTheme::Dark::Highlight); + darkPalette.setColor(QPalette::HighlightedText, UBTheme::Dark::HighlightedText); + darkPalette.setColor(QPalette::Light, UBTheme::Dark::Light); + darkPalette.setColor(QPalette::Midlight, UBTheme::Dark::Midlight); + darkPalette.setColor(QPalette::Dark, UBTheme::Dark::Dark); + darkPalette.setColor(QPalette::Mid, UBTheme::Dark::Mid); + darkPalette.setColor(QPalette::Shadow, UBTheme::Dark::Shadow); + + // Disabled state colors + darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, UBTheme::Dark::DisabledText); + darkPalette.setColor(QPalette::Disabled, QPalette::Text, UBTheme::Dark::DisabledText); + darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, UBTheme::Dark::DisabledText); + darkPalette.setColor(QPalette::Disabled, QPalette::Base, UBTheme::Dark::DisabledBase); + darkPalette.setColor(QPalette::Disabled, QPalette::Button, UBTheme::Dark::DisabledButton); + + QApplication::setPalette(darkPalette); + + // Update OpenBoard-specific palette colors + UBSettings::paletteColor = UBTheme::Dark::PaletteColor; + UBSettings::opaquePaletteColor = UBTheme::Dark::OpaquePaletteColor; +} + +void UBThemeManager::setupLightPalette() +{ + QPalette lightPalette; + + // Base colors + lightPalette.setColor(QPalette::Window, UBTheme::Light::Window); + lightPalette.setColor(QPalette::WindowText, UBTheme::Light::WindowText); + lightPalette.setColor(QPalette::Base, UBTheme::Light::Base); + lightPalette.setColor(QPalette::AlternateBase, UBTheme::Light::AlternateBase); + lightPalette.setColor(QPalette::ToolTipBase, UBTheme::Light::ToolTipBase); + lightPalette.setColor(QPalette::ToolTipText, UBTheme::Light::ToolTipText); + lightPalette.setColor(QPalette::Text, UBTheme::Light::Text); + lightPalette.setColor(QPalette::Button, UBTheme::Light::Button); + lightPalette.setColor(QPalette::ButtonText, UBTheme::Light::ButtonText); + lightPalette.setColor(QPalette::BrightText, UBTheme::Light::BrightText); + lightPalette.setColor(QPalette::Link, UBTheme::Light::Link); + lightPalette.setColor(QPalette::Highlight, UBTheme::Light::Highlight); + lightPalette.setColor(QPalette::HighlightedText, UBTheme::Light::HighlightedText); + lightPalette.setColor(QPalette::Light, UBTheme::Light::Light); + lightPalette.setColor(QPalette::Midlight, UBTheme::Light::Midlight); + lightPalette.setColor(QPalette::Dark, UBTheme::Light::Dark); + lightPalette.setColor(QPalette::Mid, UBTheme::Light::Mid); + lightPalette.setColor(QPalette::Shadow, UBTheme::Light::Shadow); + + // Disabled state colors + lightPalette.setColor(QPalette::Disabled, QPalette::WindowText, UBTheme::Light::DisabledText); + lightPalette.setColor(QPalette::Disabled, QPalette::Text, UBTheme::Light::DisabledText); + lightPalette.setColor(QPalette::Disabled, QPalette::ButtonText, UBTheme::Light::DisabledText); + lightPalette.setColor(QPalette::Disabled, QPalette::Base, UBTheme::Light::DisabledBase); + lightPalette.setColor(QPalette::Disabled, QPalette::Button, UBTheme::Light::DisabledButton); + + QApplication::setPalette(lightPalette); + + // Update OpenBoard-specific palette colors + UBSettings::paletteColor = UBTheme::Light::PaletteColor; + UBSettings::opaquePaletteColor = UBTheme::Light::OpaquePaletteColor; +} + +void UBThemeManager::loadStylesheets() +{ + QString fullStylesheet; + + // Layer 1: Theme-specific stylesheet (dark or light) + if (mIsDarkMode) + { + QString darkThemeCss = UBFileSystemUtils::readTextFile(":/darkTheme.qss"); + if (darkThemeCss.isEmpty()) { + // Fallback to file system if resource not found (allows user customization) + darkThemeCss = UBFileSystemUtils::readTextFile( + UBPlatformUtils::applicationResourcesDirectory() + "/darkTheme.qss"); + + if (darkThemeCss.isEmpty()) { + qWarning() << "Failed to load dark theme stylesheet from resources and filesystem"; + } + } + fullStylesheet = darkThemeCss; + } else { + QString lightThemeCss = UBFileSystemUtils::readTextFile(":/lightTheme.qss"); + if (lightThemeCss.isEmpty()) { + // Fallback to file system if resource not found (allows user customization) + lightThemeCss = UBFileSystemUtils::readTextFile( + UBPlatformUtils::applicationResourcesDirectory() + "/lightTheme.qss"); + + if (lightThemeCss.isEmpty()) { + qWarning() << "Failed to load light theme stylesheet from resources and filesystem"; + } + } + fullStylesheet = lightThemeCss; + } + + // Layer 2: Embedded style.qss (palette-aware styling for OpenBoard widgets) + QString embeddedStyle = UBFileSystemUtils::readTextFile(":/style.qss"); + if (!embeddedStyle.isEmpty()) { + if (!fullStylesheet.isEmpty()) { + fullStylesheet += "\n"; + } + fullStylesheet += embeddedStyle; + } + + // Layer 3: Standard CSS (user customizable, uses palette() references) + QString css = UBFileSystemUtils::readTextFile( + UBPlatformUtils::applicationEtcDirectory() + "/" + qApp->applicationName() + ".css"); + if (!css.isEmpty()) { + if (!fullStylesheet.isEmpty()) { + fullStylesheet += "\n"; + } + fullStylesheet += css; + } + + // Apply the combined stylesheet once + qApp->setStyleSheet(fullStylesheet); +} + +void UBThemeManager::updateWidgets() +{ + // Update all widgets after a theme change + if (!UBApplication::mainWindow) + { + qDebug() << "Main window not initialized, skipping widget updates"; + return; + } + + // Update all floating palettes + auto floatingPalettes = UBApplication::mainWindow->findChildren(); + for (auto floatingPalette: std::as_const(floatingPalettes)) + { + floatingPalette->setBackgroundBrush(QBrush(UBSettings::paletteColor)); + } + + // Update left and right dock palettes + if (UBApplication::boardController && UBApplication::boardController->paletteManager()) + { + auto paletteManager = UBApplication::boardController->paletteManager(); + + if (paletteManager->leftPalette()) + { + paletteManager->leftPalette()->setBackgroundBrush(QBrush(UBSettings::paletteColor)); + } + + if (paletteManager->rightPalette()) + { + paletteManager->rightPalette()->setBackgroundBrush(QBrush(UBSettings::paletteColor)); + } + } + + // Update desktop left palette and property palettes (pen, marker and eraser sub palettes) + if (UBApplication::applicationController && + UBApplication::applicationController->uninotesController()) + { + auto desktopController = UBApplication::applicationController->uninotesController(); + + if (desktopController->desktopPalette()) + { + desktopController->desktopPalette()->setBackgroundBrush(QBrush(UBSettings::opaquePaletteColor)); + } + + auto desktopPropertyPalettes = desktopController->findChildren(); + + for (auto desktopPropertyPalette : std::as_const(desktopPropertyPalettes)) + { + desktopPropertyPalette->setBackgroundBrush(QBrush(UBSettings::opaquePaletteColor)); + } + } + + // Update startup hints palette background + // (HTML content updates via themeChanged signal → JavaScript listener) + if (UBApplication::boardController && + UBApplication::boardController->paletteManager() && + UBApplication::boardController->paletteManager()->tipsPalette()) + { + auto startupHint = UBApplication::boardController->paletteManager()->tipsPalette(); + + startupHint->setBackgroundBrush(QBrush(UBSettings::paletteColor)); + startupHint->setPalette(QApplication::palette()); + startupHint->update(); + } + + // Force all widgets to update their appearance + // This ensures that all widgets pick up the new palette and stylesheet + QList allWidgets = UBApplication::mainWindow->findChildren(); + for (QWidget* widget : allWidgets) + { + widget->update(); + } + + // Also update the main window itself + UBApplication::mainWindow->update(); + + qDebug() << "Widget updates completed"; +} + +void UBThemeManager::onColorSchemeChanged(Qt::ColorScheme colorScheme) +{ + qDebug() << "System color scheme changed to:" << (colorScheme == Qt::ColorScheme::Dark ? "Dark" : "Light"); + applyTheme(colorScheme == Qt::ColorScheme::Dark); +} diff --git a/src/core/UBThemeManager.h b/src/core/UBThemeManager.h new file mode 100644 index 000000000..6b4e12277 --- /dev/null +++ b/src/core/UBThemeManager.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) + * + * Copyright (C) 2013 Open Education Foundation + * + * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour + * l'Education Numérique en Afrique (GIP ENA) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + +#ifndef UBTHEMEMANAGER_H +#define UBTHEMEMANAGER_H + +#include +#include +#include + +/** + * @brief Manages application theme (dark/light mode) detection and application + * + * This class is responsible for: + * - Detecting system theme preference (Windows, macOS, Linux) + * - Applying appropriate color palettes + * - Loading and managing theme stylesheets + * - Notifying components of theme changes + */ +class UBThemeManager : public QObject +{ + Q_OBJECT + +public: + /** + * @brief Get the singleton instance + */ + static UBThemeManager* instance(); + + /** + * @brief Apply theme based on user preference setting + * + * Respects UBSettings::appThemeMode: 0 = Auto, 1 = Light, 2 = Dark + */ + void applyUserThemePreference(); + + /** + * @brief Apply a specific theme (dark or light) + * @param isDark true for dark mode, false for light mode + */ + void applyTheme(bool isDark); + + /** + * @brief Check if dark mode is currently active + * @return true if dark mode is enabled + */ + bool isDarkMode() const { return mIsDarkMode; } + + /** + * @brief Update all theme-dependent widgets after theme change + * + * This method updates runtime widget instances including: + * - Floating palettes + * - Dock palettes + * - Desktop property palettes + * - Startup hints palette + */ + void updateWidgets(); + +public slots: + /** + * @brief Handle system color scheme changes (Qt 6.5+) + * @param colorScheme The new color scheme from the OS + */ + void onColorSchemeChanged(Qt::ColorScheme colorScheme); + +signals: + /** + * @brief Emitted when the theme changes + * @param isDark true if switched to dark mode + */ + void themeChanged(bool isDark); + +private: + UBThemeManager(); + ~UBThemeManager(); + + UBThemeManager(const UBThemeManager&) = delete; + UBThemeManager& operator=(const UBThemeManager&) = delete; + + /** + * @brief Setup the dark theme palette + */ + void setupDarkPalette(); + + /** + * @brief Setup the light theme palette + */ + void setupLightPalette(); + + /** + * @brief Load and concatenate all stylesheets + */ + void loadStylesheets(); + + static UBThemeManager* sInstance; + bool mIsDarkMode; +}; + +/** + * @brief Theme color constants + */ +namespace UBTheme { + namespace Dark { + const QColor Window(53, 53, 53); + const QColor WindowText(Qt::white); + const QColor Base(42, 42, 42); + const QColor AlternateBase(66, 66, 66); + const QColor ToolTipBase(53, 53, 53); + const QColor ToolTipText(Qt::white); + const QColor Text(Qt::white); + const QColor Button(53, 53, 53); + const QColor ButtonText(Qt::white); + const QColor BrightText(Qt::red); + const QColor Link(42, 130, 218); + const QColor Highlight(42, 130, 218); + const QColor HighlightedText(Qt::black); + const QColor Light(70, 70, 70); + const QColor Midlight(60, 60, 60); + const QColor Dark(35, 35, 35); + const QColor Mid(50, 50, 50); + const QColor Shadow(20, 20, 20); + const QColor DisabledText(127, 127, 127); + const QColor DisabledBase(49, 49, 49); + const QColor DisabledButton(53, 53, 53); + + // OpenBoard-specific palette colors + const QColor PaletteColor(70, 70, 70, 220); + const QColor OpaquePaletteColor(50, 50, 50, 240); + } + + namespace Light { + const QColor Window(240, 240, 240); + const QColor WindowText(Qt::black); + const QColor Base(Qt::white); + const QColor AlternateBase(245, 245, 245); + const QColor ToolTipBase(255, 255, 220); + const QColor ToolTipText(Qt::black); + const QColor Text(Qt::black); + const QColor Button(240, 240, 240); + const QColor ButtonText(Qt::black); + const QColor BrightText(Qt::red); + const QColor Link(0, 0, 255); + const QColor Highlight(0, 120, 215); + const QColor HighlightedText(Qt::white); + const QColor Light(245, 245, 245); + const QColor Midlight(242, 242, 242); + const QColor Dark(160, 160, 160); + const QColor Mid(160, 160, 160); + const QColor Shadow(105, 105, 105); + const QColor DisabledText(120, 120, 120); + const QColor DisabledBase(240, 240, 240); + const QColor DisabledButton(240, 240, 240); + + // OpenBoard-specific palette colors + const QColor PaletteColor(180, 180, 180, 220); + const QColor OpaquePaletteColor(200, 200, 200, 240); + } +} + +#endif // UBTHEMEMANAGER_H diff --git a/src/core/core.pri b/src/core/core.pri index 5732e8bdf..3c10d3419 100644 --- a/src/core/core.pri +++ b/src/core/core.pri @@ -2,6 +2,7 @@ HEADERS += src/core/UB.h \ src/core/UBShortcutManager.h \ src/core/UBApplication.h \ + src/core/UBThemeManager.h \ src/core/UBSettings.h \ src/core/UBSetting.h \ src/core/UBPersistenceManager.h \ @@ -20,6 +21,7 @@ HEADERS += src/core/UB.h \ SOURCES += src/core/main.cpp \ src/core/UBShortcutManager.cpp \ src/core/UBApplication.cpp \ + src/core/UBThemeManager.cpp \ src/core/UBSettings.cpp \ src/core/UBSetting.cpp \ src/core/UBPersistenceManager.cpp \ diff --git a/src/desktop/UBDesktopPropertyPalette.cpp b/src/desktop/UBDesktopPropertyPalette.cpp index 3b520b170..912f48cff 100644 --- a/src/desktop/UBDesktopPropertyPalette.cpp +++ b/src/desktop/UBDesktopPropertyPalette.cpp @@ -35,6 +35,7 @@ #include "gui/UBMainWindow.h" #include "gui/UBToolbarButtonGroup.h" #include "gui/UBRightPalette.h" +#include "core/UBThemeManager.h" #include "core/memcheck.h" @@ -42,7 +43,8 @@ UBDesktopPropertyPalette::UBDesktopPropertyPalette(QWidget *parent, UBRightPalet :UBPropertyPalette(Qt::Horizontal, parent) ,rightPalette(_rightPalette) { - setStyleSheet("QWidget { background : qlineargradient(x1:0, y1:0.49, x2:0, y2:0.5, stop:0 #c3c3c3, stop:1 #b4b4b4);}"); + updateStyleSheet(); + connect(UBThemeManager::instance(), &UBThemeManager::themeChanged, this, &UBDesktopPropertyPalette::updateStyleSheet); } int UBDesktopPropertyPalette::getParentRightOffset() @@ -50,6 +52,18 @@ int UBDesktopPropertyPalette::getParentRightOffset() return rightPalette->width(); } +void UBDesktopPropertyPalette::updateStyleSheet() +{ + if (UBThemeManager::instance()->isDarkMode()) + { + setStyleSheet("QWidget { background: qlineargradient(x1:0, y1:0.49, x2:0, y2:0.5, stop:0 #505050, stop:1 #3a3a3a); }"); + } + else + { + setStyleSheet("QWidget { background: qlineargradient(x1:0, y1:0.49, x2:0, y2:0.5, stop:0 #c3c3c3, stop:1 #b4b4b4); }"); + } +} + UBDesktopPenPalette::UBDesktopPenPalette(QWidget *parent, UBRightPalette* rightPalette, QString objectNamePrefix) : UBDesktopPropertyPalette(parent, rightPalette) diff --git a/src/desktop/UBDesktopPropertyPalette.h b/src/desktop/UBDesktopPropertyPalette.h index 62652ca06..455f90736 100644 --- a/src/desktop/UBDesktopPropertyPalette.h +++ b/src/desktop/UBDesktopPropertyPalette.h @@ -45,6 +45,7 @@ class UBDesktopPropertyPalette : public UBPropertyPalette UBDesktopPropertyPalette(QWidget *parent, UBRightPalette* _rightPalette); private: UBRightPalette* rightPalette; + void updateStyleSheet(); protected: virtual int getParentRightOffset(); }; diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index ca2007af6..c2832a9ff 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -513,12 +513,14 @@ QVariant UBDocumentTreeModel::data(const QModelIndex &index, int role) const } if(role == Qt::BackgroundRole){ - if (isConstant(index)) { - return QBrush(0xD9DFEB); + if (isConstant(index)) + { + return QBrush(QApplication::palette().color(QPalette::AlternateBase)); } - if (mHighLighted.isValid() && index == mHighLighted) { - return QBrush(0x6682B5); + if (mHighLighted.isValid() && index == mHighLighted) + { + return QBrush(QApplication::palette().color(QPalette::Highlight)); } } @@ -564,7 +566,7 @@ QVariant UBDocumentTreeModel::data(const QModelIndex &index, int role) const break; case (Qt::ForegroundRole) : if (isConstant(index)) { - return QColor(Qt::darkGray); + return QColor(QApplication::palette().color(QPalette::WindowText)); } break; } diff --git a/src/gui/UBDockPalette.cpp b/src/gui/UBDockPalette.cpp index cc37b5de8..a1bc3dc74 100644 --- a/src/gui/UBDockPalette.cpp +++ b/src/gui/UBDockPalette.cpp @@ -545,6 +545,14 @@ void UBDockPalette::assignParent(QWidget *widget) { setParent(widget); mTabPalette->setParent(widget); + + // Update size constraints from new parent to avoid an issue in dark mode where the library dock palette would no longer be correctly sized + if (widget) + { + setMinimumHeight(widget->height()); + setMaximumHeight(widget->height()); + resize(width(), widget->height()); + } } void UBDockPalette::setVisible(bool visible) { diff --git a/src/gui/UBFeaturesActionBar.cpp b/src/gui/UBFeaturesActionBar.cpp index 6f450a0a9..e9b9969ca 100644 --- a/src/gui/UBFeaturesActionBar.cpp +++ b/src/gui/UBFeaturesActionBar.cpp @@ -54,13 +54,12 @@ UBFeaturesActionBar::UBFeaturesActionBar( UBFeaturesController *controller, QWid , mpNewFolderBtn(NULL) { setObjectName(name); - setStyleSheet(QString("background: #EEEEEE; border-radius : 10px; border : 2px solid #999999;")); setAcceptDrops(true); mButtonGroup = new QButtonGroup(this); mSearchBar = new QLineEdit(this); - mSearchBar->setStyleSheet(QString("background-color:white; border-radius : 10px; padding : 2px;")); + mSearchBar->setObjectName("FeaturesSearchBar"); mLayout = new QHBoxLayout(); setLayout(mLayout); @@ -331,7 +330,7 @@ UBActionButton::UBActionButton(QWidget *parent, QAction* action, const char *nam setDefaultAction(action); setIconSize(QSize(BUTTON_SIZE, BUTTON_SIZE)); setToolButtonStyle(Qt::ToolButtonIconOnly); - setStyleSheet(QString("QToolButton {color: white; font-weight: bold; font-family: Arial; background-color: transparent; border: none}")); + setStyleSheet(QString("QToolButton {color: palette(button-text); font-weight: bold; font-family: Arial; background-color: transparent; border: none}")); setFocusPolicy(Qt::NoFocus); } diff --git a/src/gui/UBFeaturesWidget.cpp b/src/gui/UBFeaturesWidget.cpp index 40ad99846..846c4e593 100644 --- a/src/gui/UBFeaturesWidget.cpp +++ b/src/gui/UBFeaturesWidget.cpp @@ -724,11 +724,15 @@ void UBFeaturesNewFolderDialog::reactOnTextChanged(const QString &pStr) { if (validString(pStr)) { acceptButton->setEnabled(true); - mLineEdit->setStyleSheet("background:white;"); + mLineEdit->setProperty("invalid", false); } else { acceptButton->setEnabled(false); - mLineEdit->setStyleSheet("background:#FFB3C8;"); + mLineEdit->setProperty("invalid", true); } + + // Force style update after property change + mLineEdit->style()->unpolish(mLineEdit); + mLineEdit->style()->polish(mLineEdit); } UBFeaturesProgressInfo::UBFeaturesProgressInfo(QWidget *parent) : @@ -910,7 +914,7 @@ UBFeatureProperties::UBFeatureProperties( QWidget *parent, const char *name ) : mpButtonLayout->addStretch(1); mpObjInfoLabel = new QLabel(tr("Object informations")); - mpObjInfoLabel->setStyleSheet(QString("color: #888888; font-size : 18px; font-weight:bold;")); + mpObjInfoLabel->setObjectName("UBFeatureInfoLabel"); mpLayout->addWidget(mpObjInfoLabel, 0); mpObjInfos = new QTreeWidget(this); @@ -919,7 +923,6 @@ UBFeatureProperties::UBFeatureProperties( QWidget *parent, const char *name ) : mpObjInfos->setAlternatingRowColors(true); mpObjInfos->setRootIsDecorated(false); mpObjInfos->setObjectName("DockPaletteWidgetBox"); - mpObjInfos->setStyleSheet("background:white;"); mpLayout->addWidget(mpObjInfos, 1); mpLayout->setContentsMargins(0, 0, 0, 0); @@ -1112,7 +1115,6 @@ void UBFeatureProperties::onSetAsBackground() UBFeatureItemButton::UBFeatureItemButton(QWidget *parent, const char *name):QPushButton(parent) { setObjectName(name); - setStyleSheet(QString("background-color : #DDDDDD; color : #555555; border-radius : 6px; padding : 5px; font-weight : bold; font-size : 12px;")); } UBFeatureItemButton::~UBFeatureItemButton() diff --git a/src/gui/UBFloatingPalette.cpp b/src/gui/UBFloatingPalette.cpp index d5381a7f9..dd3baacff 100644 --- a/src/gui/UBFloatingPalette.cpp +++ b/src/gui/UBFloatingPalette.cpp @@ -276,7 +276,8 @@ void UBFloatingPalette::paintEvent(QPaintEvent *) if(mbGrip) { - painter.setBrush(QBrush(QColor(170, 170 ,170))); + QColor borderColor = palette().color(QPalette::Mid); + painter.setBrush(QBrush(borderColor)); QPainterPath borderPath; borderPath.addRoundedRect(0, 0, width(), height(), radius(), radius()); borderPath.addRoundedRect(border(), border(), width() - 2 * border(), height() - 2 * border(), radius(), radius()); diff --git a/src/gui/UBMainWindow.cpp b/src/gui/UBMainWindow.cpp index bbfc2aeb6..0fe3015e8 100644 --- a/src/gui/UBMainWindow.cpp +++ b/src/gui/UBMainWindow.cpp @@ -57,11 +57,6 @@ UBMainWindow::UBMainWindow(QWidget *parent, Qt::WindowFlags flags) mpDownloadWidget = new UBDownloadWidget(); mpDownloadWidget->setWindowModality(Qt::ApplicationModal); - //Setting tooltip colors staticly, since they look not quite well on different color themes - QPalette toolTipPalette; - toolTipPalette.setColor(QPalette::ToolTipBase, QColor("#FFFFDC")); - toolTipPalette.setColor(QPalette::ToolTipText, Qt::black); - QToolTip::setPalette(toolTipPalette); QWidget* centralWidget = new QWidget(this); mStackedLayout = new QStackedLayout(centralWidget); diff --git a/src/gui/UBStartupHintsPalette.cpp b/src/gui/UBStartupHintsPalette.cpp index e4da13f46..23876345e 100644 --- a/src/gui/UBStartupHintsPalette.cpp +++ b/src/gui/UBStartupHintsPalette.cpp @@ -35,6 +35,7 @@ #include #include "UBStartupHintsPalette.h" #include "core/UBApplication.h" +#include "core/UBThemeManager.h" #include "web/UBWebController.h" #include "globals/UBGlobals.h" @@ -49,6 +50,7 @@ UBStartupHintsPalette::UBStartupHintsPalette(QWidget *parent) : { setObjectName("UBStartupHintsPalette"); setFixedSize(800,600); + mLayout = new QVBoxLayout(); mLayout->setContentsMargins(10,28,10,10); setLayout(mLayout); @@ -67,6 +69,9 @@ UBStartupHintsPalette::UBStartupHintsPalette(QWidget *parent) : mShowNextTime = new QCheckBox(tr("Visible next time"),this); mShowNextTime->setChecked(UBSettings::settings()->appStartupHintsEnabled->get().toBool()); connect(mShowNextTime,SIGNAL(stateChanged(int)),this,SLOT(onShowNextTimeStateChanged(int))); + + connect(UBThemeManager::instance(), &UBThemeManager::themeChanged, mpSankoreAPI, &UBWidgetUniboardAPI::themeChanged); + mButtonLayout->addStretch(); mButtonLayout->addWidget(mShowNextTime); hide(); From 416a71d35d4cccc6361afe9b1d31a8d2f370a85c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Mon, 17 Nov 2025 09:42:02 +0100 Subject: [PATCH 069/133] remove extra semicolon Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- resources/darkTheme.qss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/darkTheme.qss b/resources/darkTheme.qss index 040facc38..830b5ecf3 100644 --- a/resources/darkTheme.qss +++ b/resources/darkTheme.qss @@ -611,7 +611,7 @@ QToolButton#desktop-ubButtonGroupRight { background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #505050, stop: 1 #3a3a3a); color: #ffffff; - border-radius: 0px; /* Reset the global QToolButton border-radius */; + border-radius: 0px; /* Reset the global QToolButton border-radius */ border-left: none; border-right: none; } From c7809d9c6d8bea574259af9f07379436fa4de7a9 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 3 Aug 2025 15:50:51 +0200 Subject: [PATCH 070/133] fix: terminate podcast on program exit - when OpenBoard is closed while a podcast is running the application is hanging waiting for a thread to finish - cleanly terminate the podcast recording before closing the application Signed-off-by: letsfindaway --- src/podcast/UBPodcastController.cpp | 12 ++++++++---- src/podcast/ffmpeg/UBFFmpegVideoEncoder.cpp | 9 ++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/podcast/UBPodcastController.cpp b/src/podcast/UBPodcastController.cpp index 442972898..6a56fc71e 100644 --- a/src/podcast/UBPodcastController.cpp +++ b/src/podcast/UBPodcastController.cpp @@ -110,15 +110,19 @@ UBPodcastController::UBPodcastController(QObject* pParent) connect(UBApplication::webController, SIGNAL(activeWebPageChanged(WebView*)), this, SLOT(webActiveWebPageChanged(WebView*))); - connect(UBApplication::app(), SIGNAL(lastWindowClosed()), - this, SLOT(applicationAboutToQuit())); - + connect(UBApplication::mainWindow, &UBMainWindow::closeEvent_Signal, this, &UBPodcastController::applicationAboutToQuit); } UBPodcastController::~UBPodcastController() { - // NOOP + QElapsedTimer elapsed; + elapsed.start(); + + while (mRecordingState != Stopped && elapsed.elapsed() < 1000) + { + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); + } } diff --git a/src/podcast/ffmpeg/UBFFmpegVideoEncoder.cpp b/src/podcast/ffmpeg/UBFFmpegVideoEncoder.cpp index 24451f27a..0d43d5dbc 100644 --- a/src/podcast/ffmpeg/UBFFmpegVideoEncoder.cpp +++ b/src/podcast/ffmpeg/UBFFmpegVideoEncoder.cpp @@ -270,10 +270,17 @@ UBFFmpegVideoEncoder::UBFFmpegVideoEncoder(QObject* parent) UBFFmpegVideoEncoder::~UBFFmpegVideoEncoder() { if (mVideoWorker) - delete mVideoWorker; + { + UBFFmpegVideoEncoder::stop(); + mVideoWorker->deleteLater(); + } if (mVideoEncoderThread) + { + mVideoEncoderThread->quit(); + mVideoEncoderThread->wait(); delete mVideoEncoderThread; + } if (mAudioInput) delete mAudioInput; From 0beaa9c088728cd51928cedad4847f4ccd48cd2a Mon Sep 17 00:00:00 2001 From: Vekhir Date: Mon, 8 Dec 2025 00:07:19 +0100 Subject: [PATCH 071/133] Explicit cast to string_view Poppler 25.12 allows string_view and char*. QByteArray can be converted to both, so choose one explicitly --- src/pdf/XPDFRenderer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pdf/XPDFRenderer.cpp b/src/pdf/XPDFRenderer.cpp index e8eb1c64d..23b76a9aa 100644 --- a/src/pdf/XPDFRenderer.cpp +++ b/src/pdf/XPDFRenderer.cpp @@ -61,7 +61,9 @@ XPDFRenderer::XPDFRenderer(const QString &filename, bool importingFile) #endif globalParams->setupBaseFonts(QFile::encodeName(UBPlatformUtils::applicationResourcesDirectory() + "/" + "fonts").data()); } -#if POPPLER_VERSION_MAJOR > 22 || (POPPLER_VERSION_MAJOR == 22 && POPPLER_VERSION_MINOR >= 3) +#if POPPLER_VERSION_MAJOR > 25 || (POPPLER_VERSION_MAJOR == 25 && POPPLER_VERSION_MINOR >= 12) + mDocument = new PDFDoc(std::make_unique(static_cast(filename.toLocal8Bit()))); +#elif POPPLER_VERSION_MAJOR > 22 || (POPPLER_VERSION_MAJOR == 22 && POPPLER_VERSION_MINOR >= 3) mDocument = new PDFDoc(std::make_unique(filename.toLocal8Bit())); #else mDocument = new PDFDoc(new GooString(filename.toLocal8Bit()), 0, 0, 0); // the filename GString is deleted on PDFDoc desctruction From 4a5332a8e839fdfaf35a3876404d6047ed462baa Mon Sep 17 00:00:00 2001 From: Vekhir Date: Wed, 24 Dec 2025 23:53:13 +0100 Subject: [PATCH 072/133] Fix Qt 6.11 warning --- src/podcast/ffmpeg/UBMicrophoneInput.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/podcast/ffmpeg/UBMicrophoneInput.cpp b/src/podcast/ffmpeg/UBMicrophoneInput.cpp index 25b485ba9..026120db8 100644 --- a/src/podcast/ffmpeg/UBMicrophoneInput.cpp +++ b/src/podcast/ffmpeg/UBMicrophoneInput.cpp @@ -291,6 +291,11 @@ void UBMicrophoneInput::onAudioInputStateChanged(QAudio::State state) } break; +#if (QT_VERSION >= QT_VERSION_CHECK(6, 11, 0)) + case QAudio::IdleState: + qWarning() << "Audio buffer full. Further input might not get processed."; + break; +#endif // handle other states? default: @@ -385,8 +390,10 @@ QString UBMicrophoneInput::getErrorString(QAudio::Error errorCode) case QAudio::IOError : return "Error reading from audio device"; +#if (QT_VERSION < QT_VERSION_CHECK(6, 11, 0)) case QAudio::UnderrunError : return "Underrun error"; +#endif case QAudio::FatalError : return "Fatal error; audio device unusable"; From a58fd2ff965ee3a3163a39c7ad7f768bd6225eeb Mon Sep 17 00:00:00 2001 From: Hussain Ali <64174033+hussainalihussain@users.noreply.github.com> Date: Sat, 10 Jan 2026 18:16:17 +0500 Subject: [PATCH 073/133] [Bug] Text typo in "Hints and tips" in step 11 solved [Bug] Text typo in "Hints and tips" in step 11 solved Solved [this issue](https://github.com/OpenBoard-org/OpenBoard/issues/1395) --- resources/startupHints/locales/en/11.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/startupHints/locales/en/11.html b/resources/startupHints/locales/en/11.html index 769f4ac1c..c68c5a179 100644 --- a/resources/startupHints/locales/en/11.html +++ b/resources/startupHints/locales/en/11.html @@ -21,7 +21,7 @@

Record your class session

You can open this tool like this :

-

You'll see the folowwing interface appear at the bottom right of the whiteboard :

+

You'll see the following interface appear at the bottom right of the whiteboard :

Click on the red button to start recording.

@@ -37,3 +37,4 @@

Record your class session

+ From 2ddb18c3f6209ff23f638f5a6d86c946e039dfa7 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 3 Aug 2025 11:11:53 +0200 Subject: [PATCH 074/133] feat: add DesktopPortal and PipeWire sink - add UBDesktopPortal for Screenshot and ScreenCast - save ScreenCast restore token in user settings - invalidate restore token when screen configuration changes - add UBPipewireSink to extract images from stream - add dependency to libpipewire-0.3 - update project files Signed-off-by: letsfindaway --- CMakeLists.txt | 1 + cmake/DependencyPipewire.cmake | 12 + src/frameworks/CMakeLists.txt | 4 + src/frameworks/UBDesktopPortal.cpp | 377 +++++++++++++++++++++++++++++ src/frameworks/UBDesktopPortal.h | 77 ++++++ src/frameworks/UBPipewireSink.cpp | 283 ++++++++++++++++++++++ src/frameworks/UBPipewireSink.h | 58 +++++ src/frameworks/frameworks.pri | 20 +- 8 files changed, 821 insertions(+), 11 deletions(-) create mode 100644 cmake/DependencyPipewire.cmake create mode 100644 src/frameworks/UBDesktopPortal.cpp create mode 100644 src/frameworks/UBDesktopPortal.h create mode 100644 src/frameworks/UBPipewireSink.cpp create mode 100644 src/frameworks/UBPipewireSink.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d87fcaee..196e49cb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,6 +113,7 @@ include(cmake/DependencyPoppler.cmake) include(cmake/DependencyZlib.cmake) include(cmake/DependencyQuaZip.cmake) include(cmake/DependencyFFmpeg.cmake) +include(cmake/DependencyPipewire.cmake) include(cmake/DependencyX11.cmake) # add source path to include directories diff --git a/cmake/DependencyPipewire.cmake b/cmake/DependencyPipewire.cmake new file mode 100644 index 000000000..40485c28f --- /dev/null +++ b/cmake/DependencyPipewire.cmake @@ -0,0 +1,12 @@ +# Find Pipewire +# +# Pipewire only supports PkgConfig + +find_package(PkgConfig REQUIRED) +pkg_check_modules(Pipewire REQUIRED IMPORTED_TARGET libpipewire-0.3) + +if (Pipewire_FOUND) + target_link_libraries(${PROJECT_NAME} + PkgConfig::Pipewire + ) +endif() diff --git a/src/frameworks/CMakeLists.txt b/src/frameworks/CMakeLists.txt index 368ef3b34..1b12387e2 100644 --- a/src/frameworks/CMakeLists.txt +++ b/src/frameworks/CMakeLists.txt @@ -23,6 +23,10 @@ target_sources(openboard PRIVATE if(CMAKE_SYSTEM_NAME STREQUAL Linux) target_sources(openboard PRIVATE + UBDesktopPortal.cpp + UBDesktopPortal.h + UBPipewireSink.cpp + UBPipewireSink.h UBPlatformUtils_linux.cpp ) endif() diff --git a/src/frameworks/UBDesktopPortal.cpp b/src/frameworks/UBDesktopPortal.cpp new file mode 100644 index 000000000..8188e122e --- /dev/null +++ b/src/frameworks/UBDesktopPortal.cpp @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + +#include "UBDesktopPortal.h" + +#include +#include +#include +#include + +#include "board/UBBoardView.h" +#include "core/UBApplication.h" +#include "core/UBApplicationController.h" +#include "core/UBSettings.h" +#include "desktop/UBDesktopAnnotationController.h" + +enum : uint { MONITOR = 1, WINDOW = 2, VIRTUAL = 4 } SourceType; +enum : uint { HIDDEN = 1, EMBEDDED = 2, METADATA = 4 } CursorMode; +enum : uint { TRANSIENT = 0, APPLICATION = 1, PERSISTENT = 2 } PersistMode; + +Q_DECLARE_METATYPE(UBDesktopPortal::Stream) +Q_DECLARE_METATYPE(UBDesktopPortal::Streams) + +const QDBusArgument &operator >> (const QDBusArgument &arg, UBDesktopPortal::Stream &stream) +{ + arg.beginStructure(); + arg >> stream.node_id; + + arg.beginMap(); + + while (!arg.atEnd()) + { + QString key; + QVariant value; + arg.beginMapEntry(); + arg >> key >> value; + arg.endMapEntry(); + stream.map.insert(key, value); + } + + arg.endMap(); + arg.endStructure(); + + return arg; +} + +UBDesktopPortal::UBDesktopPortal(QObject* parent) + : QObject{parent} +{ +} + +UBDesktopPortal::~UBDesktopPortal() +{ + if (mScreencastPortal) + { + delete mScreencastPortal; + } +} + +void UBDesktopPortal::grabScreen(QScreen* screen, const QRect& rect) +{ + mScreenRect = screen->geometry(); + + if (!rect.isNull()) + { + mScreenRect = rect.translated(mScreenRect.topLeft()); + } + + QDBusInterface screenshotPortal("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop", "org.freedesktop.portal.Screenshot"); + + if (screenshotPortal.isValid()) + { + QMap options; + options["handle_token"] = createRequestToken(); + QDBusReply reply = screenshotPortal.call("Screenshot", "", options); + QDBusObjectPath objectPath = reply.value(); + QString path = objectPath.path(); + QDBusConnection::sessionBus().connect( + "", + path, + "org.freedesktop.portal.Request", + "Response", + "ua{sv}", + this, + SLOT(handleScreenshotResponse(uint,QMap))); + } + else + { + qDebug() << "No valid screenshot portal"; + emit screenGrabbed(QPixmap{}); + } +} + +void UBDesktopPortal::startScreenCast(bool withCursor) +{ + mWithCursor = withCursor; + + QDBusInterface* portal = screencastPortal(); + + if (!portal) + { + return; + } + + // Create ScreenCast session + QString requestToken = createRequestToken(); + QMap options; + options["session_handle_token"] = createSessionToken(); + options["handle_token"] = requestToken; + + QDBusConnection::sessionBus().connect("", mRequestPath + requestToken, "org.freedesktop.portal.Request", "Response", "ua{sv}", this, + SLOT(handleCreateSessionResponse(uint,QMap))); + + const QDBusReply reply = portal->call("CreateSession", options); + + if (!reply.isValid()) + { + qWarning() << "Couldn't get reply to ScreenCast/CreateSession"; + qWarning() << "Error: " << reply.error().message(); + emit screenCastAborted(); + return; + } +} + +void UBDesktopPortal::stopScreenCast() +{ + if (mSession.isEmpty()) + { + return; + } + + QDBusInterface portal("org.freedesktop.portal.Desktop", mSession, "org.freedesktop.portal.Session"); + + if (portal.isValid()) + { + const QDBusReply reply = portal.call("Close"); + + if (!reply.isValid()) + { + qWarning() << "Couldn't get reply to ScreenCast/Close"; + qWarning() << "Error: " << reply.error().message(); + } + } + + mSession.clear(); +} + +void UBDesktopPortal::handleScreenshotResponse(uint code, const QMap& results) +{ + QUrl uri(results["uri"].toUrl()); + QFile file(uri.toLocalFile()); + + if (!file.exists()) + { + qDebug() << "Screenshot image file does not exist"; + emit screenGrabbed(QPixmap{}); + return; + } + + QPixmap pixmap{file.fileName()}; + file.remove(); + + // cut requested screen + QPixmap screenshot = pixmap.copy(mScreenRect); + + emit screenGrabbed(screenshot); +} + +void UBDesktopPortal::handleCreateSessionResponse(uint response, const QVariantMap& results) +{ + if (response != 0) + { + qWarning() << "Failed to create session: " << response << results; + emit screenCastAborted(); + return; + } + + mSession = results.value("session_handle").toString(); + + QDBusInterface* portal = screencastPortal(); + + if (!portal) + { + return; + } + + // Select sources + QString requestToken = createRequestToken(); + QMap options; + options["multiple"] = false; + options["types"] = MONITOR; + options["cursor_mode"] = mWithCursor ? EMBEDDED : HIDDEN; + options["handle_token"] = requestToken; + options["persist_mode"] = PERSISTENT; // restore token valid across application restart + + auto restoreToken = UBSettings::settings()->value("App/ScreenCastRestoreToken"); + + if (restoreToken.isValid()) + { + options["restore_token"] = restoreToken; + } + + // connect before call + QDBusConnection::sessionBus().connect("", mRequestPath + requestToken, "org.freedesktop.portal.Request", "Response", "ua{sv}", this, + SLOT(handleSelectSourcesResponse(uint,QMap))); + + const QDBusReply reply = portal->call("SelectSources", QDBusObjectPath(mSession), options); + + if (!reply.isValid()) + { + qWarning() << "Couldn't get reply to ScreenCast/SelectSources"; + qWarning() << "Error: " << reply.error().message(); + emit screenCastAborted(); + return; + } +} + +void UBDesktopPortal::handleSelectSourcesResponse(uint response, const QVariantMap& results) +{ + Q_UNUSED(results); + + if (response != 0) + { + qWarning() << "Failed to select sources: " << response; + emit screenCastAborted(); + return; + } + + QDBusInterface* portal = screencastPortal(); + + if (!portal) + { + return; + } + + // Start ScreenCast + QString requestToken = createRequestToken(); + QMap options; + options["handle_token"] = requestToken; + + QDBusConnection::sessionBus().connect("", mRequestPath + requestToken, "org.freedesktop.portal.Request", "Response", "ua{sv}", this, + SLOT(handleStartResponse(uint,QMap))); + + const QDBusReply reply = portal->call("Start", QDBusObjectPath(mSession), "", options); + + if (!reply.isValid()) + { + qWarning() << "Couldn't get reply to ScreenCast/Start"; + qWarning() << "Error: " << reply.error().message(); + emit screenCastAborted(); + return; + } + + // Hide annotation drawing view in desktop mode so that portal dialog is topmost + showGlassPane(false); +} + +void UBDesktopPortal::handleStartResponse(uint response, const QVariantMap& results) +{ + Q_UNUSED(results); + + // Show annotation drawing view in desktop mode after portal dialog was closed + showGlassPane(true); + + if (response != 0) + { + // The system Desktop dialog was canceled + qDebug() << "Failed to start or cancel dialog: " << response; + emit screenCastAborted(); + return; + } + + // save restore token + UBSettings::settings()->setValue("App/ScreenCastRestoreToken", results.value("restore_token")); + + // invalidate token when screen configuration changes + static bool connected{false}; + + if (!connected) + { + connected = true; + // don't use the four argument version of connect as this will be disconnected + // when the context object is destroyed + connect(UBSettings::settings()->appScreenList, &UBSetting::changed, [](){ + UBSettings::settings()->setValue("App/ScreenCastRestoreToken", {}); + }); + } + + const Streams streams = qdbus_cast(results.value("streams")); + const Stream stream = streams.last(); + + QDBusInterface* portal = screencastPortal(); + + if (!portal) + { + return; + } + + // Open PipeWire Remote + QMap options; + const QDBusReply reply = portal->call("OpenPipeWireRemote", QDBusObjectPath(mSession), options); + + if (!reply.isValid()) + { + qWarning() << "Couldn't get reply to ScreenCast/OpenPipeWireRemote"; + qWarning() << "Error: " << reply.error().message(); + emit screenCastAborted(); + return; + } + + const int fd = reply.value().fileDescriptor(); + emit streamStarted(fd, stream.node_id); +} + +QDBusInterface* UBDesktopPortal::screencastPortal() +{ + if (!mScreencastPortal) + { + mScreencastPortal = new QDBusInterface("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop", + "org.freedesktop.portal.ScreenCast"); + mScreencastPortal->setParent(this); + + mRequestPath = "/org/freedesktop/portal/desktop/request/" + mScreencastPortal->connection().baseService().remove(0, 1).replace('.', '_') + "/"; + qDebug() << "request path" << mRequestPath; + } + + if (mScreencastPortal->isValid()) + { + return mScreencastPortal; + } + + emit screenCastAborted(); + return nullptr; +} + +QString UBDesktopPortal::createSessionToken() const +{ + static int sessionTokenCounter = 0; + + sessionTokenCounter += 1; + return QString("obsess%1").arg(sessionTokenCounter); +} + +QString UBDesktopPortal::createRequestToken() const +{ + static int requestTokenCounter = 0; + + requestTokenCounter += 1; + return QString("obreq%1").arg(requestTokenCounter); +} + +void UBDesktopPortal::showGlassPane(bool show) const +{ + if (UBApplication::applicationController->isShowingDesktop()) + { + UBApplication::applicationController->uninotesController()->drawingView()->setVisible(show); + } +} diff --git a/src/frameworks/UBDesktopPortal.h b/src/frameworks/UBDesktopPortal.h new file mode 100644 index 000000000..57d4e620d --- /dev/null +++ b/src/frameworks/UBDesktopPortal.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + +#pragma once + +#include +#include +#include + +// forward +class QDBusInterface; +class QScreen; + +class UBDesktopPortal : public QObject +{ + Q_OBJECT + +public: + typedef struct + { + uint node_id; + QVariantMap map; + } Stream; + typedef QList Streams; + + explicit UBDesktopPortal(QObject* parent = nullptr); + virtual ~UBDesktopPortal(); + + void grabScreen(QScreen* screen, const QRect& rect = {}); + +public slots: + void startScreenCast(bool withCursor); + void stopScreenCast(); + +signals: + void screenGrabbed(QPixmap pixmap); + void streamStarted(int fd, int nodeId); + void screenCastAborted(); + +private slots: + void handleScreenshotResponse(uint code, const QMap& results); + void handleCreateSessionResponse(uint response, const QVariantMap& results); + void handleSelectSourcesResponse(uint response, const QVariantMap& results); + void handleStartResponse(uint response, const QVariantMap& results); + +private: + QDBusInterface* screencastPortal(); + QString createSessionToken() const; + QString createRequestToken() const; + void showGlassPane(bool show) const; + +private: + QRect mScreenRect; + bool mWithCursor{false}; + QString mSession; + QString mRequestPath; + QDBusInterface* mScreencastPortal{nullptr}; +}; diff --git a/src/frameworks/UBPipewireSink.cpp b/src/frameworks/UBPipewireSink.cpp new file mode 100644 index 000000000..91139404c --- /dev/null +++ b/src/frameworks/UBPipewireSink.cpp @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + +#include "UBPipewireSink.h" + +#include +#include + +#include +#include +#include +#include + +#include + + +UBPipewireSink::UBPipewireSink(QObject* parent) + : QObject{parent} +{ +} + +UBPipewireSink::~UBPipewireSink() +{ + qDebug() << "UBPipewireSink: stop threaded loop"; + pw_thread_loop_stop(mLoop); + pw_thread_loop_destroy(mLoop); +} + +bool UBPipewireSink::start(int fd, int nodeId) +{ + // stream event handler struct + // NOTE unused entries added for compatibility with some compilers + static const struct pw_stream_events streamEvents = { + .version = PW_VERSION_STREAM_EVENTS, + .destroy = nullptr, + .state_changed = [](void* userdata, enum pw_stream_state old, enum pw_stream_state state, const char* error){ + static_cast(userdata)->streamStateChanged(old, state, error); + }, + .control_info = nullptr, + .io_changed = nullptr, + .param_changed = [](void* userdata, uint32_t id, const struct spa_pod* param){ + static_cast(userdata)->streamParamChanged(id, param); + }, + .add_buffer = nullptr, + .remove_buffer = nullptr, + .process = [](void* userdata){ + static_cast(userdata)->process(); + }, + .drained = nullptr, + .command = nullptr, + .trigger_done = nullptr + }; + + qDebug() << "UBPipewireSink: start" << fd << nodeId; + + // Initialize PipeWire + pw_init(nullptr, nullptr); + + mLoop = pw_thread_loop_new(nullptr, nullptr); + + if (!mLoop) + { + qWarning() << "UBPipewireSink: unable to create main loop"; + return false; + } + + pw_thread_loop_lock(mLoop); + pw_thread_loop_start(mLoop); + + auto loop = pw_thread_loop_get_loop(mLoop); + + mContext = pw_context_new(loop, nullptr, 0); + + if (!mContext) + { + qWarning() << "UBPipewireSink: unable to create context"; + pw_thread_loop_destroy(mLoop); + return false; + } + + // connect context, duplicate fd before use, see + // https://chromium.googlesource.com/external/webrtc/+/master/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc#457 + // and https://doc.qt.io/qt-6/qdbusunixfiledescriptor.html#fileDescriptor + const auto fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 0); + auto core = pw_context_connect_fd(mContext, fd2, nullptr, 0); + + if (!core) + { + qWarning() << "Cannot connect" << errno; + return false; + } + + // Create stream + struct pw_properties* props; + props = pw_properties_new( + PW_KEY_MEDIA_TYPE, "Video", + PW_KEY_MEDIA_CATEGORY, "Capture", + PW_KEY_MEDIA_ROLE, "Screen", + nullptr); + + mStream = pw_stream_new(core, "capture", props); + + if (!mStream) + { + qWarning() << "UBPipewireSink: unable to create stream"; + pw_context_destroy(mContext); + pw_thread_loop_destroy(mLoop); + return false; + } + + pw_stream_add_listener(mStream, &mHook, &streamEvents, this); + + // Set up stream parameters + const struct spa_pod* params[1]; + uint8_t buffer[1024]; + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); + + const auto rDef = SPA_RECTANGLE(1024, 768); + const auto rMin = SPA_RECTANGLE(1, 1); + const auto rMax = SPA_RECTANGLE(4096, 4096); + const auto fDef = SPA_FRACTION(25, 1); + const auto fMin = SPA_FRACTION(0, 1); + const auto fMax = SPA_FRACTION(1000, 1); + + auto p = spa_pod_builder_add_object( + &b, + SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), + SPA_FORMAT_VIDEO_format, SPA_POD_CHOICE_ENUM_Id(7, + SPA_VIDEO_FORMAT_ARGB, + SPA_VIDEO_FORMAT_xRGB, + SPA_VIDEO_FORMAT_RGB, + SPA_VIDEO_FORMAT_RGBA, + SPA_VIDEO_FORMAT_RGBx, + SPA_VIDEO_FORMAT_BGRA, + SPA_VIDEO_FORMAT_BGRx), + SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle(&rDef, &rMin, &rMax), + SPA_FORMAT_VIDEO_framerate, SPA_POD_CHOICE_RANGE_Fraction(&fDef, &fMin, &fMax)); + + params[0] = static_cast(p); + + // connect stream + // NOTE connection by nodeId is deprecated. But portal only provides this. + auto res = + pw_stream_connect(mStream, PW_DIRECTION_INPUT, nodeId, + pw_stream_flags(PW_STREAM_FLAG_AUTOCONNECT | // try to automatically connect this stream + PW_STREAM_FLAG_MAP_BUFFERS), // mmap the buffer data for us + params, 1); + + if (res < 0) + { + qWarning() << "UBPipewireSink: unable to connect stream" << res; + } + + pw_thread_loop_unlock(mLoop); + + return true; +} + +void UBPipewireSink::process() +{ + struct pw_buffer* b; + struct spa_buffer* buf; + + if ((b = pw_stream_dequeue_buffer(mStream)) == nullptr) + { + pw_log_warn("out of buffers: %m"); + return; + } + + buf = b->buffer; + if (buf->datas[0].data == NULL) + return; + + // create image from frame data + auto data = static_cast(buf->datas[0].data); + auto width = static_cast(mFormat.info.raw.size.width); + auto height = static_cast(mFormat.info.raw.size.height); + auto stride = buf->datas[0].chunk->stride; + + QImage image; + bool swapRgb{false}; + + switch (mFormat.info.raw.format) + { + case SPA_VIDEO_FORMAT_ARGB: + image = QImage(data, width, height, stride, QImage::Format_ARGB32); + break; + + case SPA_VIDEO_FORMAT_xRGB: + image = QImage(data, width, height, stride, QImage::Format_RGB32); + break; + + case SPA_VIDEO_FORMAT_RGB: + image = QImage(data, width, height, stride, QImage::Format_RGB888); + break; + + case SPA_VIDEO_FORMAT_RGBA: + image = QImage(data, width, height, stride, QImage::Format_RGBA8888); + break; + + case SPA_VIDEO_FORMAT_RGBx: + image = QImage(data, width, height, stride, QImage::Format_RGBX8888); + break; + + case SPA_VIDEO_FORMAT_BGRA: + image = QImage(data, width, height, stride, QImage::Format_RGBA8888); + swapRgb = true; + break; + + case SPA_VIDEO_FORMAT_BGRx: + image = QImage(data, width, height, stride, QImage::Format_RGBX8888); + swapRgb = true; + break; + + default: + qWarning() << "UBPipewireSink: unsupported image format"; + } + + if (swapRgb) + { +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + image.rgbSwap(); +#else + image = image.rgbSwapped(); +#endif + } + + emit gotImage(image); + + pw_stream_queue_buffer(mStream, b); +} + +void UBPipewireSink::streamStateChanged(pw_stream_state old, pw_stream_state state, const char* error) +{ + qDebug() << "UBPipewireSink: state changed" << state << error; + + if (old == PW_STREAM_STATE_STREAMING) + { + emit streamingInterrupted(); + } +} + +void UBPipewireSink::streamParamChanged(uint32_t id, const spa_pod* param) +{ + if (param == NULL || id != SPA_PARAM_Format) + return; + + if (spa_format_parse(param, &mFormat.media_type, &mFormat.media_subtype) < 0) + return; + + if (mFormat.media_type != SPA_MEDIA_TYPE_video || mFormat.media_subtype != SPA_MEDIA_SUBTYPE_raw) + return; + + if (spa_format_video_raw_parse(param, &mFormat.info.raw) < 0) + return; + + qDebug() << "got video format:"; + qDebug() << " format:" << mFormat.info.raw.format + << spa_debug_type_find_name(spa_type_video_format, mFormat.info.raw.format); + qDebug() << " size:" << mFormat.info.raw.size.width << mFormat.info.raw.size.height; + qDebug() << " framerate:" << mFormat.info.raw.framerate.num << "/" << mFormat.info.raw.framerate.denom; +} diff --git a/src/frameworks/UBPipewireSink.h b/src/frameworks/UBPipewireSink.h new file mode 100644 index 000000000..44ccb657f --- /dev/null +++ b/src/frameworks/UBPipewireSink.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + +#pragma once + +#include + +#include +#include + + +class UBPipewireSink : public QObject +{ + Q_OBJECT + +public: + explicit UBPipewireSink(QObject* parent = nullptr); + ~UBPipewireSink(); + +public slots: + bool start(int fd, int nodeId); + +signals: + void gotImage(QImage image); + void streamingInterrupted(); + +private: + void process(); + void streamStateChanged(enum pw_stream_state old, enum pw_stream_state state, const char* error); + void streamParamChanged(uint32_t id, const struct spa_pod* param); + +private: + pw_thread_loop* mLoop{nullptr}; + pw_context* mContext{nullptr}; + pw_stream* mStream{nullptr}; + struct spa_video_info mFormat{}; + struct spa_hook mHook{}; +}; + diff --git a/src/frameworks/frameworks.pri b/src/frameworks/frameworks.pri index 165ed1a5a..a14e74972 100644 --- a/src/frameworks/frameworks.pri +++ b/src/frameworks/frameworks.pri @@ -35,15 +35,13 @@ macx { } -linux-g++ { - - SOURCES += src/frameworks/UBPlatformUtils_linux.cpp -} -linux-g++-32 { - - SOURCES += src/frameworks/UBPlatformUtils_linux.cpp -} -linux-g++-64 { - - SOURCES += src/frameworks/UBPlatformUtils_linux.cpp +linux-g++* { + HEADERS += src/frameworks/UBDesktopPortal.h \ + src/frameworks/UBPipewireSink.h + SOURCES += src/frameworks/UBPlatformUtils_linux.cpp \ + src/frameworks/UBDesktopPortal.cpp \ + src/frameworks/UBPipewireSink.cpp + + CONFIG += link_pkgconfig + PKGCONFIG += libpipewire-0.3 } From 2608e01c1da4f543bcf90f97dc7c1d7cf5397fa9 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 3 Aug 2025 12:18:08 +0200 Subject: [PATCH 075/133] feat: add function to grab screen using desktop portal - add UBPlatformUtils::grabScreen - deliver result asynchronously - add function to determine session type X11 or Wayland Signed-off-by: letsfindaway --- src/frameworks/UBPlatformUtils.h | 13 +++++++ src/frameworks/UBPlatformUtils_linux.cpp | 47 ++++++++++++++++++++++++ src/frameworks/UBPlatformUtils_mac.mm | 6 +++ src/frameworks/UBPlatformUtils_win.cpp | 6 +++ 4 files changed, 72 insertions(+) diff --git a/src/frameworks/UBPlatformUtils.h b/src/frameworks/UBPlatformUtils.h index ee4b11790..38a11814f 100644 --- a/src/frameworks/UBPlatformUtils.h +++ b/src/frameworks/UBPlatformUtils.h @@ -35,6 +35,7 @@ #include class QMainWindow; +class QScreen; #define SYMBOL_KEYS_COUNT 47 @@ -212,12 +213,24 @@ class UBPlatformUtils static void setFrontProcess(); static void showFullScreen(QWidget * pWidget); static void showOSK(bool show); + static void grabScreen(QScreen* screen, std::function callback, QRect rect = {}); #ifdef Q_OS_OSX static void SetMacLocaleByIdentifier(const QString& id); static void toggleFinder(const bool on); static bool errorOpeningVirtualKeyboard; +#endif + enum SessionType { + UNKNOWN, + X11, + WAYLAND + }; + +#ifdef Q_OS_LINUX + static SessionType sessionType(); +#else + static SessionType sessionType() { return UNKNOWN; } #endif }; diff --git a/src/frameworks/UBPlatformUtils_linux.cpp b/src/frameworks/UBPlatformUtils_linux.cpp index 6dde5010b..ee175a1d6 100644 --- a/src/frameworks/UBPlatformUtils_linux.cpp +++ b/src/frameworks/UBPlatformUtils_linux.cpp @@ -37,6 +37,7 @@ #include #include +#include "frameworks/UBDesktopPortal.h" #include "frameworks/UBFileSystemUtils.h" #include "core/UBApplication.h" #include "core/UBDisplayManager.h" @@ -535,6 +536,52 @@ void UBPlatformUtils::showOSK(bool show) } } +void UBPlatformUtils::grabScreen(QScreen* screen, std::function callback, QRect rect) +{ + if (sessionType() == WAYLAND) + { + UBDesktopPortal* portal = new UBDesktopPortal; + + QObject::connect(portal, &UBDesktopPortal::screenGrabbed, portal, [portal,callback](QPixmap screenshot){ + callback(screenshot); + portal->deleteLater(); + }); + + portal->grabScreen(screen, rect); + } + else + { + // see https://doc.qt.io/qt-6.2/qtwidgets-desktop-screenshot-example.html + // for using window id 0 + QPixmap pixmap = screen->grabWindow(0, rect.x(), rect.y(), rect.width(), rect.height()); + callback(pixmap); + } +} + +UBPlatformUtils::SessionType UBPlatformUtils::sessionType() +{ + /* + * We use XDG_SESSION_TYPE here instead of QGuiApplication::platformName(), because + * the platformName just says what Qt plugin is used to access the platform, while + * XDG_SESSION_TYPE is the actual type of the session. E.g. if we're on Wayland, + * but use the xcb platform plugin using xwayland, then platform name returns "xdg" + * just as if we're running on X11. However we would still have to use the desktop + * portal to access screen content outside of our application. + */ + QString xdgSessionType = QProcessEnvironment::systemEnvironment().value("XDG_SESSION_TYPE", ""); + + if (xdgSessionType == "x11") + { + return X11; + } + else if (xdgSessionType == "wayland") + { + return WAYLAND; + } + + return UNKNOWN; +} + OnboardListener::OnboardListener(const QDBusConnection& connection, QObject* parent) : QObject{parent} , mConnection{connection} diff --git a/src/frameworks/UBPlatformUtils_mac.mm b/src/frameworks/UBPlatformUtils_mac.mm index 92f89d090..513bc3b89 100644 --- a/src/frameworks/UBPlatformUtils_mac.mm +++ b/src/frameworks/UBPlatformUtils_mac.mm @@ -751,3 +751,9 @@ click menu item (nbItems - 4)\n\ } } } + +void UBPlatformUtils::grabScreen(QScreen* screen, std::function callback, QRect rect) +{ + QPixmap pixmap = screen->grabWindow(0, rect.x(), rect.y(), rect.width(), rect.height()); + callback(pixmap); +} diff --git a/src/frameworks/UBPlatformUtils_win.cpp b/src/frameworks/UBPlatformUtils_win.cpp index ba4416bf2..9c144b255 100644 --- a/src/frameworks/UBPlatformUtils_win.cpp +++ b/src/frameworks/UBPlatformUtils_win.cpp @@ -494,3 +494,9 @@ void UBPlatformUtils::showOSK(bool show) PostMessage(oskWindow, WM_SYSCOMMAND, SC_CLOSE, 0); } } + +void UBPlatformUtils::grabScreen(QScreen* screen, std::function callback, QRect rect) +{ + QPixmap pixmap = screen->grabWindow(0, rect.x(), rect.y(), rect.width(), rect.height()); + callback(pixmap); +} From 230ba4703769154872c6f603a6b60cd511d82f6d Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 3 Aug 2025 12:31:46 +0200 Subject: [PATCH 076/133] feat: screenshot with wayland using desktop portal - use screenshot portal for grab screen on wayland - fix screen positioning of desktop screenshot dialog Signed-off-by: letsfindaway --- src/core/UBDisplayManager.cpp | 12 +++--- src/core/UBDisplayManager.h | 2 +- src/desktop/UBCustomCaptureWindow.cpp | 12 +----- src/desktop/UBDesktopAnnotationController.cpp | 43 +++++++++---------- src/desktop/UBDesktopAnnotationController.h | 2 +- src/gui/UBScreenMirror.cpp | 11 +++-- src/podcast/UBPodcastController.cpp | 13 ++++-- src/podcast/UBPodcastController.h | 1 + src/web/UBWebController.cpp | 25 ++++++----- 9 files changed, 63 insertions(+), 58 deletions(-) diff --git a/src/core/UBDisplayManager.cpp b/src/core/UBDisplayManager.cpp index ca45ad27e..e83bae7df 100644 --- a/src/core/UBDisplayManager.cpp +++ b/src/core/UBDisplayManager.cpp @@ -521,18 +521,18 @@ qreal UBDisplayManager::logicalDpi(ScreenRole role) const return scr ? scr->logicalDotsPerInch() : 96.; } -QPixmap UBDisplayManager::grab(ScreenRole role, QRect rect) const +void UBDisplayManager::grab(ScreenRole role, std::function callback, QRect rect) const { QScreen* scr = screen(role); if (scr) { - // see https://doc.qt.io/qt-6.2/qtwidgets-desktop-screenshot-example.html - // for using window id 0 - return scr->grabWindow(0, rect.x(), rect.y(), rect.width(), rect.height()); + UBPlatformUtils::grabScreen(scr, callback, rect); + } + else + { + callback(QPixmap()); } - - return QPixmap(); } QPixmap UBDisplayManager::grabGlobal(QRect rect) const diff --git a/src/core/UBDisplayManager.h b/src/core/UBDisplayManager.h index 6cfaaed6b..00b596375 100644 --- a/src/core/UBDisplayManager.h +++ b/src/core/UBDisplayManager.h @@ -105,7 +105,7 @@ class UBDisplayManager : public QObject qreal physicalDpi(ScreenRole role) const; qreal logicalDpi(ScreenRole role) const; - QPixmap grab(ScreenRole role, QRect rect = QRect(0, 0, -1, -1)) const; + void grab(ScreenRole role, std::function callback, QRect rect = {}) const; QPixmap grabGlobal(QRect rect) const; void initScreensByRole(); diff --git a/src/desktop/UBCustomCaptureWindow.cpp b/src/desktop/UBCustomCaptureWindow.cpp index 79fab9301..0193b70d1 100644 --- a/src/desktop/UBCustomCaptureWindow.cpp +++ b/src/desktop/UBCustomCaptureWindow.cpp @@ -79,16 +79,8 @@ int UBCustomCaptureWindow::execute(const QPixmap &pScreenPixmap) { mWholeScreenPixmap = pScreenPixmap; - // necessary so that changing geometry really affects the widget - showNormal(); - const auto geo = UBApplication::displayManager->screenGeometry(ScreenRole::Desktop); - setGeometry(geo); - - // for some Qt versions it is also necessary to do explicit move and resize - move(geo.topLeft()); - resize(geo.size()); - - this->show(); + setGeometry(UBApplication::displayManager->screenGeometry(ScreenRole::Desktop)); + showFullScreen(); setWindowOpacity(1.0); return exec(); diff --git a/src/desktop/UBDesktopAnnotationController.cpp b/src/desktop/UBDesktopAnnotationController.cpp index 6d4e1da48..c0ef7d49c 100644 --- a/src/desktop/UBDesktopAnnotationController.cpp +++ b/src/desktop/UBDesktopAnnotationController.cpp @@ -442,25 +442,22 @@ void UBDesktopAnnotationController::customCapture() updateBackground(); mDesktopPalette->disappearForCapture(); - UBCustomCaptureWindow customCaptureWindow(mDesktopPalette); - // need to show the window before execute it to avoid some glitch on windows. - #ifndef Q_OS_WIN // Working only without this call on win32 desktop mode - UBPlatformUtils::showFullScreen(&customCaptureWindow); - #endif - - if (customCaptureWindow.execute(getScreenPixmap()) == QDialog::Accepted) - { - QPixmap selectedPixmap = customCaptureWindow.getSelectedPixmap(); - emit imageCaptured(selectedPixmap, false); - } + getScreenPixmap([this](QPixmap pixmap){ + UBCustomCaptureWindow customCaptureWindow(mDesktopPalette); + if (customCaptureWindow.execute(pixmap) == QDialog::Accepted) + { + QPixmap selectedPixmap = customCaptureWindow.getSelectedPixmap(); + emit imageCaptured(selectedPixmap, false); + } - mDesktopPalette->appear(); + mDesktopPalette->appear(); - mCustomCaptureClicked = false; - mIsFullyTransparent = false; - updateBackground(); + mCustomCaptureClicked = false; + mIsFullyTransparent = false; + updateBackground(); + }); } } @@ -473,21 +470,21 @@ void UBDesktopAnnotationController::screenCapture() mDesktopPalette->disappearForCapture(); - QPixmap originalPixmap = getScreenPixmap(); - - mDesktopPalette->appear(); + getScreenPixmap([this](QPixmap pixmap){ + mDesktopPalette->appear(); - emit imageCaptured(originalPixmap, false); + emit imageCaptured(pixmap, false); - mIsFullyTransparent = false; + mIsFullyTransparent = false; - updateBackground(); + updateBackground(); + }); } -QPixmap UBDesktopAnnotationController::getScreenPixmap() +void UBDesktopAnnotationController::getScreenPixmap(std::function callback) { - return UBApplication::displayManager->grab(ScreenRole::Control); + UBApplication::displayManager->grab(ScreenRole::Control, callback); } diff --git a/src/desktop/UBDesktopAnnotationController.h b/src/desktop/UBDesktopAnnotationController.h index 5a3e07130..c549cb934 100644 --- a/src/desktop/UBDesktopAnnotationController.h +++ b/src/desktop/UBDesktopAnnotationController.h @@ -99,7 +99,7 @@ class UBDesktopAnnotationController : public QObject void restoreUniboard(); protected: - QPixmap getScreenPixmap(); + void getScreenPixmap(std::function callback); UBBoardView* mTransparentDrawingView; std::shared_ptr mTransparentDrawingScene; diff --git a/src/gui/UBScreenMirror.cpp b/src/gui/UBScreenMirror.cpp index ff9810862..c2e3dea08 100644 --- a/src/gui/UBScreenMirror.cpp +++ b/src/gui/UBScreenMirror.cpp @@ -90,14 +90,17 @@ void UBScreenMirror::grabPixmap() if (mSourceWidget) { mLastPixmap = mSourceWidget->grab(); + + if (!mLastPixmap.isNull()) + mLastPixmap = mLastPixmap.scaled(width(), height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); } else { - mLastPixmap = UBApplication::displayManager->grab(ScreenRole::Control); + UBApplication::displayManager->grab(ScreenRole::Control, [this](QPixmap pixmap){ + if (!pixmap.isNull()) + mLastPixmap = pixmap.scaled(width(), height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); + }); } - - if (!mLastPixmap.isNull()) - mLastPixmap = mLastPixmap.scaled(size() * mLastPixmap.devicePixelRatioF(), Qt::KeepAspectRatio, Qt::SmoothTransformation); } diff --git a/src/podcast/UBPodcastController.cpp b/src/podcast/UBPodcastController.cpp index 6a56fc71e..e3e924b2b 100644 --- a/src/podcast/UBPodcastController.cpp +++ b/src/podcast/UBPodcastController.cpp @@ -748,7 +748,10 @@ void UBPodcastController::processScreenGrabingTimerEvent() if (mIsDesktopMode) { - widgetContent = UBApplication::displayManager->grab(ScreenRole::Control); + // TODO implement screencast based on screencast portal + UBApplication::displayManager->grab(ScreenRole::Control, [this](QPixmap pixmap){ + encodeWidgetContent(pixmap); + }); } else { @@ -756,8 +759,12 @@ void UBPodcastController::processScreenGrabingTimerEvent() widgetContent = QPixmap(mSourceWidget->size()); QPainter p(&widgetContent); mSourceWidget->render(&p); + encodeWidgetContent(widgetContent); } +} +void UBPodcastController::encodeWidgetContent(QPixmap pixmap) +{ QPainter p(&mLatestCapture); if (!mInitialized) @@ -766,11 +773,11 @@ void UBPodcastController::processScreenGrabingTimerEvent() mInitialized = true; } - QRectF targetRect = mViewToVideoTransform.mapRect(QRectF(0, 0, widgetContent.width(), widgetContent.height())); + QRectF targetRect = mViewToVideoTransform.mapRect(QRectF(0, 0, pixmap.width(), pixmap.height())); p.setRenderHints(QPainter::Antialiasing); p.setRenderHints(QPainter::SmoothPixmapTransform); - p.drawPixmap(targetRect.left(), targetRect.top(), widgetContent.scaled(targetRect.width(), targetRect.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); + p.drawPixmap(targetRect.left(), targetRect.top(), pixmap.scaled(targetRect.width(), targetRect.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); sendLatestPixmapToEncoder(); } diff --git a/src/podcast/UBPodcastController.h b/src/podcast/UBPodcastController.h index 975857670..84d47f112 100644 --- a/src/podcast/UBPodcastController.h +++ b/src/podcast/UBPodcastController.h @@ -94,6 +94,7 @@ class UBPodcastController : public QObject private slots: void processScreenGrabingTimerEvent(); + void encodeWidgetContent(QPixmap pixmap); void processScenePaintEvent(); diff --git a/src/web/UBWebController.cpp b/src/web/UBWebController.cpp index 731aad7f8..17b816d48 100644 --- a/src/web/UBWebController.cpp +++ b/src/web/UBWebController.cpp @@ -553,17 +553,20 @@ void UBWebController::customCapture() mToolsCurrentPalette->setVisible(false); qApp->processEvents(); - UBCustomCaptureWindow customCaptureWindow(mCurrentWebBrowser); + UBApplication::displayManager->grab(ScreenRole::Control, [this](QPixmap pixmap){ + UBCustomCaptureWindow customCaptureWindow(mCurrentWebBrowser); + customCaptureWindow.show(); - customCaptureWindow.show(); - - if (customCaptureWindow.execute(getScreenPixmap()) == QDialog::Accepted) - { - QPixmap selectedPixmap = customCaptureWindow.getSelectedPixmap(); - emit imageCaptured(selectedPixmap, false, mCurrentWebBrowser->currentTab()->url()); - } + qDebug() << "before execute"; + if (customCaptureWindow.execute(pixmap) == QDialog::Accepted) + { + qDebug() << "after execute"; + QPixmap selectedPixmap = customCaptureWindow.getSelectedPixmap(); + emit imageCaptured(selectedPixmap, false, mCurrentWebBrowser->currentTab()->url()); + } - mToolsCurrentPalette->setVisible(true); + mToolsCurrentPalette->setVisible(true); + }); } @@ -575,7 +578,9 @@ void UBWebController::toogleMirroring(bool checked) QPixmap UBWebController::getScreenPixmap() { - return UBApplication::displayManager->grab(ScreenRole::Control); + // FIXME implement + return {}; +// return UBApplication::displayManager->grab(ScreenRole::Control); } From d5f817eb3f50dc846916edf3a4e9e90becb50afa Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 3 Aug 2025 11:23:53 +0200 Subject: [PATCH 077/133] feat: use screencast portal for desktop mode mirroring - on wayland, use the desktop portal to start a screencast to mirror the screen in desktop mode Signed-off-by: letsfindaway --- src/gui/UBScreenMirror.cpp | 93 +++++++++++++++++++++++++++++++++++++- src/gui/UBScreenMirror.h | 18 ++++++-- 2 files changed, 106 insertions(+), 5 deletions(-) diff --git a/src/gui/UBScreenMirror.cpp b/src/gui/UBScreenMirror.cpp index c2e3dea08..04b699094 100644 --- a/src/gui/UBScreenMirror.cpp +++ b/src/gui/UBScreenMirror.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) * * Copyright (C) 2013 Open Education Foundation * @@ -34,6 +34,12 @@ #include "core/UBDisplayManager.h" #include "board/UBBoardController.h" +#ifdef Q_OS_LINUX +#include "frameworks/UBDesktopPortal.h" +#include "frameworks/UBPipewireSink.h" +#include "frameworks/UBPlatformUtils.h" +#endif + #if defined(Q_OS_OSX) #include #endif @@ -103,11 +109,66 @@ void UBScreenMirror::grabPixmap() } } +#ifdef Q_OS_LINUX +void UBScreenMirror::startScreenCast() +{ + // use UBDesktopPortal + if (!mPortal) + { + mPortal = new UBDesktopPortal(this); + + connect(mPortal, &UBDesktopPortal::streamStarted, this, &UBScreenMirror::playStream); + connect(mPortal, &UBDesktopPortal::screenCastAborted, this, [](){ + UBApplication::applicationController->mirroringEnabled(false); + }); + } + + mPortal->startScreenCast(true); +} + +void UBScreenMirror::playStream(int fd, int nodeId) +{ + qDebug() << "Start stream player" << fd << nodeId; + auto sink = new UBPipewireSink(this); + + connect(sink, &UBPipewireSink::gotImage, this, [this](QImage image){ + mLastPixmap = QPixmap::fromImage(image).scaled(width(), height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); + update(); + }); + + connect(sink, &UBPipewireSink::streamingInterrupted, sink, &QObject::deleteLater); + + sink->start(fd, nodeId); +} +#endif void UBScreenMirror::setSourceWidget(QWidget *sourceWidget) { + if (mSourceWidget == sourceWidget) + { + return; + } + + qDebug() << "Mirror: setSourceWidget" << sourceWidget; mSourceWidget = sourceWidget; +#ifdef Q_OS_LINUX + if (mSourceWidget == nullptr && mIsStarted && UBPlatformUtils::sessionType() == UBPlatformUtils::WAYLAND) + { + // stop timer + if (mTimerID != 0) + { + killTimer(mTimerID); + mTimerID = 0; + } + + // use desktop portal to start a screencast + mLastPixmap = {}; + startScreenCast(); + return; + } +#endif + grabPixmap(); update(); @@ -116,8 +177,25 @@ void UBScreenMirror::setSourceWidget(QWidget *sourceWidget) void UBScreenMirror::start() { + if (mIsStarted) + { + return; + } + qDebug() << "mirroring START"; + mIsStarted = true; UBApplication::boardController->freezeW3CWidgets(true); + +#ifdef Q_OS_LINUX + if (mSourceWidget == nullptr && UBPlatformUtils::sessionType() == UBPlatformUtils::WAYLAND) + { + // use desktop portal to start a screencast + mLastPixmap = {}; + startScreenCast(); + return; + } +#endif + if (mTimerID == 0) { int ms = 125; @@ -141,11 +219,24 @@ void UBScreenMirror::start() void UBScreenMirror::stop() { + if (!mIsStarted) + { + return; + } + qDebug() << "mirroring STOP"; + mIsStarted = false; UBApplication::boardController->freezeW3CWidgets(false); if (mTimerID != 0) { killTimer(mTimerID); mTimerID = 0; } + +#ifdef Q_OS_LINUX + if (mPortal) + { + mPortal->stopScreenCast(); + } +#endif } diff --git a/src/gui/UBScreenMirror.h b/src/gui/UBScreenMirror.h index 59b918d68..92923c9b6 100644 --- a/src/gui/UBScreenMirror.h +++ b/src/gui/UBScreenMirror.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) + * Copyright (C) 2015-2025 Département de l'Instruction Publique (DIP-SEM) * * Copyright (C) 2013 Open Education Foundation * @@ -33,9 +33,13 @@ #include #include +// forward +class UBDesktopPortal; + + class UBScreenMirror : public QWidget { - Q_OBJECT; + Q_OBJECT public: UBScreenMirror(QWidget* parent = 0); @@ -55,13 +59,19 @@ class UBScreenMirror : public QWidget private: void grabPixmap(); +#ifdef Q_OS_LINUX + void startScreenCast(); + void playStream(int fd, int nodeId); +#endif QWidget* mSourceWidget; - QPixmap mLastPixmap; - long mTimerID; + bool mIsStarted{false}; +#ifdef Q_OS_LINUX + UBDesktopPortal* mPortal{nullptr}; +#endif }; #endif /* UBSCREENMIRROR_H_ */ From 2d9e0de05723c18cc372f9ab7f0590e79d955efd Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 21 Jul 2025 17:17:14 +0200 Subject: [PATCH 078/133] feat: podcast in desktop mode - use ScreenCast to record desktop - send images to encoder - create and terminate a transient stream when switching to desktop mode for the first time with recording disabled Signed-off-by: letsfindaway --- src/podcast/UBPodcastController.cpp | 67 ++++++++++++++++++++++++++++- src/podcast/UBPodcastController.h | 7 +++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/src/podcast/UBPodcastController.cpp b/src/podcast/UBPodcastController.cpp index e3e924b2b..ac9b72a02 100644 --- a/src/podcast/UBPodcastController.cpp +++ b/src/podcast/UBPodcastController.cpp @@ -30,7 +30,6 @@ #include "UBPodcastController.h" #include "frameworks/UBFileSystemUtils.h" -#include "frameworks/UBStringUtils.h" #include "frameworks/UBPlatformUtils.h" #include "core/UBApplication.h" @@ -65,6 +64,8 @@ #include "ffmpeg/UBFFmpegVideoEncoder.h" #include "ffmpeg/UBMicrophoneInput.h" #elif defined(Q_OS_LINUX) + #include "frameworks/UBDesktopPortal.h" + #include "frameworks/UBPipewireSink.h" #include "ffmpeg/UBFFmpegVideoEncoder.h" #include "ffmpeg/UBMicrophoneInput.h" #endif @@ -250,7 +251,9 @@ void UBPodcastController::setSourceWidget(QWidget* pWidget) startNextChapter(); - if (mIsDesktopMode || UBApplication::applicationController->displayMode() == UBApplicationController::Internet) + // no timer for wayland desktop mode + if ((mIsDesktopMode && UBPlatformUtils::sessionType() != UBPlatformUtils::WAYLAND) || + UBApplication::applicationController->displayMode() == UBApplicationController::Internet) { mScreenGrabingTimerEventID = startTimer(1000 / mVideoFramesPerSecondAtStart); } @@ -454,6 +457,15 @@ void UBPodcastController::stop() if (mRecordingProgressTimerEventID != 0) killTimer(mRecordingProgressTimerEventID); + if (mPortal) + { + delete mPortal; + delete mPipewireSink; + + mPortal = nullptr; + mPipewireSink = nullptr; + } + sendLatestPixmapToEncoder(); setRecordingState(Stopping); @@ -631,6 +643,19 @@ void UBPodcastController::applicationMainModeChanged(UBApplicationController::Ma { mIsDesktopMode = false; +#ifdef Q_OS_LINUX + if (mPortal) + { + qDebug() << "Stop ScreenCast"; + mPortal->stopScreenCast(); + + delete mPipewireSink; + mPipewireSink = nullptr; + + mInitialized = false; + } +#endif + if (pMode == UBApplicationController::Internet) { setSourceWidget(UBApplication::webController->controlView()); @@ -649,6 +674,44 @@ void UBPodcastController::applicationDesktopMode(bool displayed) if (displayed) { setSourceWidget(UBApplication::displayManager->widget(ScreenRole::Desktop)); + +#ifdef Q_OS_LINUX + if (UBPlatformUtils::sessionType() == UBPlatformUtils::WAYLAND && !mPipewireSink) + { + // create a ScreenCast session + if (!mPortal) + { + mPortal = new UBDesktopPortal{this}; + + // delete portal if screencast was aborted + connect(mPortal, &UBDesktopPortal::screenCastAborted, this, [this](){ + mPortal->deleteLater(); + mPortal = nullptr; + }); + } + + if (mRecordingState == Recording) + { + mPipewireSink = new UBPipewireSink{this}; + + disconnect(mPortal, &UBDesktopPortal::streamStarted, mPortal, &UBDesktopPortal::stopScreenCast); + connect(mPortal, &UBDesktopPortal::streamStarted, mPipewireSink, &UBPipewireSink::start); + connect(mPipewireSink, &UBPipewireSink::gotImage, this, [this](QImage image){ + if (mPipewireSink) + { + encodeWidgetContent(QPixmap::fromImage(image)); + } + }); + } + else + { + // stop stream, we just selected the screen + connect(mPortal, &UBDesktopPortal::streamStarted, mPortal, &UBDesktopPortal::stopScreenCast); + } + + mPortal->startScreenCast(true); + } +#endif } else { diff --git a/src/podcast/UBPodcastController.h b/src/podcast/UBPodcastController.h index 84d47f112..89143892b 100644 --- a/src/podcast/UBPodcastController.h +++ b/src/podcast/UBPodcastController.h @@ -40,6 +40,9 @@ class UBGraphicsScene; class WebView; class UBPodcastRecordingPalette; +class UBDesktopPortal; +class UBPipewireSink; + class UBPodcastController : public QObject { @@ -188,6 +191,10 @@ class UBPodcastController : public QObject QString mPodcastRecordingPath; +#ifdef Q_OS_LINUX + UBDesktopPortal* mPortal{nullptr}; + UBPipewireSink* mPipewireSink{nullptr}; +#endif }; #endif /* UBPODCASTCONTROLLER_H_ */ From 4fd6863f2ae3dfac62c40136a323da6bc23f6481 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 3 Aug 2025 12:22:31 +0200 Subject: [PATCH 079/133] fix: screen labels on wayland - create screen labels in UBDisplayManager instead of UBPreferencesDialog, fixes crash on wayland - workaround: position labels as fullscreen windows and then switch to normal after compositor has positioned it - workaround: handle button clicks stealing focus from line edit Signed-off-by: letsfindaway --- src/core/UBDisplayManager.cpp | 160 +++++++++++++++++++++++++++ src/core/UBDisplayManager.h | 19 +++- src/core/UBPreferencesController.cpp | 115 ++++++------------- src/core/UBPreferencesController.h | 3 +- 4 files changed, 206 insertions(+), 91 deletions(-) diff --git a/src/core/UBDisplayManager.cpp b/src/core/UBDisplayManager.cpp index e83bae7df..51b7252fd 100644 --- a/src/core/UBDisplayManager.cpp +++ b/src/core/UBDisplayManager.cpp @@ -96,6 +96,7 @@ void UBDisplayManager::initScreenIndexes() { qDebug() << "availableScreens" << screens; mAvailableScreens = screens; + createScreenLabels(); emit availableScreenCountChanged(screens.count()); } @@ -106,6 +107,62 @@ void UBDisplayManager::initScreenIndexes() */ } +void UBDisplayManager::createScreenLabels() +{ + if (!mLabelParent) + { + // don't create screen labels before parent is known + return; + } + + qDeleteAll(mScreenLabels); + mScreenLabels.clear(); + + const static QSize labelSize{300, 150}; + const auto screens = availableScreens(); + QStringList availableScreenIndexes; + int screenIndex = 1; + QFont font; + font.setPointSize(48); + + for (QScreen* screen : screens) + { + QString index = QString::number(screenIndex); + availableScreenIndexes << index; + + QPushButton* button = new QPushButton{mLabelParent}; + button->setWindowFlag(Qt::FramelessWindowHint, true); + button->setWindowFlag(Qt::WindowStaysOnTopHint, true); + button->setWindowFlag(Qt::BypassWindowManagerHint, true); + button->setWindowFlag(Qt::Window, true); + button->setWindowFlag(Qt::WindowDoesNotAcceptFocus, true); + button->setAttribute(Qt::WA_ShowWithoutActivating, true); + button->setProperty("screenIndex", index); +#ifdef QT_DEBUG + button->setText(index + "(" + screen->name() + ")"); +#else + button->setText(index); +#endif + button->setFont(font); + button->move(screen->geometry().topLeft()); + button->setMinimumSize(labelSize); + button->setCursor(Qt::PointingHandCursor); + + connect(button, &QPushButton::pressed, this, [this](){ + QPushButton* button = dynamic_cast(sender()); + + if (button) + { + QString screenIndex = button->property("screenIndex").toString(); + emit screenLabelPressed(screenIndex); + } + }); + + mScreenLabels << button; + ++screenIndex; + } +} + void UBDisplayManager::initScreensByRole() { mScreensByRole.clear(); @@ -146,6 +203,9 @@ void UBDisplayManager::assignRoles() QStringList screenList = appScreenList.toStringList(); qDebug() << "assignRoles using screen list" << screenList; + // disable screen labels of screens in list + disableScreenLabels(screenList); + if (!appScreenList.isValid()) { // no entry in configuration files @@ -317,6 +377,24 @@ void UBDisplayManager::adjustScreens() positionScreens(); } +void UBDisplayManager::setScreenLabelParent(QWidget* labelParent) +{ + mLabelParent = labelParent; + createScreenLabels(); +} + +QStringList UBDisplayManager::availableScreenIndexes() +{ + QStringList screenIndexes; + + for (const auto label : mScreenLabels) + { + screenIndexes << label->property("screenIndex").toString(); + } + + return screenIndexes; +} + void UBDisplayManager::positionScreens() { // static event filter object @@ -473,6 +551,88 @@ void UBDisplayManager::unBlackout() UBApplication::boardController->freezeW3CWidgets(false); } +void UBDisplayManager::showScreenLabels(bool show) +{ + if (mScreenLabels.empty() || mScreenLabels.first().isNull() || mScreenLabels.first()->isVisible() == show) + { + return; + } + + if (show) + { + if (UBPlatformUtils::sessionType() == UBPlatformUtils::WAYLAND) + { + constexpr int positioningDelay{300}; + + // workaround: wayland window positioning only works for fullscreen + for (auto label : mScreenLabels) + { + if (label) + { + label->showFullScreen(); + } + + // we can however go back to normal later, when OS window positioning is finished + QTimer::singleShot(positioningDelay, this, [label](){ + if (label) + { + label->showNormal(); + } + }); + } + + auto parent = mScreenLabels.first()->parentWidget(); + + // make sure focus is on label's parent (screen list line edit) after labels are displayed + QTimer::singleShot(positioningDelay + 100, this, [parent](){ + parent->activateWindow(); + }); + } + else + { + for (auto label : mScreenLabels) + { + if (label) + { + label->showNormal(); + } + } + } + } + else + { + // workaround for wayland not supporting WindowDoesNotAcceptFocus + for (const auto label : mScreenLabels) + { + if (label && label->rect().contains(QCursor::pos())) + { + // do not hide labels when triggered by a click on one of them + return; + } + } + + for (auto label : mScreenLabels) + { + if (label) + { + label->hide(); + } + } + } +} + +void UBDisplayManager::disableScreenLabels(QStringList screenList) +{ + for (auto label : mScreenLabels) + { + if (label) + { + const auto screenIndex = label->property("screenIndex").toString(); + label->setDisabled(screenList.contains(screenIndex)); + } + } +} + void UBDisplayManager::addOrRemoveScreen(QScreen *screen) { Q_UNUSED(screen); diff --git a/src/core/UBDisplayManager.h b/src/core/UBDisplayManager.h index 00b596375..082da734d 100644 --- a/src/core/UBDisplayManager.h +++ b/src/core/UBDisplayManager.h @@ -30,8 +30,9 @@ #ifndef UBDISPLAYMANAGER_H_ #define UBDISPLAYMANAGER_H_ -#include #include +#include +#include class UBBlackoutWidget; class UBBoardView; @@ -113,16 +114,20 @@ class UBDisplayManager : public QObject void positionScreens(); void adjustScreens(); - signals: + void setScreenLabelParent(QWidget* labelParent); + QStringList availableScreenIndexes(); + + signals: void screenRolesAssigned(); void screenLayoutChanged(); void availableScreenCountChanged(int screenCount); + void screenLabelPressed(const QString& screenIndex); - public slots: - + public slots: void blackout(); - void unBlackout(); + void showScreenLabels(bool show); + void disableScreenLabels(QStringList screenList); private slots: @@ -131,6 +136,7 @@ class UBDisplayManager : public QObject private: void initScreenIndexes(); + void createScreenLabels(); QList mBlackoutWidgets; QList mBlackoutUiList; @@ -139,6 +145,9 @@ class UBDisplayManager : public QObject QMap> mScreensByRole; QMap> mWidgetsByRole; + QList> mScreenLabels; + QWidget* mLabelParent{nullptr}; + bool mUseMultiScreen; }; diff --git a/src/core/UBPreferencesController.cpp b/src/core/UBPreferencesController.cpp index ed0e393d8..f4aa59ec3 100644 --- a/src/core/UBPreferencesController.cpp +++ b/src/core/UBPreferencesController.cpp @@ -770,6 +770,10 @@ UBScreenListLineEdit::UBScreenListLineEdit(QWidget *parent) , mValidator(nullptr) { connect(this, &QLineEdit::textChanged, this, &UBScreenListLineEdit::onTextChanged); + UBApplication::displayManager->setScreenLabelParent(this); + + connect(UBApplication::displayManager, &UBDisplayManager::screenLabelPressed, this, &UBScreenListLineEdit::addScreen); + connect(this, &UBScreenListLineEdit::screenListChanged, UBApplication::displayManager, &UBDisplayManager::disableScreenLabels); } void UBScreenListLineEdit::setDefault() @@ -785,116 +789,59 @@ void UBScreenListLineEdit::loadScreenList(const QStringList &screenList) void UBScreenListLineEdit::focusInEvent(QFocusEvent *focusEvent) { QLineEdit::focusInEvent(focusEvent); + UBApplication::displayManager->showScreenLabels(true); - if (mScreenLabels.empty()) + if (!mValidator) { - QStringList screenList = UBStringUtils::trimmed(text().split(',')); - - QList screens = UBApplication::displayManager->availableScreens(); - QStringList availableScreenIndexes; - int screenIndex = 1; - QFont font; - font.setPointSize(48); - - for (QScreen* screen : screens) - { - QString index = QString::number(screenIndex); - availableScreenIndexes << index; - - QPushButton* button = new QPushButton(this); - button->setWindowFlag(Qt::FramelessWindowHint, true); - button->setWindowFlag(Qt::WindowStaysOnTopHint, true); - button->setWindowFlag(Qt::X11BypassWindowManagerHint, true); - button->setWindowFlag(Qt::Window, true); - button->setWindowFlag(Qt::WindowDoesNotAcceptFocus, true); - button->setAttribute(Qt::WA_ShowWithoutActivating, true); - button->setProperty("screenIndex", index); -#ifdef QT_DEBUG - button->setText(index + "(" + screen->name() + ")"); -#else - button->setText(index); -#endif - button->setFont(font); - button->move(screen->geometry().topLeft()); - button->setMinimumSize(300, 150); - button->setDisabled(screenList.contains(index)); - button->setCursor(Qt::PointingHandCursor); - button->show(); - - connect(button, &QPushButton::pressed, this, &UBScreenListLineEdit::addScreen); - - mScreenLabels << button; - ++screenIndex; - } + mValidator = new UBStringListValidator(this); + setValidator(mValidator); + } - if (!mValidator) - { - mValidator = new UBStringListValidator(this); - setValidator(mValidator); - } + mValidator->setValidationStringList(UBApplication::displayManager->availableScreenIndexes()); - mValidator->setValidationStringList(availableScreenIndexes); - } } void UBScreenListLineEdit::focusOutEvent(QFocusEvent *focusEvent) { QLineEdit::focusOutEvent(focusEvent); - qDeleteAll(mScreenLabels); - mScreenLabels.clear(); -} - -void UBScreenListLineEdit::addScreen() -{ - QPushButton* button = dynamic_cast(sender()); - if (button) + if (focusEvent->reason() != Qt::ActiveWindowFocusReason) { - QString list = text(); - mValidator->fixup(list); - QString screenIndex = button->property("screenIndex").toString(); - - if (list.isEmpty()) - { - setText(screenIndex); - } - else - { - setText(list + "," + screenIndex); - } - - button->setEnabled(false); + UBApplication::displayManager->showScreenLabels(false); } } -void UBScreenListLineEdit::onTextChanged(const QString &input) +void UBScreenListLineEdit::addScreen(const QString& screenIndex) { - const QStringList screenList = UBStringUtils::trimmed(input.split(',')); + qDebug() << "addScreen" << screenIndex; - for (QPushButton* button : std::as_const(mScreenLabels)) + QString list = text(); + mValidator->fixup(list); + + if (list.isEmpty()) { - button->setDisabled(screenList.contains(button->property("screenIndex").toString())); + setText(screenIndex); } - - if (input.isEmpty() || input.right(1) == ',') + else { - // create and attach a new QCompleter - QStringList model; - - for (QPushButton* button : std::as_const(mScreenLabels)) - { - if (button->isEnabled()) - { - model << input + button->property("screenIndex").toString(); - } - } + setText(list + "," + screenIndex); } +} + +void UBScreenListLineEdit::onTextChanged(const QString &input) +{ + const QStringList screenList = UBStringUtils::trimmed(input.split(',')); // user indication of acceptable input if (hasAcceptableInput()) { setStyleSheet(""); emit screenListChanged(screenList); + + QTimer::singleShot(100, this, [this](){ + // keep focus + activateWindow(); + }); } else { diff --git a/src/core/UBPreferencesController.h b/src/core/UBPreferencesController.h index d89b4c181..a244177cc 100644 --- a/src/core/UBPreferencesController.h +++ b/src/core/UBPreferencesController.h @@ -149,11 +149,10 @@ class UBScreenListLineEdit : public QLineEdit void screenListChanged(QStringList screenList); private slots: - void addScreen(); + void addScreen(const QString& screenIndex); void onTextChanged(const QString& input); private: - QList mScreenLabels; UBStringListValidator* mValidator; }; From 2bb4b4ca77833d20be1e61c65b2ea811226294c8 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 3 Aug 2025 11:34:30 +0200 Subject: [PATCH 080/133] feat: keep desktop mode palette always on top with KDE - on Wayland, a window cannot easily be defined to stay on top - with KDE, we now run a KWin script to accomplish this Signed-off-by: letsfindaway --- CMakeLists.txt | 1 + resources/etc/kwinKeepAbove.js | 23 ++++++++++++++++++ src/desktop/UBDesktopAnnotationController.cpp | 5 ++++ src/frameworks/UBDesktopPortal.cpp | 7 ++++++ src/frameworks/UBPlatformUtils.h | 1 + src/frameworks/UBPlatformUtils_linux.cpp | 24 +++++++++++++++++++ 6 files changed, 61 insertions(+) create mode 100644 resources/etc/kwinKeepAbove.js diff --git a/CMakeLists.txt b/CMakeLists.txt index 196e49cb7..b028ee335 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,7 @@ set(OPENBOARD_ETC_FILE ${OPENBOARD_ETC_DIR}/OpenBoard.config ${OPENBOARD_ETC_DIR}/OpenBoard.css ${OPENBOARD_ETC_DIR}/widgets.md5sum) set(OPENBOARD_TEMPLATE_FILE ${OPENBOARD_ETC_DIR}/asyncAPI.js + ${OPENBOARD_ETC_DIR}/kwinKeepAbove.js ${OPENBOARD_ETC_DIR}/intranet-podcast-metadata.template) set(OPENBOARD_ICON_FILE resources/images/ch.openboard.OpenBoard.svg) diff --git a/resources/etc/kwinKeepAbove.js b/resources/etc/kwinKeepAbove.js new file mode 100644 index 000000000..c79e9fcb2 --- /dev/null +++ b/resources/etc/kwinKeepAbove.js @@ -0,0 +1,23 @@ +/* + * Set keepAbove for OpenBoard DesktopView + * + * Works with KDE 5 and KDE 6 + */ + +function keepOnTop() { + // KDE 6 property + var allClients = workspace.stackingOrder; + + if (!allClients) { + // KDE 5 function + allClients = workspace.clientList(); + } + for (var i = 0; i < allClients.length; ++i) { + var client = allClients[i]; + if (client.resourceClass == "org.oe-f.openboard" && client.caption == "DesktopView") { + client.keepAbove=true; + } + } +} + +keepOnTop(); diff --git a/src/desktop/UBDesktopAnnotationController.cpp b/src/desktop/UBDesktopAnnotationController.cpp index c0ef7d49c..48f232219 100644 --- a/src/desktop/UBDesktopAnnotationController.cpp +++ b/src/desktop/UBDesktopAnnotationController.cpp @@ -79,6 +79,7 @@ UBDesktopAnnotationController::UBDesktopAnnotationController(QObject *parent, UB { mTransparentDrawingView = new UBBoardView(UBApplication::boardController, static_cast(0), false, true); // deleted in UBDesktopAnnotationController::destructor + mTransparentDrawingView->setWindowTitle("DesktopView"); mTransparentDrawingView->setAttribute(Qt::WA_TranslucentBackground, true); #ifdef Q_OS_OSX // didn't find the equivalent in Qt6 @@ -350,6 +351,10 @@ void UBDesktopAnnotationController::showWindow() #ifdef UB_REQUIRES_MASK_UPDATE updateMask(true); #endif // UB_REQUIRES_MASK_UPDATE + +#ifdef Q_OS_LINUX + UBPlatformUtils::keepOnTop(); +#endif } diff --git a/src/frameworks/UBDesktopPortal.cpp b/src/frameworks/UBDesktopPortal.cpp index 8188e122e..99015abe1 100644 --- a/src/frameworks/UBDesktopPortal.cpp +++ b/src/frameworks/UBDesktopPortal.cpp @@ -32,6 +32,8 @@ #include "core/UBApplicationController.h" #include "core/UBSettings.h" #include "desktop/UBDesktopAnnotationController.h" +#include "frameworks/UBPlatformUtils.h" + enum : uint { MONITOR = 1, WINDOW = 2, VIRTUAL = 4 } SourceType; enum : uint { HIDDEN = 1, EMBEDDED = 2, METADATA = 4 } CursorMode; @@ -373,5 +375,10 @@ void UBDesktopPortal::showGlassPane(bool show) const if (UBApplication::applicationController->isShowingDesktop()) { UBApplication::applicationController->uninotesController()->drawingView()->setVisible(show); + + if (show) + { + UBPlatformUtils::keepOnTop(); + } } } diff --git a/src/frameworks/UBPlatformUtils.h b/src/frameworks/UBPlatformUtils.h index 38a11814f..b090c723c 100644 --- a/src/frameworks/UBPlatformUtils.h +++ b/src/frameworks/UBPlatformUtils.h @@ -229,6 +229,7 @@ class UBPlatformUtils #ifdef Q_OS_LINUX static SessionType sessionType(); + static void keepOnTop(); #else static SessionType sessionType() { return UNKNOWN; } #endif diff --git a/src/frameworks/UBPlatformUtils_linux.cpp b/src/frameworks/UBPlatformUtils_linux.cpp index ee175a1d6..401139a6e 100644 --- a/src/frameworks/UBPlatformUtils_linux.cpp +++ b/src/frameworks/UBPlatformUtils_linux.cpp @@ -582,6 +582,30 @@ UBPlatformUtils::SessionType UBPlatformUtils::sessionType() return UNKNOWN; } +void UBPlatformUtils::keepOnTop() +{ + if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.KWin")) + { + QTimer::singleShot(500, [](){ + // keep desktop window on top for KDE environments + QDBusInterface scripting("org.kde.KWin", "/Scripting"); + auto result = scripting.callWithArgumentList(QDBus::Block, "loadScript", {applicationTemplateDirectory() + "/kwinKeepAbove.js"}); + + if (result.type() != QDBusMessage::ReplyMessage || result.arguments().empty() || !result.arguments().first().canConvert()) + { + qDebug() << "Failed loading KWin script"; + return; + } + + auto path = "/" + result.arguments().first().toString(); + + QDBusInterface script("org.kde.KWin", path); + script.call("run"); + script.call("stop"); + }); + } +} + OnboardListener::OnboardListener(const QDBusConnection& connection, QObject* parent) : QObject{parent} , mConnection{connection} From 301aba5722dc67b45602afdc287654018c220a53 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 11 Aug 2025 11:40:33 +0200 Subject: [PATCH 081/133] fix: screen positioning after settings change - reposition sccreens only after dialog is closed - hide windows before repositioning on wayland Signed-off-by: letsfindaway --- src/core/UBDisplayManager.cpp | 24 ++++++++++++++++++++++++ src/core/UBPreferencesController.cpp | 8 +++++++- src/core/UBPreferencesController.h | 1 + 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/core/UBDisplayManager.cpp b/src/core/UBDisplayManager.cpp index 51b7252fd..f8c47dd37 100644 --- a/src/core/UBDisplayManager.cpp +++ b/src/core/UBDisplayManager.cpp @@ -374,6 +374,30 @@ QList UBDisplayManager::availableScreens() const void UBDisplayManager::adjustScreens() { assignRoles(); + + if (UBPlatformUtils::sessionType() == UBPlatformUtils::SessionType::WAYLAND) + { + auto controlWidget = widget(ScreenRole::Control); + + // hide windows for repositioning + if (controlWidget && hasControl() && controlWidget->isVisible()) + { + for (auto widget : mWidgetsByRole) + { + if (widget) + { + widget->hide(); + } + } + + QTimer::singleShot(100, this, [this](){ + positionScreens(); + }); + + return; + } + } + positionScreens(); } diff --git a/src/core/UBPreferencesController.cpp b/src/core/UBPreferencesController.cpp index f4aa59ec3..b65283059 100644 --- a/src/core/UBPreferencesController.cpp +++ b/src/core/UBPreferencesController.cpp @@ -158,7 +158,7 @@ void UBPreferencesController::wire() connect(mPreferencesUI->defaultSettingsButton, SIGNAL(released()), this, SLOT(defaultSettings())); connect(mPreferencesUI->screenList, &UBScreenListLineEdit::screenListChanged, this, [this,settings](const QStringList screenList){ - settings->appScreenList->set(screenList); + mScreenList = screenList; if (!mScreenConfigurationPath.isEmpty()) { @@ -362,6 +362,12 @@ void UBPreferencesController::close() UBSettings::settings()->setProxyUsername(mPreferencesUI->proxyUsername->text()); UBSettings::settings()->setProxyPassword(mPreferencesUI->proxyPassword->text()); + // screen settings + if (mScreenList != UBSettings::settings()->appScreenList->get().toStringList()) + { + UBSettings::settings()->appScreenList->set(mScreenList); + } + mPreferencesWindow->accept(); } diff --git a/src/core/UBPreferencesController.h b/src/core/UBPreferencesController.h index a244177cc..8758cfcb5 100644 --- a/src/core/UBPreferencesController.h +++ b/src/core/UBPreferencesController.h @@ -87,6 +87,7 @@ class UBPreferencesController : public QObject UBColorPicker* mDarkBackgroundGridColorPicker; UBColorPicker* mLightBackgroundGridColorPicker; QString mScreenConfigurationPath; + QStringList mScreenList; protected slots: From 5a7e6dc4a302ee075e0fad1a39824b71bfe45aa5 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sat, 16 Aug 2025 17:13:43 +0200 Subject: [PATCH 082/133] fix: built-in onscreen keyboard on wayland - avoid and remove dependency to X11 - send key events as QKeyEvent instead of X11 events - works both for X11 and wayland Signed-off-by: letsfindaway --- CMakeLists.txt | 1 - OpenBoard.pro | 1 - cmake/DependencyX11.cmake | 18 -- src/frameworks/UBPlatformUtils_linux.cpp | 91 +++++---- src/gui/UBKeyboardPalette_linux.cpp | 245 ++--------------------- 5 files changed, 64 insertions(+), 292 deletions(-) delete mode 100644 cmake/DependencyX11.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index b028ee335..982188442 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,7 +115,6 @@ include(cmake/DependencyZlib.cmake) include(cmake/DependencyQuaZip.cmake) include(cmake/DependencyFFmpeg.cmake) include(cmake/DependencyPipewire.cmake) -include(cmake/DependencyX11.cmake) # add source path to include directories target_include_directories(${PROJECT_NAME} PRIVATE diff --git a/OpenBoard.pro b/OpenBoard.pro index af1c166b2..c86394d3c 100644 --- a/OpenBoard.pro +++ b/OpenBoard.pro @@ -455,7 +455,6 @@ linux-g++* { CONFIG += link_prl LIBS += -lcrypto #LIBS += -lprofiler - LIBS += -lX11 greaterThan(QT_MAJOR_VERSION, 5) { LIBS += -lquazip1-qt6 diff --git a/cmake/DependencyX11.cmake b/cmake/DependencyX11.cmake deleted file mode 100644 index f630160b7..000000000 --- a/cmake/DependencyX11.cmake +++ /dev/null @@ -1,18 +0,0 @@ -# Find FFmpeg - -find_package(X11 QUIET) - -if (X11_FOUND) - target_link_libraries(${PROJECT_NAME} - X11 - ) -else() - find_package(PkgConfig REQUIRED) - pkg_check_modules(X11 REQUIRED x11) - - if (X11_FOUND) - target_link_libraries(${PROJECT_NAME} - PkgConfig::X11 - ) - endif() -endif() diff --git a/src/frameworks/UBPlatformUtils_linux.cpp b/src/frameworks/UBPlatformUtils_linux.cpp index 401139a6e..62e804ebb 100644 --- a/src/frameworks/UBPlatformUtils_linux.cpp +++ b/src/frameworks/UBPlatformUtils_linux.cpp @@ -35,7 +35,6 @@ #include #include -#include #include "frameworks/UBDesktopPortal.h" #include "frameworks/UBFileSystemUtils.h" @@ -118,12 +117,17 @@ void UBPlatformUtils::fadeDisplayIn() bool UBPlatformUtils::hasSystemOnScreenKeyboard() { - QProcess oskTestProcess; - oskTestProcess.start("which", QStringList() << "onboard"); + if (sessionType() == X11) + { + QProcess oskTestProcess; + oskTestProcess.start("which", QStringList() << "onboard"); + + return oskTestProcess.waitForFinished() && + oskTestProcess.exitStatus() == QProcess::NormalExit && + oskTestProcess.readAll() != ""; + } - return oskTestProcess.waitForFinished() && - oskTestProcess.exitStatus() == QProcess::NormalExit && - oskTestProcess.readAll() != ""; + return false; } QStringList UBPlatformUtils::availableTranslations() @@ -183,12 +187,7 @@ void UBPlatformUtils::hideMenuBarAndDock() } #define KEYBTDECL(s1, s2, clSwitch, code) KEYBT(QChar(s1), QChar(s2), clSwitch, 0, 0, KEYCODE(s1, code, 0), KEYCODE(s2, code, 1)) - -#define KEYBTDECLEX1(s1, s2, clSwitch, code, cs1, cs2) KEYBT(QChar(s1), QChar(s2), clSwitch, 0, 0, KEYCODE(cs1, code, 0), KEYCODE(cs2, code, 1)) -#define KEYBTDECLEX2(s1, s2, clSwitch, code, cs1, cs2) KEYBT(QChar(s1), QChar(s2), clSwitch, 0, 0, KEYCODE(cs1, code, 2), KEYCODE(cs2, code, 3)) - #define KEYBTDECLEX6(s1, s2, clSwitch, code, cs1, cs2, cs3, cs4, cs5, cs6) KEYBT(QChar(s1), QChar(s2), clSwitch, 0, 0, KEYCODE(cs1, code, 0), KEYCODE(cs2, code, 1), KEYCODE(cs3, code, 2), KEYCODE(cs4, code, 3), KEYCODE(cs5, code, 4), KEYCODE(cs6, code, 5)) - #define KEYBTDECLEX8(s1, s2, clSwitch, code, cs1, cs2, cs3, cs4, cs5, cs6, cs7, cs8) KEYBT(QChar(s1), QChar(s2), clSwitch, 0, 0, KEYCODE(cs1, code, 0), KEYCODE(cs2, code, 1), KEYCODE(cs3, code, 2), KEYCODE(cs4, code, 3), KEYCODE(cs5, code, 4), KEYCODE(cs6, code, 5), KEYCODE(cs7, code, 6), KEYCODE(cs8, code, 7)) @@ -246,10 +245,10 @@ KEYBT ENGLISH_LOCALE[] = { KEYBT RUSSIAN_LOCALE [] = { - /* ё Ё */ KEYBTDECLEX2(0x451, 0x401, true, 41, XK_Cyrillic_io, XK_Cyrillic_IO), + /* ё Ё */ KEYBTDECL(0x451, 0x401, true, 41), /* 1 ! */ KEYBTDECL(0x31, 0x21, false, 2), /* 2 " */ KEYBTDECL(0x32, 0x5c, false, 3), - /* 3 № */ KEYBTDECLEX1(0x33, 0x2116, false, 4, 0x33, XK_numerosign), + /* 3 № */ KEYBTDECL(0x33, 0x2116, false, 4), /* 4 ; */ KEYBTDECL(0x34, 0x3b, false, 5), /* 5 % */ KEYBTDECL(0x35, 0x25, false, 6), /* 6 : */ KEYBTDECL(0x36, 0x3a, false, 7), @@ -260,41 +259,41 @@ KEYBT RUSSIAN_LOCALE [] = /* - _ */ KEYBTDECL(0x2d, 0x4f, false, 12), /* = + */ KEYBTDECL(0x3d, 0x2b, false, 13), - /* й Й */ KEYBTDECLEX2(0x439, 0x419, true, 16, XK_Cyrillic_shorti, XK_Cyrillic_SHORTI), - /* ц Ц */ KEYBTDECLEX2(0x446, 0x426, true, 17, XK_Cyrillic_tse, XK_Cyrillic_TSE), - /* у У */ KEYBTDECLEX2(0x443, 0x423, true, 18, XK_Cyrillic_u, XK_Cyrillic_U), - /* к К */ KEYBTDECLEX2(0x43a, 0x41a, true, 19, XK_Cyrillic_ka, XK_Cyrillic_KA), - /* е Е */ KEYBTDECLEX2(0x435, 0x415, true, 20, XK_Cyrillic_ie, XK_Cyrillic_IE), - /* н Н */ KEYBTDECLEX2(0x43d, 0x41d, true, 21, XK_Cyrillic_en, XK_Cyrillic_EN), - /* г Г */ KEYBTDECLEX2(0x433, 0x413, true, 22, XK_Cyrillic_ghe, XK_Cyrillic_GHE), - /* ш Ш */ KEYBTDECLEX2(0x448, 0x428, true, 23, XK_Cyrillic_sha, XK_Cyrillic_SHA), - /* щ Щ */ KEYBTDECLEX2(0x449, 0x429, true, 24, XK_Cyrillic_shcha, XK_Cyrillic_SHCHA), - /* з З */ KEYBTDECLEX2(0x437, 0x417, true, 25, XK_Cyrillic_ze, XK_Cyrillic_ZE), - /* х Х */ KEYBTDECLEX2(0x445, 0x425, true, 26, XK_Cyrillic_ha, XK_Cyrillic_HA), - /* ъ Ъ */ KEYBTDECLEX2(0x44a, 0x42a, true, 27, XK_Cyrillic_hardsign, XK_Cyrillic_HARDSIGN), - - /* ф Ф */ KEYBTDECLEX2(0x444, 0x424, true, 30, XK_Cyrillic_ef, XK_Cyrillic_EF), - /* ы Ы */ KEYBTDECLEX2(0x44b, 0x42b, true, 31, XK_Cyrillic_yeru, XK_Cyrillic_YERU), - /* в В */ KEYBTDECLEX2(0x432, 0x412, true, 32, XK_Cyrillic_ve, XK_Cyrillic_VE), - /* а А */ KEYBTDECLEX2(0x430, 0x410, true, 33, XK_Cyrillic_a, XK_Cyrillic_A), - /* п П */ KEYBTDECLEX2(0x43f, 0x41f, true, 34, XK_Cyrillic_pe, XK_Cyrillic_PE), - /* р Р */ KEYBTDECLEX2(0x440, 0x420, true, 35, XK_Cyrillic_er, XK_Cyrillic_ER), - /* о О */ KEYBTDECLEX2(0x43e, 0x41e, true, 36, XK_Cyrillic_o, XK_Cyrillic_O), - /* л Л */ KEYBTDECLEX2(0x43b, 0x41b, true, 37, XK_Cyrillic_el, XK_Cyrillic_EL), - /* д Д */ KEYBTDECLEX2(0x434, 0x414, true, 38, XK_Cyrillic_de, XK_Cyrillic_DE), - /* ж Ж */ KEYBTDECLEX2(0x436, 0x416, true, 39, XK_Cyrillic_zhe, XK_Cyrillic_ZHE), - /* э Э */ KEYBTDECLEX2(0x44d, 0x42d, true, 40, XK_Cyrillic_e, XK_Cyrillic_E), + /* й Й */ KEYBTDECL(0x439, 0x419, true, 16), + /* ц Ц */ KEYBTDECL(0x446, 0x426, true, 17), + /* у У */ KEYBTDECL(0x443, 0x423, true, 18), + /* к К */ KEYBTDECL(0x43a, 0x41a, true, 19), + /* е Е */ KEYBTDECL(0x435, 0x415, true, 20), + /* н Н */ KEYBTDECL(0x43d, 0x41d, true, 21), + /* г Г */ KEYBTDECL(0x433, 0x413, true, 22), + /* ш Ш */ KEYBTDECL(0x448, 0x428, true, 23), + /* щ Щ */ KEYBTDECL(0x449, 0x429, true, 24), + /* з З */ KEYBTDECL(0x437, 0x417, true, 25), + /* х Х */ KEYBTDECL(0x445, 0x425, true, 26), + /* ъ Ъ */ KEYBTDECL(0x44a, 0x42a, true, 27), + + /* ф Ф */ KEYBTDECL(0x444, 0x424, true, 30), + /* ы Ы */ KEYBTDECL(0x44b, 0x42b, true, 31), + /* в В */ KEYBTDECL(0x432, 0x412, true, 32), + /* а А */ KEYBTDECL(0x430, 0x410, true, 33), + /* п П */ KEYBTDECL(0x43f, 0x41f, true, 34), + /* р Р */ KEYBTDECL(0x440, 0x420, true, 35), + /* о О */ KEYBTDECL(0x43e, 0x41e, true, 36), + /* л Л */ KEYBTDECL(0x43b, 0x41b, true, 37), + /* д Д */ KEYBTDECL(0x434, 0x414, true, 38), + /* ж Ж */ KEYBTDECL(0x436, 0x416, true, 39), + /* э Э */ KEYBTDECL(0x44d, 0x42d, true, 40), /* \ / */ KEYBTDECL(0x5c, 0x2f, false, 43), - /* я Я */ KEYBTDECLEX2(0x44f, 0x42f, true, 44, XK_Cyrillic_ya, XK_Cyrillic_YA), - /* ч Ч */ KEYBTDECLEX2(0x447, 0x427, true, 45, XK_Cyrillic_che, XK_Cyrillic_CHE), - /* с С */ KEYBTDECLEX2(0x441, 0x421, true, 46, XK_Cyrillic_es, XK_Cyrillic_ES), - /* м М */ KEYBTDECLEX2(0x43c, 0x41c, true, 47, XK_Cyrillic_em, XK_Cyrillic_EM), - /* и И */ KEYBTDECLEX2(0x438, 0x418, true, 48, XK_Cyrillic_i, XK_Cyrillic_I), - /* т Т */ KEYBTDECLEX2(0x442, 0x422, true, 49, XK_Cyrillic_te, XK_Cyrillic_TE), - /* ь Ь */ KEYBTDECLEX2(0x44c, 0x42c, true, 50, XK_Cyrillic_softsign, XK_Cyrillic_SOFTSIGN), - /* б Б */ KEYBTDECLEX2(0x431, 0x411, true, 51, XK_Cyrillic_be, XK_Cyrillic_BE), - /* ю Ю */ KEYBTDECLEX2(0x44e, 0x42e, true, 52, XK_Cyrillic_yu, XK_Cyrillic_YU), + /* я Я */ KEYBTDECL(0x44f, 0x42f, true, 44), + /* ч Ч */ KEYBTDECL(0x447, 0x427, true, 45), + /* с С */ KEYBTDECL(0x441, 0x421, true, 46), + /* м М */ KEYBTDECL(0x43c, 0x41c, true, 47), + /* и И */ KEYBTDECL(0x438, 0x418, true, 48), + /* т Т */ KEYBTDECL(0x442, 0x422, true, 49), + /* ь Ь */ KEYBTDECL(0x44c, 0x42c, true, 50), + /* б Б */ KEYBTDECL(0x431, 0x411, true, 51), + /* ю Ю */ KEYBTDECL(0x44e, 0x42e, true, 52), /* . , */ KEYBTDECL(0x2e, 0x2c, false, 53)}; KEYBT GERMAN_LOCALE[] = { diff --git a/src/gui/UBKeyboardPalette_linux.cpp b/src/gui/UBKeyboardPalette_linux.cpp index 5a92b551d..5f0f8495e 100644 --- a/src/gui/UBKeyboardPalette_linux.cpp +++ b/src/gui/UBKeyboardPalette_linux.cpp @@ -29,152 +29,47 @@ #include "UBKeyboardPalette.h" -#include -#include - - -// The key code to be sent. -// A full list of available codes can be found in /usr/include/X11/keysymdef.h -//#define KEYCODE XK_Down - -// Function to create a keyboard event -XKeyEvent createKeyEvent(Display *display, Window &win, - Window &winRoot, bool press, - int keycode, int modifiers) -{ - XKeyEvent event; - - event.display = display; - event.window = win; - event.root = winRoot; - event.subwindow = None; - event.time = CurrentTime; - event.x = 1; - event.y = 1; - event.x_root = 1; - event.y_root = 1; - event.same_screen = True; - event.keycode = keycode; - event.state = modifiers; - - if(press) - event.type = KeyPress; - else - event.type = KeyRelease; - - return event; -} - -void x11SendKey(Display *display, int keyCode, int modifiers) -{ - -// Get the root window for the current display. - Window winRoot = XDefaultRootWindow(display); - if (winRoot==0) - return; - -// Find the window which has the current keyboard focus. - Window winFocus; - int revert; - XGetInputFocus(display, &winFocus, &revert); - -// Send a fake key press event to the window. - XKeyEvent event = createKeyEvent(display, winFocus, winRoot, true, keyCode, modifiers); - XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event); - -// Send a fake key release event to the window. - event = createKeyEvent(display, winFocus, winRoot, false, keyCode, modifiers); - XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event); - -} - -/* -void traceKeyCodes() -{ - Display *display = XOpenDisplay(0); - if(display == NULL) - return; - - int min_keycodes, max_keycodes, byte_per_code; - - XDisplayKeycodes(display, &min_keycodes, &max_keycodes); - KeySym* keySyms = XGetKeyboardMapping(display, min_keycodes, - max_keycodes - min_keycodes, &byte_per_code); - - qDebug() << "Codes table, min_keycodes: " << min_keycodes << ", max_keycodes: " - << max_keycodes << ", bytes_per_code:" << byte_per_code; - for(int i=0; imin_keycodes , modifier); - } - - XCloseDisplay(display); + auto focusObject = QGuiApplication::focusObject(); + auto key = keycode.symbol; + QString keyStr = QChar(key); + QKeyEvent pressEvent = QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier, keyStr); + QKeyEvent releaseEvent = QKeyEvent(QEvent::KeyRelease, key, Qt::NoModifier); + QCoreApplication::sendEvent(focusObject, &pressEvent); + QCoreApplication::sendEvent(focusObject, &releaseEvent); } void UBKeyboardButton::sendControlSymbol(int nSymbol) { - // Obtain the X11 display. - Display *display = XOpenDisplay(0); - if(display == NULL) - return; - + auto focusObject = QGuiApplication::focusObject(); + QString keyStr; - KeyCode keyCode = XKeysymToKeycode(display, nSymbol); - - if (keyCode != NoSymbol) + if (nSymbol == Qt::Key_Space) { - x11SendKey(display, keyCode, 0); + keyStr = " "; } - XCloseDisplay(display); + QKeyEvent pressEvent = QKeyEvent(QEvent::KeyPress, nSymbol, Qt::NoModifier, keyStr); + QKeyEvent releaseEvent = QKeyEvent(QEvent::KeyRelease, nSymbol, Qt::NoModifier); + QCoreApplication::sendEvent(focusObject, &pressEvent); + QCoreApplication::sendEvent(focusObject, &releaseEvent); } void UBKeyboardPalette::createCtrlButtons() { ctrlButtons = new UBKeyboardButton*[9]; - ctrlButtons[0] = new UBCntrlButton(this, XK_BackSpace, "backspace"); - ctrlButtons[1] = new UBCntrlButton(this, XK_Tab, "tab"); + ctrlButtons[0] = new UBCntrlButton(this, Qt::Key_Backspace, "backspace"); + ctrlButtons[1] = new UBCntrlButton(this, Qt::Key_Tab, "tab"); ctrlButtons[2] = new UBCapsLockButton(this, "capslock"); - ctrlButtons[3] = new UBCntrlButton(this, tr("Enter"), XK_Return); + ctrlButtons[3] = new UBCntrlButton(this, tr("Enter"), Qt::Key_Return); ctrlButtons[4] = new UBShiftButton(this, "shift"); ctrlButtons[5] = new UBShiftButton(this, "shift"); ctrlButtons[6] = new UBLocaleButton(this); - ctrlButtons[7] = new UBCntrlButton(this, "", XK_space); + ctrlButtons[7] = new UBCntrlButton(this, "", Qt::Key_Space); ctrlButtons[8] = new UBLocaleButton(this); } @@ -184,110 +79,8 @@ void UBKeyboardPalette::checkLayout() void UBKeyboardPalette::onActivated(bool activated) { - if (activated) - { - if (storage) - { - qDebug() << "Keybard already activated...."; - return; - } - - Display *display = XOpenDisplay(0); - if(display == NULL) - return; - - XDisplayKeycodes(display, &this->min_keycodes, &this->max_keycodes); - KeySym* keySyms = XGetKeyboardMapping(display, min_keycodes, - max_keycodes - min_keycodes, &byte_per_code); - - storage = keySyms; - - XCloseDisplay(display); - - onLocaleChanged(locales[nCurrentLocale]); - - } - else - { - Display *display = XOpenDisplay(0); - if(display == NULL) - { - qDebug() << "Keybard not activated...."; - return; - } - - KeySym* keySyms = (KeySym*)storage; - if (keySyms!=NULL) - { - qDebug() << "Default key table restored....."; - - XChangeKeyboardMapping(display, min_keycodes, byte_per_code, - keySyms, max_keycodes - min_keycodes); - - XFree(keySyms); - storage = NULL; - } - - XCloseDisplay(display); - } } void UBKeyboardPalette::onLocaleChanged(UBKeyboardLocale* locale) { - const int maxMapOffset = 3; //Suppose to have at least 2 keysym groups due to X11 xlib specification - - Display *display = XOpenDisplay(0); - if(display == NULL) - return; - - int byte_per_code; - KeySym* keySyms = XGetKeyboardMapping(display, min_keycodes, - max_keycodes - min_keycodes, &byte_per_code); - - for(int i=0; icodes[j]; - if (!kc.empty()) - { - if (kc.modifier <= maxMapOffset) - keySyms[kc.code * byte_per_code + kc.modifier] = kc.symbol; - - } - } - } - - //Now look for modifiers > 5 and reassign them to free places - for(int i=0; icodes[j]; - if (!kc.empty()) - { - if (kc.modifier > maxMapOffset) - { - for(int i1=0; i1 Date: Mon, 18 Aug 2025 10:54:20 +0200 Subject: [PATCH 083/133] fix: application icon on Wayland - use application icon in task bar on Wayland - set desktop file name to point to icon - adjust KWin script accordingly Signed-off-by: letsfindaway --- resources/etc/kwinKeepAbove.js | 2 +- src/core/UBApplication.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/etc/kwinKeepAbove.js b/resources/etc/kwinKeepAbove.js index c79e9fcb2..90c27ab36 100644 --- a/resources/etc/kwinKeepAbove.js +++ b/resources/etc/kwinKeepAbove.js @@ -14,7 +14,7 @@ function keepOnTop() { } for (var i = 0; i < allClients.length; ++i) { var client = allClients[i]; - if (client.resourceClass == "org.oe-f.openboard" && client.caption == "DesktopView") { + if (client.resourceClass == "ch.openboard.OpenBoard" && client.caption == "DesktopView") { client.keepAbove=true; } } diff --git a/src/core/UBApplication.cpp b/src/core/UBApplication.cpp index 640fad511..bf6d87ad2 100644 --- a/src/core/UBApplication.cpp +++ b/src/core/UBApplication.cpp @@ -106,6 +106,7 @@ UBApplication::UBApplication(const QString &id, int &argc, char **argv) : Single setOrganizationName("Open Education Foundation"); setOrganizationDomain("oe-f.org"); setApplicationName("OpenBoard"); + setDesktopFileName("ch.openboard.OpenBoard"); #ifdef Q_OS_OSX // With Qt 6.9 on macOS 15 (at least), icons aren't shown in menus. This forces their display. From 02819ede38a05bafb6151f078849f5b5a5b5f1e4 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Thu, 1 Feb 2024 12:31:09 +0100 Subject: [PATCH 084/133] feat: add flexible background rulings - add UBBackgroundRulings to read/write/keep a ruling description - add UBBackgroundManager to manage UBBackgroundRulings - add XML schema for ruling descriptions - add initial set of rulings - provide compatibility with legacy background flags - save and load rulings in document pages --- CMakeLists.txt | 2 + resources/OpenBoard.qrc | 18 +- resources/etc/background/01_blank.xml | 26 + resources/etc/background/02_ruled.xml | 14 + resources/etc/background/03_crossed.xml | 22 + resources/etc/background/04_crossed5.xml | 38 + resources/etc/background/05_seyes.xml | 70 ++ resources/etc/background/06_staveBorder.xml | 38 + resources/etc/background/background.xsd | 122 +++ .../background/bgButtonTemplateDarkOff.svg | 51 + .../etc/background/bgButtonTemplateDarkOn.svg | 52 + .../background/bgButtonTemplateLightOff.svg | 51 + .../background/bgButtonTemplateLightOn.svg | 52 + resources/etc/background/crossed1.xml | 166 +++ resources/etc/background/de-primary1.xml | 33 + resources/etc/background/de-primary2.xml | 33 + resources/etc/background/de-primary3.xml | 25 + resources/etc/background/isometric.xml | 30 + resources/etc/background/ruled5.xml | 22 + resources/etc/background/stave.xml | 30 + resources/forms/mainWindow.ui | 162 +-- .../images/backgroundPalette/background1.svg | 64 -- .../backgroundPalette/background1On.svg | 41 - .../images/backgroundPalette/background2.svg | 71 -- .../backgroundPalette/background2On.svg | 73 -- .../images/backgroundPalette/background3.svg | 64 -- .../backgroundPalette/background3On.svg | 66 -- .../images/backgroundPalette/background4.svg | 133 --- .../backgroundPalette/background4On.svg | 73 -- .../images/backgroundPalette/background5.svg | 146 --- .../backgroundPalette/background5On.svg | 149 --- .../images/backgroundPalette/background6.svg | 146 --- .../backgroundPalette/background6On.svg | 150 --- .../images/backgroundPalette/background7.svg | 177 ---- .../backgroundPalette/background7On.svg | 180 ---- .../images/backgroundPalette/background8.svg | 177 ---- .../backgroundPalette/background8On.svg | 220 ---- resources/images/darkMode.svg | 16 + resources/images/lightMode.svg | 16 + src/adaptors/UBExportFullPDF.cpp | 10 +- src/adaptors/UBExportPDF.cpp | 8 +- src/adaptors/UBSvgSubsetAdaptor.cpp | 61 +- src/api/UBWidgetUniboardAPI.cpp | 8 +- src/board/UBBoardController.cpp | 66 +- src/board/UBBoardController.h | 11 +- src/board/UBBoardPaletteManager.cpp | 50 +- src/board/UBBoardPaletteManager.h | 2 - src/core/UB.h | 7 - src/core/UBApplicationController.cpp | 2 +- src/core/UBPersistenceManager.cpp | 6 +- src/core/UBSettings.cpp | 36 +- src/core/UBSettings.h | 7 +- src/core/UBShortcutManager.cpp | 8 +- src/desktop/UBDesktopAnnotationController.cpp | 4 +- src/domain/UBGraphicsScene.cpp | 146 +-- src/domain/UBGraphicsScene.h | 17 +- src/gui/CMakeLists.txt | 4 + src/gui/UBActionPalette.cpp | 11 +- src/gui/UBBackgroundManager.cpp | 227 +++++ src/gui/UBBackgroundManager.h | 33 + src/gui/UBBackgroundPalette.cpp | 108 +- src/gui/UBBackgroundPalette.h | 18 +- src/gui/UBBackgroundRuling.cpp | 957 ++++++++++++++++++ src/gui/UBBackgroundRuling.h | 168 +++ src/gui/gui.pri | 5 + 65 files changed, 2522 insertions(+), 2477 deletions(-) create mode 100644 resources/etc/background/01_blank.xml create mode 100644 resources/etc/background/02_ruled.xml create mode 100644 resources/etc/background/03_crossed.xml create mode 100644 resources/etc/background/04_crossed5.xml create mode 100644 resources/etc/background/05_seyes.xml create mode 100644 resources/etc/background/06_staveBorder.xml create mode 100644 resources/etc/background/background.xsd create mode 100644 resources/etc/background/bgButtonTemplateDarkOff.svg create mode 100644 resources/etc/background/bgButtonTemplateDarkOn.svg create mode 100644 resources/etc/background/bgButtonTemplateLightOff.svg create mode 100644 resources/etc/background/bgButtonTemplateLightOn.svg create mode 100644 resources/etc/background/crossed1.xml create mode 100644 resources/etc/background/de-primary1.xml create mode 100644 resources/etc/background/de-primary2.xml create mode 100644 resources/etc/background/de-primary3.xml create mode 100644 resources/etc/background/isometric.xml create mode 100644 resources/etc/background/ruled5.xml create mode 100644 resources/etc/background/stave.xml delete mode 100644 resources/images/backgroundPalette/background1.svg delete mode 100644 resources/images/backgroundPalette/background1On.svg delete mode 100644 resources/images/backgroundPalette/background2.svg delete mode 100644 resources/images/backgroundPalette/background2On.svg delete mode 100644 resources/images/backgroundPalette/background3.svg delete mode 100644 resources/images/backgroundPalette/background3On.svg delete mode 100644 resources/images/backgroundPalette/background4.svg delete mode 100644 resources/images/backgroundPalette/background4On.svg delete mode 100644 resources/images/backgroundPalette/background5.svg delete mode 100644 resources/images/backgroundPalette/background5On.svg delete mode 100644 resources/images/backgroundPalette/background6.svg delete mode 100644 resources/images/backgroundPalette/background6On.svg delete mode 100644 resources/images/backgroundPalette/background7.svg delete mode 100644 resources/images/backgroundPalette/background7On.svg delete mode 100644 resources/images/backgroundPalette/background8.svg delete mode 100644 resources/images/backgroundPalette/background8On.svg create mode 100644 resources/images/darkMode.svg create mode 100644 resources/images/lightMode.svg create mode 100644 src/gui/UBBackgroundManager.cpp create mode 100644 src/gui/UBBackgroundManager.h create mode 100644 src/gui/UBBackgroundRuling.cpp create mode 100644 src/gui/UBBackgroundRuling.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d87fcaee..acf647ef2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,7 @@ set(OPENBOARD_FORMS_DIR resources/forms src/web/simplebrowser) set(OPENBOARD_TS_DIR resources/i18n) set(OPENBOARD_FONT_DIR resources/customizations resources/fonts) set(OPENBOARD_ETC_DIR resources/etc) +set(OPENBOARD_BG_DIR resources/etc/background) set(OPENBOARD_LIBRARY_DIR resources/library) set(OPENBOARD_STARTUP_HINTS resources/startupHints) @@ -216,6 +217,7 @@ install(DIRECTORY ${OPENBOARD_FONT_DIR} DESTINATION ${OPENBOARD_INSTALL_ install(DIRECTORY ${OPENBOARD_LIBRARY_DIR} DESTINATION ${OPENBOARD_INSTALL_DATADIR}) install(DIRECTORY ${OPENBOARD_STARTUP_HINTS} DESTINATION ${OPENBOARD_INSTALL_DATADIR}) install(DIRECTORY ${PROJECT_BINARY_DIR}/i18n DESTINATION ${OPENBOARD_INSTALL_DATADIR}) +install(DIRECTORY ${OPENBOARD_BG_DIR} DESTINATION ${OPENBOARD_INSTALL_DATADIR}/template) install(FILES ${OPENBOARD_ETC_FILE} DESTINATION ${OPENBOARD_INSTALL_SYSCONFDIR}) install(FILES ${OPENBOARD_TEMPLATE_FILE} DESTINATION ${OPENBOARD_INSTALL_DATADIR}/template) install(FILES ${OPENBOARD_ICON_FILE} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps) diff --git a/resources/OpenBoard.qrc b/resources/OpenBoard.qrc index 6e817b3e6..1020ea5ed 100644 --- a/resources/OpenBoard.qrc +++ b/resources/OpenBoard.qrc @@ -153,22 +153,6 @@ images/stylusPalette/captureAreaOn.png images/stylusPalette/snap.svg images/stylusPalette/snapOn.svg - images/backgroundPalette/background1.svg - images/backgroundPalette/background1On.svg - images/backgroundPalette/background2.svg - images/backgroundPalette/background2On.svg - images/backgroundPalette/background3.svg - images/backgroundPalette/background3On.svg - images/backgroundPalette/background4.svg - images/backgroundPalette/background4On.svg - images/backgroundPalette/background5.svg - images/backgroundPalette/background5On.svg - images/backgroundPalette/background6.svg - images/backgroundPalette/background6On.svg - images/backgroundPalette/background7.svg - images/backgroundPalette/background7On.svg - images/backgroundPalette/background8.svg - images/backgroundPalette/background8On.svg images/toolPalette/podcast.svg images/toolPalette/podcastOn.svg images/toolPalette/rulerTool.png @@ -400,5 +384,7 @@ images/removeFromFavorites.png images/toolbar/tip.png images/moveTool.svg + images/lightMode.svg + images/darkMode.svg diff --git a/resources/etc/background/01_blank.xml b/resources/etc/background/01_blank.xml new file mode 100644 index 000000000..d76dc8a1c --- /dev/null +++ b/resources/etc/background/01_blank.xml @@ -0,0 +1,26 @@ + + 84836d5a-1846-4c91-9ff9-f2c4d118364d + Empty + Leer + + + #00000000 + #00000000 + + + 0 + 10 + + 0 + 1 + + + + 90 + 10 + + 0 + 1 + + + diff --git a/resources/etc/background/02_ruled.xml b/resources/etc/background/02_ruled.xml new file mode 100644 index 000000000..6abde93f0 --- /dev/null +++ b/resources/etc/background/02_ruled.xml @@ -0,0 +1,14 @@ + + 0de33238-c30e-4396-8ec4-2bfc53304389 + Ruled + Liniert + + + 0 + 10 + + 0 + 1 + + + diff --git a/resources/etc/background/03_crossed.xml b/resources/etc/background/03_crossed.xml new file mode 100644 index 000000000..0e8cc232d --- /dev/null +++ b/resources/etc/background/03_crossed.xml @@ -0,0 +1,22 @@ + + 7493c8bb-6d98-4be6-966c-fbddf9eff529 + Crossed + Kariert + + + 0 + 10 + + 0 + 1 + + + + 90 + 10 + + 0 + 1 + + + diff --git a/resources/etc/background/04_crossed5.xml b/resources/etc/background/04_crossed5.xml new file mode 100644 index 000000000..5930b73e6 --- /dev/null +++ b/resources/etc/background/04_crossed5.xml @@ -0,0 +1,38 @@ + + 8ed2037b-ab38-4d4f-9b52-c4e36b1c8102 + Crossed 5mm + Kariert 5mm + + + 0 + 10 + + 0 + 1 + + + 5 + 1 + + 0.5 + 0.5 + + + + + 90 + 10 + + 0 + 1 + + + 5 + 1 + + 0.5 + 0.5 + + + + diff --git a/resources/etc/background/05_seyes.xml b/resources/etc/background/05_seyes.xml new file mode 100644 index 000000000..cad1b5226 --- /dev/null +++ b/resources/etc/background/05_seyes.xml @@ -0,0 +1,70 @@ + + 38b45f18-f6a5-4336-ae91-bedba3a2442c + Seyes + + + 0 + 20 + + 0 + 2 + + #8e7cc3 + #8e7cc3 + + + + 5 + 2 + + #996fa8dc + #996fa8dc + + + + 10 + 2 + + #996fa8dc + #996fa8dc + + + + 15 + 2 + + #996fa8dc + #996fa8dc + + + + 0 + 0 + + + + 90 + 20 + topleft + + 0 + 2 + + #8e7cc3 + #8e7cc3 + + + + + 90 + topleft + + 20 + 2 + + #ff0000 + #ff0000 + + + + diff --git a/resources/etc/background/06_staveBorder.xml b/resources/etc/background/06_staveBorder.xml new file mode 100644 index 000000000..102540dca --- /dev/null +++ b/resources/etc/background/06_staveBorder.xml @@ -0,0 +1,38 @@ + + 1da51382-220e-40d2-804a-36ca2ab3fbd8 + Stave lines with border + Notenlinien mit Rand + Lignes de notes avec bordure + + 0 + 50 + + 0 + 1 + + + 5 + 1 + + + 10 + 1 + + + 15 + 1 + + + 20 + 1 + + + 5 + 5 + + 0 + 1 + + + + diff --git a/resources/etc/background/background.xsd b/resources/etc/background/background.xsd new file mode 100644 index 000000000..8ff787d21 --- /dev/null +++ b/resources/etc/background/background.xsd @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/etc/background/bgButtonTemplateDarkOff.svg b/resources/etc/background/bgButtonTemplateDarkOff.svg new file mode 100644 index 000000000..df2389127 --- /dev/null +++ b/resources/etc/background/bgButtonTemplateDarkOff.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/etc/background/bgButtonTemplateDarkOn.svg b/resources/etc/background/bgButtonTemplateDarkOn.svg new file mode 100644 index 000000000..ede9a1f6d --- /dev/null +++ b/resources/etc/background/bgButtonTemplateDarkOn.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/etc/background/bgButtonTemplateLightOff.svg b/resources/etc/background/bgButtonTemplateLightOff.svg new file mode 100644 index 000000000..c8282c6a5 --- /dev/null +++ b/resources/etc/background/bgButtonTemplateLightOff.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/etc/background/bgButtonTemplateLightOn.svg b/resources/etc/background/bgButtonTemplateLightOn.svg new file mode 100644 index 000000000..971f280c8 --- /dev/null +++ b/resources/etc/background/bgButtonTemplateLightOn.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/etc/background/crossed1.xml b/resources/etc/background/crossed1.xml new file mode 100644 index 000000000..8da7bf0f9 --- /dev/null +++ b/resources/etc/background/crossed1.xml @@ -0,0 +1,166 @@ + + 5daad8dd-1c41-4c37-9c14-2ab073c7249c + Crossed 1mm + Millimeterpapier + + + 0 + 10 + + 0 + 1 + + + 1 + 1 + + 0.4 + 0.4 + + + + 2 + 1 + + 0.4 + 0.4 + + + + 3 + 1 + + 0.4 + 0.4 + + + + 4 + 1 + + 0.4 + 0.4 + + + + 5 + 1 + + 0.6 + 0.6 + + + + 6 + 1 + + 0.4 + 0.4 + + + + 7 + 1 + + 0.4 + 0.4 + + + + 8 + 1 + + 0.4 + 0.4 + + + + 9 + 1 + + 0.4 + 0.4 + + + + + 90 + 10 + + 0 + 1 + + + 1 + 1 + + 0.4 + 0.4 + + + + 2 + 1 + + 0.4 + 0.4 + + + + 3 + 1 + + 0.4 + 0.4 + + + + 4 + 1 + + 0.4 + 0.4 + + + + 5 + 1 + + 0.6 + 0.6 + + + + 6 + 1 + + 0.4 + 0.4 + + + + 7 + 1 + + 0.4 + 0.4 + + + + 8 + 1 + + 0.4 + 0.4 + + + + 9 + 1 + + 0.4 + 0.4 + + + + diff --git a/resources/etc/background/de-primary1.xml b/resources/etc/background/de-primary1.xml new file mode 100644 index 000000000..6055a6b12 --- /dev/null +++ b/resources/etc/background/de-primary1.xml @@ -0,0 +1,33 @@ + + ca8931ff-19b6-4217-88f9-9f64ec366bfa + German elementary school, first grade + Grundschule, erste Klasse + + 0 + 20 + + 0 + 1 + + + 5 + 1 + + + 10 + 1 + + + 15 + 1 + + + 5 + 5 + + 0 + 1 + + + + diff --git a/resources/etc/background/de-primary2.xml b/resources/etc/background/de-primary2.xml new file mode 100644 index 000000000..f3d2d3399 --- /dev/null +++ b/resources/etc/background/de-primary2.xml @@ -0,0 +1,33 @@ + + eb53b553-0e73-473c-b4c3-bcd328e27d76 + German elementary school, second grade + Grundschule, zweite Klasse + + 0 + 16 + + 0 + 1 + + + 4 + 1 + + + 8 + 1 + + + 12 + 1 + + + 5 + 5 + + 0 + 1 + + + + diff --git a/resources/etc/background/de-primary3.xml b/resources/etc/background/de-primary3.xml new file mode 100644 index 000000000..964025d90 --- /dev/null +++ b/resources/etc/background/de-primary3.xml @@ -0,0 +1,25 @@ + + ff386ccf-e7e1-4838-b7fa-255c28208209 + German elementary school, third grade + Grundschule, dritte Klasse + + 0 + 14 + + 0 + 1 + + + 3.5 + 1 + + + 5 + 5 + + 0 + 1 + + + + diff --git a/resources/etc/background/isometric.xml b/resources/etc/background/isometric.xml new file mode 100644 index 000000000..6bac2b023 --- /dev/null +++ b/resources/etc/background/isometric.xml @@ -0,0 +1,30 @@ + + 07187386-b012-492c-b0a8-50faa18c28a0 + Isometric + Isometrisches Gitter + + + 30 + 8.66025403784 + + 0 + 1 + + + + 90 + 8.66025403784 + + 0 + 1 + + + + 150 + 8.66025403784 + + 0 + 1 + + + diff --git a/resources/etc/background/ruled5.xml b/resources/etc/background/ruled5.xml new file mode 100644 index 000000000..a4c15e259 --- /dev/null +++ b/resources/etc/background/ruled5.xml @@ -0,0 +1,22 @@ + + e986ad6c-9a3e-4a63-a97a-1a19c7fa90cc + Ruled 5mm + Liniert 5mm + + + 0 + 10 + + 0 + 1 + + + 5 + 1 + + 0.5 + 0.5 + + + + diff --git a/resources/etc/background/stave.xml b/resources/etc/background/stave.xml new file mode 100644 index 000000000..2688462c3 --- /dev/null +++ b/resources/etc/background/stave.xml @@ -0,0 +1,30 @@ + + 1dd2b623-950c-4d4d-af74-98d576636099 + Stave lines + Notenlinien + Lignes de notes + + 0 + 50 + + 0 + 1 + + + 5 + 1 + + + 10 + 1 + + + 15 + 1 + + + 20 + 1 + + + diff --git a/resources/forms/mainWindow.ui b/resources/forms/mainWindow.ui index e7c76e60d..a435ec9e8 100644 --- a/resources/forms/mainWindow.ui +++ b/resources/forms/mainWindow.ui @@ -1186,158 +1186,6 @@ - - - true - - - - :/images/backgroundPalette/background1.svg - :/images/backgroundPalette/background1On.svg:/images/backgroundPalette/background1.svg - - - Plain Light Background - - - Light - - - Plain Light Background - - - - - true - - - - :/images/backgroundPalette/background2.svg - :/images/backgroundPalette/background2On.svg:/images/backgroundPalette/background2.svg - - - Grid Light Background - - - Light - - - Grid Light Background - - - - - true - - - - :/images/backgroundPalette/background5.svg - :/images/backgroundPalette/background5On.svg:/images/backgroundPalette/background5.svg - - - Ruled Light Background - - - Light - - - Ruled Light Background - - - - - true - - - - :/images/backgroundPalette/background7.svg - :/images/backgroundPalette/background7On.svg:/images/backgroundPalette/background7.svg - - - Seyes ruled Light Background - - - Light - - - Seyes ruled Light Background - - - - - true - - - - :/images/backgroundPalette/background3.svg - :/images/backgroundPalette/background3On.svg:/images/backgroundPalette/background3.svg - - - Plain Dark Background - - - Dark - - - Plain Dark Background - - - - - true - - - - :/images/backgroundPalette/background4.svg - :/images/backgroundPalette/background4On.svg:/images/backgroundPalette/background4.svg - - - Grid Dark Background - - - Dark - - - Grid Dark Background - - - - - true - - - - :/images/backgroundPalette/background6.svg - :/images/backgroundPalette/background6On.svg:/images/backgroundPalette/background6.svg - - - Ruled Dark Background - - - Dark - - - Ruled Dark Background - - - - - true - - - - :/images/backgroundPalette/background8.svg - :/images/backgroundPalette/background8On.svg:/images/backgroundPalette/background8.svg - - - Seyes ruled Dark Background - - - Dark - - - Seyes ruled Dark Background - - true @@ -1910,20 +1758,20 @@ Reset grid size - + true - :/images/minus.svg - :/images/save.svg:/images/minus.svg + :/images/lightMode.svg + :/images/darkMode.svg:/images/lightMode.svg - Draw intermediate grid lines + Switch between light and dark background - Draw intermediate grid lines + Switch between light and dark background diff --git a/resources/images/backgroundPalette/background1.svg b/resources/images/backgroundPalette/background1.svg deleted file mode 100644 index 468c39377..000000000 --- a/resources/images/backgroundPalette/background1.svg +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/backgroundPalette/background1On.svg b/resources/images/backgroundPalette/background1On.svg deleted file mode 100644 index 83d52f55c..000000000 --- a/resources/images/backgroundPalette/background1On.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/backgroundPalette/background2.svg b/resources/images/backgroundPalette/background2.svg deleted file mode 100644 index 1023164cd..000000000 --- a/resources/images/backgroundPalette/background2.svg +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/backgroundPalette/background2On.svg b/resources/images/backgroundPalette/background2On.svg deleted file mode 100644 index 75c81a8f4..000000000 --- a/resources/images/backgroundPalette/background2On.svg +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/backgroundPalette/background3.svg b/resources/images/backgroundPalette/background3.svg deleted file mode 100644 index 7198b419a..000000000 --- a/resources/images/backgroundPalette/background3.svg +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/backgroundPalette/background3On.svg b/resources/images/backgroundPalette/background3On.svg deleted file mode 100644 index 26ebcd0b2..000000000 --- a/resources/images/backgroundPalette/background3On.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/backgroundPalette/background4.svg b/resources/images/backgroundPalette/background4.svg deleted file mode 100644 index 053ebf054..000000000 --- a/resources/images/backgroundPalette/background4.svg +++ /dev/null @@ -1,133 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/resources/images/backgroundPalette/background4On.svg b/resources/images/backgroundPalette/background4On.svg deleted file mode 100644 index 2513743cf..000000000 --- a/resources/images/backgroundPalette/background4On.svg +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/backgroundPalette/background5.svg b/resources/images/backgroundPalette/background5.svg deleted file mode 100644 index ac6e870e1..000000000 --- a/resources/images/backgroundPalette/background5.svg +++ /dev/null @@ -1,146 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/resources/images/backgroundPalette/background5On.svg b/resources/images/backgroundPalette/background5On.svg deleted file mode 100644 index 25d0a1c3c..000000000 --- a/resources/images/backgroundPalette/background5On.svg +++ /dev/null @@ -1,149 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/resources/images/backgroundPalette/background6.svg b/resources/images/backgroundPalette/background6.svg deleted file mode 100644 index 1c38545bb..000000000 --- a/resources/images/backgroundPalette/background6.svg +++ /dev/null @@ -1,146 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/resources/images/backgroundPalette/background6On.svg b/resources/images/backgroundPalette/background6On.svg deleted file mode 100644 index 1210a2516..000000000 --- a/resources/images/backgroundPalette/background6On.svg +++ /dev/null @@ -1,150 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/resources/images/backgroundPalette/background7.svg b/resources/images/backgroundPalette/background7.svg deleted file mode 100644 index bf960aaed..000000000 --- a/resources/images/backgroundPalette/background7.svg +++ /dev/null @@ -1,177 +0,0 @@ - - - -image/svg+xml diff --git a/resources/images/backgroundPalette/background7On.svg b/resources/images/backgroundPalette/background7On.svg deleted file mode 100644 index a1c67bbf6..000000000 --- a/resources/images/backgroundPalette/background7On.svg +++ /dev/null @@ -1,180 +0,0 @@ - - - -image/svg+xml diff --git a/resources/images/backgroundPalette/background8.svg b/resources/images/backgroundPalette/background8.svg deleted file mode 100644 index ad06d61b4..000000000 --- a/resources/images/backgroundPalette/background8.svg +++ /dev/null @@ -1,177 +0,0 @@ - - - -image/svg+xml diff --git a/resources/images/backgroundPalette/background8On.svg b/resources/images/backgroundPalette/background8On.svg deleted file mode 100644 index d622b6433..000000000 --- a/resources/images/backgroundPalette/background8On.svg +++ /dev/null @@ -1,220 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -image/svg+xml - - - - - - - - - - - - diff --git a/resources/images/darkMode.svg b/resources/images/darkMode.svg new file mode 100644 index 000000000..9e8caa180 --- /dev/null +++ b/resources/images/darkMode.svg @@ -0,0 +1,16 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/resources/images/lightMode.svg b/resources/images/lightMode.svg new file mode 100644 index 000000000..6d6e7992e --- /dev/null +++ b/resources/images/lightMode.svg @@ -0,0 +1,16 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/adaptors/UBExportFullPDF.cpp b/src/adaptors/UBExportFullPDF.cpp index 87f04c74e..8c8ef936c 100644 --- a/src/adaptors/UBExportFullPDF.cpp +++ b/src/adaptors/UBExportFullPDF.cpp @@ -116,7 +116,7 @@ void UBExportFullPDF::saveOverlayPdf(std::shared_ptr pDocumentP // set background according to PDF export settings bool isDark = scene->isDarkBackground(); - UBPageBackground pageBackground = scene->pageBackground(); + const auto sceneBackground = scene->background(); bool exportDark = isDark && UBSettings::settings()->exportBackgroundColor->get().toBool(); @@ -154,15 +154,15 @@ void UBExportFullPDF::saveOverlayPdf(std::shared_ptr pDocumentP if (sceneHasPDFBackground) { scene->setDrawingMode(true); - scene->setBackground(false, UBPageBackground::plain); + scene->setSceneBackground(false, nullptr); } else if (UBSettings::settings()->exportBackgroundGrid->get().toBool()) { - scene->setBackground(exportDark, pageBackground); + scene->setSceneBackground(exportDark, sceneBackground); } else { - scene->setBackground(exportDark, UBPageBackground::plain); + scene->setSceneBackground(exportDark, nullptr); } //render to PDF @@ -174,7 +174,7 @@ void UBExportFullPDF::saveOverlayPdf(std::shared_ptr pDocumentP //restore background state scene->setDrawingMode(false); - scene->setBackground(isDark, pageBackground); + scene->setSceneBackground(isDark, sceneBackground); } if (pdfPainter) delete pdfPainter; diff --git a/src/adaptors/UBExportPDF.cpp b/src/adaptors/UBExportPDF.cpp index 31263a18d..c9c6fee05 100644 --- a/src/adaptors/UBExportPDF.cpp +++ b/src/adaptors/UBExportPDF.cpp @@ -110,17 +110,17 @@ bool UBExportPDF::persistsDocument(std::shared_ptr pDocumentPro // set background to white, no crossing for PDF output bool isDark = scene->isDarkBackground(); - UBPageBackground pageBackground = scene->pageBackground(); + const auto pageBackground = scene->background(); bool exportDark = isDark && UBSettings::settings()->exportBackgroundColor->get().toBool(); if (UBSettings::settings()->exportBackgroundGrid->get().toBool()) { - scene->setBackground(exportDark, pageBackground); + scene->setSceneBackground(exportDark, pageBackground); } else { - scene->setBackground(exportDark, UBPageBackground::plain); + scene->setSceneBackground(exportDark, nullptr); } // pageSize is the output PDF page size; it is set to equal the scene's boundary size; if the contents @@ -150,7 +150,7 @@ bool UBExportPDF::persistsDocument(std::shared_ptr pDocumentPro scene->setRenderingQuality(UBItem::RenderingQualityNormal, UBItem::CacheAllowed); // Restore background state - scene->setBackground(isDark, pageBackground); + scene->setSceneBackground(isDark, pageBackground); } if(!painterNeedsBegin) diff --git a/src/adaptors/UBSvgSubsetAdaptor.cpp b/src/adaptors/UBSvgSubsetAdaptor.cpp index 659d2dddd..7337a6c00 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.cpp +++ b/src/adaptors/UBSvgSubsetAdaptor.cpp @@ -51,6 +51,8 @@ #include "domain/UBGraphicsGroupContainerItemDelegate.h" #include "domain/UBItem.h" +#include "gui/UBBackgroundRuling.h" +#include "gui/UBBackgroundManager.h" #include "tools/UBGraphicsRuler.h" #include "tools/UBGraphicsAxes.h" #include "tools/UBGraphicsCompass.h" @@ -505,6 +507,7 @@ void UBSvgSubsetAdaptor::UBSvgSubsetReader::processElement() bool darkBackground = false; bool crossedBackground = false; bool ruledBackground = false; + bool intermediateLines = false; auto ubDarkBackground = mXmlReader.attributes().value(mNamespaceUri, "dark-background"); @@ -524,42 +527,30 @@ void UBSvgSubsetAdaptor::UBSvgSubsetReader::processElement() mScene->setBackgroundGridSize(gridSize); } - if (crossedBackground) { - - auto ubIntermediateLines = mXmlReader.attributes().value(mNamespaceUri, "intermediate-lines"); - - if (!ubIntermediateLines.isNull()) { - bool intermediateLines = ubIntermediateLines.toInt(); - - mScene->setIntermediateLines(intermediateLines); - } - } - auto ubRuledBackground = mXmlReader.attributes().value(mNamespaceUri, "ruled-background"); if (!ubRuledBackground.isNull()) ruledBackground = (ubRuledBackground.toString() == xmlTrue); - if (ruledBackground && !crossedBackground) { // if for some reason both are true, the background will be a grid + if (ruledBackground || crossedBackground) { auto ubIntermediateLines = mXmlReader.attributes().value(mNamespaceUri, "intermediate-lines"); if (!ubIntermediateLines.isNull()) { - bool intermediateLines = ubIntermediateLines.toInt(); - - mScene->setIntermediateLines(intermediateLines); + intermediateLines = ubIntermediateLines.toInt(); } } - UBPageBackground bg; - if (crossedBackground) - bg = UBPageBackground::crossed; - else if (ruledBackground) - bg = UBPageBackground::ruled; - else - bg = UBPageBackground::plain; + const UBBackgroundRuling* background{nullptr}; + + // guess background pattern from attributes + if (crossedBackground || ruledBackground) + { + const auto bgManager = UBApplication::boardController->backgroundManager(); + background = bgManager->guessBackground(crossedBackground, ruledBackground, intermediateLines); + } - mScene->setBackground(darkBackground, bg); + mScene->setSceneBackground(darkBackground, background); auto pageNominalSize = mXmlReader.attributes().value(mNamespaceUri, "nominal-size"); if (!pageNominalSize.isNull()) @@ -581,6 +572,18 @@ void UBSvgSubsetAdaptor::UBSvgSubsetReader::processElement() } } + else if (name == "background") + { + UBBackgroundRuling bg; + bg.parseXml(mXmlReader); + + if (bg.isValid()) + { + const auto bgManager = UBApplication::boardController->backgroundManager(); + bgManager->addBackground(bg); + mScene->setSceneBackground(mScene->isDarkBackground(), bgManager->background(bg.uuid())); + } + } else if (name == "g") { strokesGroup = new UBGraphicsStrokesGroup(); @@ -1225,8 +1228,9 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::writeSvgElement(std::shared_ptrisDarkBackground() ? xmlTrue : xmlFalse); - bool crossedBackground = mScene->pageBackground() == UBPageBackground::crossed; - bool ruledBackground = mScene->pageBackground() == UBPageBackground::ruled; + bool crossedBackground = mScene->background() && mScene->background()->isCrossed(); + bool ruledBackground = mScene->background() && mScene->background()->isRuled(); + bool intermediateLines = mScene->background() && mScene->background()->hasIntermediateLines(); mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "crossed-background", crossedBackground ? xmlTrue : xmlFalse); mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "ruled-background", ruledBackground ? xmlTrue : xmlFalse); @@ -1235,8 +1239,6 @@ void UBSvgSubsetAdaptor::UBSvgSubsetWriter::writeSvgElement(std::shared_ptrintermediateLines(); - mXmlWriter.writeAttribute(UBSettings::uniboardDocumentNamespaceUri, "intermediate-lines", QString::number(intermediateLines)); } @@ -1279,6 +1281,11 @@ bool UBSvgSubsetAdaptor::UBSvgSubsetWriter::persistScene(std::shared_ptrbackground()) + { + mScene->background()->toXml(mXmlWriter); + } + // Get the items from the scene QList items = mScene->items(); diff --git a/src/api/UBWidgetUniboardAPI.cpp b/src/api/UBWidgetUniboardAPI.cpp index fade7ce31..6454cd513 100644 --- a/src/api/UBWidgetUniboardAPI.cpp +++ b/src/api/UBWidgetUniboardAPI.cpp @@ -50,6 +50,7 @@ #include "UBWidgetMessageAPI.h" #include "frameworks/UBFileSystemUtils.h" #include "core/UBDownloadManager.h" +#include "gui/UBBackgroundManager.h" #include "core/memcheck.h" @@ -234,10 +235,9 @@ void UBWidgetUniboardAPI::setBackground(bool pIsDark, bool pIsCrossed) auto scene = mScene.lock(); if (scene) { - if (pIsCrossed) - scene->setBackground(pIsDark, UBPageBackground::crossed); - else - scene->setBackground(pIsDark, UBPageBackground::plain); + const auto backgroundManager = UBApplication::boardController->backgroundManager(); + const auto background = backgroundManager->guessBackground(pIsCrossed, false, false); + scene->setSceneBackground(pIsDark, background); } } diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index 5fc5ac0a0..353d0b9ca 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -68,6 +68,7 @@ #include "domain/UBItem.h" #include "domain/UBPageSizeUndoCommand.h" +#include "gui/UBBackgroundManager.h" #include "gui/UBFeaturesWidget.h" #include "gui/UBKeyboardPalette.h" #include "gui/UBMagnifer.h" @@ -110,6 +111,8 @@ UBBoardController::UBBoardController(UBMainWindow* mainWindow) , mActionUngroupText(tr("Ungroup")) , mAutosaveTimer(0) { + mBgManager = new UBBackgroundManager(this); + mZoomFactor = UBSettings::settings()->boardZoomFactor->get().toDouble(); int penColorIndex = UBSettings::settings()->penColorIndex(); @@ -1532,14 +1535,16 @@ std::shared_ptr UBBoardController::setActiveDocumentScene(std:: adjustDisplayViews(); UBSettings::settings()->setDarkBackground(mActiveScene->isDarkBackground()); - UBSettings::settings()->setPageBackground(mActiveScene->pageBackground()); + + if (mActiveScene->background()) + { + UBSettings::settings()->setPageBackgroundUuid(mActiveScene->background()->uuid()); + } freezeW3CWidgets(false); selectionChanged(); - updateBackgroundActionsState(mActiveScene->isDarkBackground(), mActiveScene->pageBackground()); - if (documentChange) { UBGraphicsTextItem::lastUsedTextColor = QColor(Qt::black); @@ -1702,20 +1707,14 @@ int UBBoardController::autosaveTimeoutFromSettings() const return value * minute; } -void UBBoardController::changeBackground(bool isDark, UBPageBackground pageBackground) +void UBBoardController::setBackground(bool isDark, const UBBackgroundRuling* background) { - bool currentIsDark = mActiveScene->isDarkBackground(); - UBPageBackground currentBackgroundType = mActiveScene->pageBackground(); - - if ((isDark != currentIsDark) || (currentBackgroundType != pageBackground)) - { - UBSettings::settings()->setDarkBackground(isDark); - UBSettings::settings()->setPageBackground(pageBackground); + UBSettings::settings()->setDarkBackground(isDark); + UBSettings::settings()->setPageBackgroundUuid(background ? background->uuid() : QUuid{}); - mActiveScene->setBackground(isDark, pageBackground); + mActiveScene->setSceneBackground(isDark, background); - emit backgroundChanged(); - } + emit backgroundChanged(); } void UBBoardController::boardViewResized(QResizeEvent* event) @@ -2525,45 +2524,6 @@ void UBBoardController::moveToolWidgetToScene(UBToolWidget* toolWidget) } -void UBBoardController::updateBackgroundActionsState(bool isDark, UBPageBackground pageBackground) -{ - switch (pageBackground) { - - case UBPageBackground::crossed: - if (isDark) - mMainWindow->actionCrossedDarkBackground->setChecked(true); - else - mMainWindow->actionCrossedLightBackground->setChecked(true); - break; - - case UBPageBackground::ruled: - { - QAction* actionRuledBackground = nullptr; - if(UBSettings::settings()->isSeyesRuledBackground()) - if(isDark) - actionRuledBackground = mMainWindow->actionSeyesRuledDarkBackground; - else - actionRuledBackground = mMainWindow->actionSeyesRuledLightBackground; - else - if(isDark) - actionRuledBackground = mMainWindow->actionRuledDarkBackground; - else - actionRuledBackground = mMainWindow->actionRuledLightBackground; - if(actionRuledBackground) - actionRuledBackground->setChecked(true); - } - break; - - default: - if (isDark) - mMainWindow->actionPlainDarkBackground->setChecked(true); - else - mMainWindow->actionPlainLightBackground->setChecked(true); - break; - } -} - - void UBBoardController::addItem() { QString defaultPath = UBSettings::settings()->lastImportToLibraryPath->get().toString(); diff --git a/src/board/UBBoardController.h b/src/board/UBBoardController.h index 3a3bc6e3f..7b1a22568 100644 --- a/src/board/UBBoardController.h +++ b/src/board/UBBoardController.h @@ -44,6 +44,8 @@ class UBMainWindow; class UBApplication; class UBBoardView; +class UBBackgroundRuling; +class UBBackgroundManager; class UBDocument; class UBDocumentController; class UBMessageWindow; @@ -102,6 +104,11 @@ class UBBoardController : public UBDocumentContainer return mDisplayView; } + UBBackgroundManager* backgroundManager() const + { + return mBgManager; + } + void setPenColorOnDarkBackground(const QColor& pColor) { if (mPenColorOnDarkBackground == pColor) @@ -221,7 +228,7 @@ class UBBoardController : public UBDocumentContainer UBItem *downloadFinished(bool pSuccess, QUrl sourceUrl, QUrl contentUrl, QString pHeader, QByteArray pData, QPointF pPos, QSize pSize, bool isBackground = false, bool internalData = false); - void changeBackground(bool isDark, UBPageBackground pageBackground); + void setBackground(bool isDark, const UBBackgroundRuling* background); void setToolCursor(int tool); void showMessage(const QString& message, bool showSpinningWheel = false); void hideMessage(); @@ -297,6 +304,7 @@ class UBBoardController : public UBDocumentContainer int mActiveSceneIndex; int mSwitchToSceneIndex{-1}; UBBoardPaletteManager *mPaletteManager; + UBBackgroundManager* mBgManager{nullptr}; UBSoftwareUpdateDialog *mSoftwareUpdateDialog; UBMessageWindow *mMessageWindow; UBEmbedController *mEmbedController; @@ -327,7 +335,6 @@ class UBBoardController : public UBDocumentContainer private slots: void stylusToolDoubleClicked(int tool); void boardViewResized(QResizeEvent* event); - void updateBackgroundActionsState(bool isDark, UBPageBackground pageBackground); void colorPaletteChanged(); void libraryDialogClosed(int ret); void lastWindowClosed(); diff --git a/src/board/UBBoardPaletteManager.cpp b/src/board/UBBoardPaletteManager.cpp index e81bc95a0..233d0d8a1 100644 --- a/src/board/UBBoardPaletteManager.cpp +++ b/src/board/UBBoardPaletteManager.cpp @@ -247,22 +247,8 @@ void UBBoardPaletteManager::setupPalettes() mStylusPalette->stackUnder(mZoomPalette); mTipPalette = new UBStartupHintsPalette(mContainer); - QList backgroundsActions; - backgroundsActions << UBApplication::mainWindow->actionPlainLightBackground; - backgroundsActions << UBApplication::mainWindow->actionCrossedLightBackground; - if(UBSettings::settings()->isSeyesRuledBackground()) - backgroundsActions << UBApplication::mainWindow->actionSeyesRuledLightBackground; - else - backgroundsActions << UBApplication::mainWindow->actionRuledLightBackground; - backgroundsActions << UBApplication::mainWindow->actionPlainDarkBackground; - backgroundsActions << UBApplication::mainWindow->actionCrossedDarkBackground; - if(UBSettings::settings()->isSeyesRuledBackground()) - backgroundsActions << UBApplication::mainWindow->actionSeyesRuledDarkBackground; - else - backgroundsActions << UBApplication::mainWindow->actionRuledDarkBackground; - - mBackgroundsPalette = new UBBackgroundPalette(backgroundsActions, mContainer); + mBackgroundsPalette = new UBBackgroundPalette(mContainer); mBackgroundsPalette->setButtonIconSize(QSize(128, 128)); mBackgroundsPalette->groupActions(); mBackgroundsPalette->setClosable(true); @@ -452,14 +438,6 @@ void UBBoardPaletteManager::connectPalettes() connect(UBApplication::mainWindow->actionBackgrounds, SIGNAL(toggled(bool)), this, SLOT(toggleBackgroundPalette(bool))); connect(mBackgroundsPalette, SIGNAL(closed()), this, SLOT(backgroundPaletteClosed())); - connect(UBApplication::mainWindow->actionPlainLightBackground, SIGNAL(triggered()), this, SLOT(changeBackground())); - connect(UBApplication::mainWindow->actionCrossedLightBackground, SIGNAL(triggered()), this, SLOT(changeBackground())); - connect(UBApplication::mainWindow->actionRuledLightBackground, SIGNAL(triggered()), this, SLOT(changeBackground())); - connect(UBApplication::mainWindow->actionSeyesRuledLightBackground, SIGNAL(triggered()), this, SLOT(changeBackground())); - connect(UBApplication::mainWindow->actionPlainDarkBackground, SIGNAL(triggered()), this, SLOT(changeBackground())); - connect(UBApplication::mainWindow->actionCrossedDarkBackground, SIGNAL(triggered()), this, SLOT(changeBackground())); - connect(UBApplication::mainWindow->actionRuledDarkBackground, SIGNAL(triggered()), this, SLOT(changeBackground())); - connect(UBApplication::mainWindow->actionSeyesRuledDarkBackground, SIGNAL(triggered()), this, SLOT(changeBackground())); connect(UBApplication::mainWindow->actionPodcast, SIGNAL(triggered(bool)), this, SLOT(tooglePodcastPalette(bool))); connect(UBApplication::mainWindow->actionAddItemToCurrentPage, SIGNAL(triggered()), this, SLOT(addItemToCurrentPage())); @@ -543,32 +521,6 @@ void UBBoardPaletteManager::containerResized() } -void UBBoardPaletteManager::changeBackground() -{ - if (UBApplication::mainWindow->actionCrossedLightBackground->isChecked()) - UBApplication::boardController->changeBackground(false, UBPageBackground::crossed); - - else if (UBApplication::mainWindow->actionRuledLightBackground->isChecked() || - UBApplication::mainWindow->actionSeyesRuledLightBackground->isChecked()) - UBApplication::boardController->changeBackground(false, UBPageBackground::ruled); - - else if (UBApplication::mainWindow->actionPlainDarkBackground->isChecked()) - UBApplication::boardController->changeBackground(true, UBPageBackground::plain); - - else if (UBApplication::mainWindow->actionCrossedDarkBackground->isChecked()) - UBApplication::boardController->changeBackground(true, UBPageBackground::crossed); - - else if (UBApplication::mainWindow->actionRuledDarkBackground->isChecked() || - UBApplication::mainWindow->actionSeyesRuledDarkBackground->isChecked()) - UBApplication::boardController->changeBackground(true, UBPageBackground::ruled); - - else - UBApplication::boardController->changeBackground(false, UBPageBackground::plain); - - mBackgroundsPalette->backgroundChanged(); -} - - void UBBoardPaletteManager::activeSceneChanged() { std::shared_ptr activeScene = UBApplication::boardController->activeScene(); diff --git a/src/board/UBBoardPaletteManager.h b/src/board/UBBoardPaletteManager.h index e7434534f..c4b96a39b 100644 --- a/src/board/UBBoardPaletteManager.h +++ b/src/board/UBBoardPaletteManager.h @@ -153,8 +153,6 @@ class UBBoardPaletteManager : public QObject private slots: - void changeBackground(); - void toggleBackgroundPalette(bool checked); void backgroundPaletteClosed(); diff --git a/src/core/UB.h b/src/core/UB.h index 8ccdc469c..4dca9233f 100644 --- a/src/core/UB.h +++ b/src/core/UB.h @@ -220,13 +220,6 @@ struct UBUndoType }; }; -enum UBPageBackground -{ - plain = 0, - crossed, - ruled -}; - /* * Qt Version Compatibility */ diff --git a/src/core/UBApplicationController.cpp b/src/core/UBApplicationController.cpp index 013d2ba91..7fc8bf989 100644 --- a/src/core/UBApplicationController.cpp +++ b/src/core/UBApplicationController.cpp @@ -96,7 +96,7 @@ UBApplicationController::UBApplicationController(UBBoardView *pControlView, connect(mUninoteController, SIGNAL(restoreUniboard()), this, SLOT(hideDesktop())); mBlackScene = std::make_shared(nullptr); - mBlackScene->setBackground(true, UBPageBackground::plain); + mBlackScene->setSceneBackground(true, nullptr); if (displayManager->numScreens() >= 2 && displayManager->useMultiScreen()) { diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp index bb92037ef..c2827a889 100644 --- a/src/core/UBPersistenceManager.cpp +++ b/src/core/UBPersistenceManager.cpp @@ -28,6 +28,7 @@ #include "UBPersistenceManager.h" #include "domain/UBMediaAssetItem.h" +#include "gui/UBBackgroundManager.h" #include "gui/UBMainWindow.h" #include @@ -818,8 +819,9 @@ std::shared_ptr UBPersistenceManager::createDocumentSceneAt(std newScene = std::make_shared(proxy, useUndoRedoStack); } - newScene->setBackground(UBSettings::settings()->isDarkBackground(), - UBSettings::settings()->UBSettings::pageBackground()); + const auto uuid = UBSettings::settings()->UBSettings::pageBackgroundUuid(); + const auto background = UBApplication::boardController->backgroundManager()->background(uuid); + newScene->setSceneBackground(UBSettings::settings()->isDarkBackground(), background); newScene->setBackgroundGridSize(UBSettings::settings()->crossSize); diff --git a/src/core/UBSettings.cpp b/src/core/UBSettings.cpp index 7d269261a..c3eb58b6f 100644 --- a/src/core/UBSettings.cpp +++ b/src/core/UBSettings.cpp @@ -50,7 +50,6 @@ int UBSettings::crossSize = 24; int UBSettings::defaultCrossSize = 24; int UBSettings::minCrossSize = 12; int UBSettings::maxCrossSize = 96; //TODO: user-settable? -bool UBSettings::intermediateLines = false; int UBSettings::colorPaletteSize = 5; int UBSettings::objectFrameWidth = 20; int UBSettings::boardMargin = 10; @@ -814,21 +813,10 @@ bool UBSettings::isDarkBackground() } -UBPageBackground UBSettings::pageBackground() +QUuid UBSettings::pageBackgroundUuid() { - QString val = value("Board/PageBackground", 0).toString(); - - if (val == "crossed") - return UBPageBackground::crossed; - else if (val == "ruled") - return UBPageBackground::ruled; - else - return UBPageBackground::plain; -} - -bool UBSettings::isSeyesRuledBackground() -{ - return value("Board/SeyesRuledBackground", false).toBool(); + QUuid uuid = value("Board/PageBackground", 0).toString(); + return uuid; } void UBSettings::setDarkBackground(bool isDarkBackground) @@ -838,23 +826,9 @@ void UBSettings::setDarkBackground(bool isDarkBackground) } -void UBSettings::setPageBackground(UBPageBackground background) -{ - QString val; - - if (background == UBPageBackground::crossed) - val = "crossed"; - else if (background == UBPageBackground::ruled) - val = "ruled"; - else - val = "plain"; - - setValue("Board/PageBackground", val); -} - -void UBSettings::setSeyesRuledBackground(bool isSeyesRuledBackground) +void UBSettings::setPageBackgroundUuid(const QUuid& background) { - setValue("Board/SeyesRuledBackground", isSeyesRuledBackground); + setValue("Board/PageBackground", background.toString()); } void UBSettings::setPenPressureSensitive(bool sensitive) diff --git a/src/core/UBSettings.h b/src/core/UBSettings.h index 609a44917..00893839e 100644 --- a/src/core/UBSettings.h +++ b/src/core/UBSettings.h @@ -87,11 +87,9 @@ class UBSettings : public QObject // Background related bool isDarkBackground(); - UBPageBackground pageBackground(); - bool isSeyesRuledBackground(); + QUuid pageBackgroundUuid(); void setDarkBackground(bool isDarkBackground); - void setPageBackground(UBPageBackground background); - void setSeyesRuledBackground(bool isSeyesRuledBackground); + void setPageBackgroundUuid(const QUuid& background); // Stylus palette related bool isStylusPaletteVisible(); @@ -193,7 +191,6 @@ class UBSettings : public QObject static int defaultCrossSize; static int minCrossSize; static int maxCrossSize; - static bool intermediateLines; static int colorPaletteSize; static int objectFrameWidth; diff --git a/src/core/UBShortcutManager.cpp b/src/core/UBShortcutManager.cpp index dfe8c8239..25c1c7082 100644 --- a/src/core/UBShortcutManager.cpp +++ b/src/core/UBShortcutManager.cpp @@ -188,14 +188,8 @@ void UBShortcutManager::addMainActions(UBMainWindow *mainWindow) addActions(tr("Background"), { mainWindow->actionBackgrounds, - mainWindow->actionPlainLightBackground, - mainWindow->actionCrossedLightBackground, - mainWindow->actionRuledLightBackground, - mainWindow->actionPlainDarkBackground, - mainWindow->actionCrossedDarkBackground, - mainWindow->actionRuledDarkBackground, mainWindow->actionDefaultGridSize, - mainWindow->actionDrawIntermediateGridLines + mainWindow->actionLightDarkMode }, mainWindow); addActions(tr("Podcast"), { diff --git a/src/desktop/UBDesktopAnnotationController.cpp b/src/desktop/UBDesktopAnnotationController.cpp index 6d4e1da48..1fc56770d 100644 --- a/src/desktop/UBDesktopAnnotationController.cpp +++ b/src/desktop/UBDesktopAnnotationController.cpp @@ -188,9 +188,9 @@ UBDesktopAnnotationController::~UBDesktopAnnotationController() void UBDesktopAnnotationController::updateColors(){ if(UBApplication::boardController->activeScene()->isDarkBackground()){ - mTransparentDrawingScene->setBackground(true, UBPageBackground::plain); + mTransparentDrawingScene->setSceneBackground(true, nullptr); }else{ - mTransparentDrawingScene->setBackground(false, UBPageBackground::plain); + mTransparentDrawingScene->setSceneBackground(false, nullptr); } } diff --git a/src/domain/UBGraphicsScene.cpp b/src/domain/UBGraphicsScene.cpp index 5caa8e1e2..5c49b5b15 100644 --- a/src/domain/UBGraphicsScene.cpp +++ b/src/domain/UBGraphicsScene.cpp @@ -25,8 +25,6 @@ */ - - #include "UBGraphicsScene.h" #include @@ -42,6 +40,7 @@ #include "core/UBPersistenceManager.h" #include "core/UBTextTools.h" +#include "gui/UBBackgroundRuling.h" #include "gui/UBMagnifer.h" #include "gui/UBMainWindow.h" #include "gui/UBResources.h" @@ -321,7 +320,6 @@ UBGraphicsScene::UBGraphicsScene(std::shared_ptr document, bool , mPenCircle(0) , mDocument(document) , mDarkBackground(false) - , mPageBackground(UBPageBackground::plain) , mIsDesktopMode(false) , mZoomFactor(1) , mBackgroundObject(0) @@ -361,7 +359,6 @@ UBGraphicsScene::UBGraphicsScene(std::shared_ptr document, bool } mBackgroundGridSize = UBSettings::settings()->crossSize; - mIntermediateLines = UBSettings::settings()->intermediateLines; // Just for debug. Do not delete please // connect(this, SIGNAL(selectionChanged()), this, SLOT(selectionChangedProcessing())); @@ -1148,7 +1145,7 @@ void UBGraphicsScene::drawArcTo(const QPointF& pCenterPoint, qreal pSpanAngle) setDocumentUpdated(); } -void UBGraphicsScene::setBackground(bool pIsDark, UBPageBackground pBackground) +void UBGraphicsScene::setSceneBackground(bool pIsDark, const UBBackgroundRuling *background) { bool needRepaint = false; @@ -1161,12 +1158,14 @@ void UBGraphicsScene::setBackground(bool pIsDark, UBPageBackground pBackground) updatePenCircleColor(); recolorAllItems(); + UBSettings::settings()->setDarkBackground(mDarkBackground); needRepaint = true; } - if (mPageBackground != pBackground) + if (mBackground != background) { - mPageBackground = pBackground; + mBackground = background; + UBSettings::settings()->setPageBackgroundUuid(mBackground ? mBackground->uuid() : QUuid{}); needRepaint = true; } @@ -1190,12 +1189,6 @@ void UBGraphicsScene::setBackgroundGridSize(int pSize) } } -void UBGraphicsScene::setIntermediateLines(bool checked) -{ - mIntermediateLines = checked; - updateBackground(); -} - void UBGraphicsScene::setDrawingMode(bool bModeDesktop) { mIsDesktopMode = bModeDesktop; @@ -1402,8 +1395,9 @@ std::shared_ptr UBGraphicsScene::sceneDeepCopy() const std::shared_ptr copy = std::make_shared(this->document(), this->mUndoRedoStackEnabled); copy->setUuid(this->uuid()); - copy->setBackground(this->isDarkBackground(), mPageBackground); copy->setBackgroundGridSize(mBackgroundGridSize); + copy->mDarkBackground = mDarkBackground; + copy->mBackground = mBackground; copy->setSceneRect(this->sceneRect()); if (this->mNominalSize.isValid()) @@ -2184,6 +2178,11 @@ void UBGraphicsScene::setDocument(std::shared_ptr pDocument) } } +const UBBackgroundRuling* UBGraphicsScene::background() const +{ + return mBackground; +} + QGraphicsItem* UBGraphicsScene::scaleToFitDocumentSize(QGraphicsItem* item, bool center, int margin, bool expand) { int maxWidth = mNominalSize.width() - (margin * 2); @@ -2866,124 +2865,17 @@ void UBGraphicsScene::drawBackground(QPainter *painter, const QRectF &rect) if (mZoomFactor > 0.5) { - QColor bgCrossColor; - - if (darkBackground) - bgCrossColor = QColor(UBSettings::settings()->boardCrossColorDarkBackground->get().toString()); - else - bgCrossColor = QColor(UBSettings::settings()->boardCrossColorLightBackground->get().toString()); if (mZoomFactor < 0.7) { - int alpha = 255 * mZoomFactor / 2; - bgCrossColor.setAlpha (alpha); // fade the crossing on small zooms - } - - qreal gridSize = backgroundGridSize(); - painter->setPen (bgCrossColor); - - if (mPageBackground == UBPageBackground::crossed) - { - qreal firstY = ((int) (rect.y () / gridSize)) * gridSize; - - for (qreal yPos = firstY; yPos < rect.y () + rect.height (); yPos += gridSize) - { - painter->drawLine (rect.x (), yPos, rect.x () + rect.width (), yPos); - } - - qreal firstX = ((int) (rect.x () / gridSize)) * gridSize; - - for (qreal xPos = firstX; xPos < rect.x () + rect.width (); xPos += gridSize) - { - painter->drawLine (xPos, rect.y (), xPos, rect.y () + rect.height ()); - } - - if (mIntermediateLines) - { - QColor intermediateColor = bgCrossColor; - intermediateColor.setAlphaF(0.5 * bgCrossColor.alphaF()); - painter->setPen(intermediateColor); - - for (qreal yPos = firstY - gridSize/2; yPos < rect.y () + rect.height (); yPos += gridSize) - { - painter->drawLine (rect.x (), yPos, rect.x () + rect.width (), yPos); - } - - for (qreal xPos = firstX - gridSize/2; xPos < rect.x () + rect.width (); xPos += gridSize) - { - painter->drawLine (xPos, rect.y (), xPos, rect.y () + rect.height ()); - } - } + painter->setOpacity(mZoomFactor / 2); } - else if (mPageBackground == UBPageBackground::ruled) + if (mBackground) { - if(UBSettings::settings()->isSeyesRuledBackground()) - { - qreal gridSizeSeyes = gridSize * 2; // The grid size must be bigger - int nbMarginCase = 1; // a small left margin of one gridSize - - QPen seyesSquare ("#8e7cc3"); - seyesSquare.setWidthF (2.); - - QColor interlineColor("#6fa8dc"); - interlineColor.setAlphaF(0.6); - QPen interlinePen(interlineColor); - interlinePen.setWidthF(2.); - - QPen redLineMargin(QColor("red")); - redLineMargin.setWidthF(2.); - - // Horizontal lines - - qreal firstY = ((int) (rect.y () / gridSizeSeyes)) * gridSizeSeyes; - - for (qreal yPos = firstY; yPos < rect.y () + rect.height (); yPos += gridSizeSeyes) - { - painter->setPen (seyesSquare); - painter->drawLine (rect.x (), yPos, rect.x () + rect.width (), yPos); - painter->setPen (interlinePen); - painter->drawLine (rect.x (), yPos+gridSizeSeyes/4, rect.x () + rect.width (), yPos+gridSizeSeyes/4); - painter->drawLine (rect.x (), yPos+2*gridSizeSeyes/4, rect.x () + rect.width (), yPos+2*gridSizeSeyes/4); - painter->drawLine (rect.x (), yPos+3*gridSizeSeyes/4, rect.x () + rect.width (), yPos+3*gridSizeSeyes/4); - } - - // Vertical margin - - qreal firstX = ((int) nbMarginCase * gridSizeSeyes) - mNominalSize.width() / 2.; - - painter->setPen(redLineMargin); - painter->drawLine (firstX, rect.y (), firstX, rect.y () + rect.height ()); - - // Vertical lines - - firstX = ((int) (nbMarginCase + 1) * gridSizeSeyes) - mNominalSize.width() / 2.; - - painter->setPen (seyesSquare); - for (qreal xPos = firstX; xPos < rect.x () + rect.width (); xPos += gridSizeSeyes) - { - painter->drawLine (xPos, rect.y (), xPos, rect.y () + rect.height ()); - } - } - else - { - qreal firstY = ((int) (rect.y () / backgroundGridSize())) * backgroundGridSize(); - - for (qreal yPos = firstY; yPos < rect.y () + rect.height (); yPos += backgroundGridSize()) - { - painter->drawLine (rect.x (), yPos, rect.x () + rect.width (), yPos); - } - - if (mIntermediateLines) { - QColor intermediateColor = bgCrossColor; - intermediateColor.setAlphaF(0.5 * bgCrossColor.alphaF()); - painter->setPen(intermediateColor); - - for (qreal yPos = firstY - gridSize/2; yPos < rect.y () + rect.height (); yPos += gridSize) - { - painter->drawLine (rect.x (), yPos, rect.x () + rect.width (), yPos); - } - } - } + qreal gridSize = backgroundGridSize(); + QRectF nominalScene{{0, 0}, mNominalSize}; + nominalScene.moveCenter({0, 0}); + mBackground->draw(painter, rect, gridSize, nominalScene, mDarkBackground); } } } diff --git a/src/domain/UBGraphicsScene.h b/src/domain/UBGraphicsScene.h index 54820fd4e..3133fbdb7 100644 --- a/src/domain/UBGraphicsScene.h +++ b/src/domain/UBGraphicsScene.h @@ -37,6 +37,7 @@ #include "UBItem.h" +class UBBackgroundRuling; class UBGraphicsPixmapItem; class UBGraphicsSvgItem; class UBGraphicsPolygonItem; @@ -212,21 +213,13 @@ class UBGraphicsScene: public UBCoreGraphicsScene, public UBItem, public std::en return !mDarkBackground; } - UBPageBackground pageBackground() const - { - return mPageBackground; - } + const UBBackgroundRuling* background() const; int backgroundGridSize() const { return mBackgroundGridSize; } - bool intermediateLines() const - { - return mIntermediateLines; - } - bool hasBackground() { return (mBackgroundObject != 0); @@ -340,10 +333,9 @@ public slots: void initStroke(); void hideTool(); - void setBackground(bool pIsDark, UBPageBackground pBackground); + void setSceneBackground(bool pIsDark, const UBBackgroundRuling *background); void setBackgroundZoomFactor(qreal zoom); void setBackgroundGridSize(int pSize); - void setIntermediateLines(bool checked); void setDrawingMode(bool bModeDesktop); void deselectAllItems(); @@ -440,9 +432,8 @@ public slots: std::shared_ptr mDocument; bool mDarkBackground; - UBPageBackground mPageBackground; + const UBBackgroundRuling* mBackground{nullptr}; int mBackgroundGridSize; - bool mIntermediateLines; bool mIsDesktopMode; qreal mZoomFactor; diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 7a9c3f12c..0d41ee950 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -1,8 +1,12 @@ target_sources(${PROJECT_NAME} PRIVATE UBActionPalette.cpp UBActionPalette.h + UBBackgroundManager.cpp + UBBackgroundManager.h UBBackgroundPalette.cpp UBBackgroundPalette.h + UBBackgroundRuling.cpp + UBBackgroundRuling.h UBBlackoutWidget.cpp UBBlackoutWidget.h UBBoardThumbnailsView.cpp diff --git a/src/gui/UBActionPalette.cpp b/src/gui/UBActionPalette.cpp index 6196a6b07..391020d6a 100644 --- a/src/gui/UBActionPalette.cpp +++ b/src/gui/UBActionPalette.cpp @@ -68,7 +68,7 @@ void UBActionPalette::init(Qt::Orientation orientation) mButtonSize = QSize(32, 32); mIsClosable = false; mAutoClose = false; - mActionGroup = 0; + mActionGroup = nullptr; mToolButtonStyle = Qt::ToolButtonIconOnly; mButtons.clear(); @@ -165,10 +165,15 @@ void UBActionPalette::groupActions() action->setProperty("id", i); mActionGroup->addAction(action); ++i; + + connect(action, &QAction::triggered, this, [this,action](bool checked){ + if (checked) + { + emit buttonGroupClicked(action); + } + }); } } - - connect(mActionGroup, SIGNAL(triggered(QAction*)), this, SIGNAL(buttonGroupClicked(QAction*))); } diff --git a/src/gui/UBBackgroundManager.cpp b/src/gui/UBBackgroundManager.cpp new file mode 100644 index 000000000..8e6ffb773 --- /dev/null +++ b/src/gui/UBBackgroundManager.cpp @@ -0,0 +1,227 @@ +#include "UBBackgroundManager.h" + +#include "core/UBSettings.h" +#include "frameworks/UBPlatformUtils.h" +#include "gui/UBBackgroundRuling.h" + +#include +#include + + +UBBackgroundManager::UBBackgroundManager(QObject *parent) + : QObject{parent} +{ + scan(); +} + +void UBBackgroundManager::scan() +{ + // scan application and user directories for background rules + QString appDir = UBPlatformUtils::applicationTemplateDirectory() + "/background"; + QString usrDir = UBSettings::userDataDirectory() + "/template/background"; + + scan(appDir); + scan(usrDir); +} + +void UBBackgroundManager::addBackground(UBBackgroundRuling &background) +{ + if (background.isValid() && !this->background(background.uuid())) + { + mBackgrounds.append(background); + } + else + { + qWarning() << "Invalid or duplicate background ruling" << background.description("en"); + } +} + +const QList &UBBackgroundManager::backgrounds() const +{ + return mBackgrounds; +} + +QAction *UBBackgroundManager::backgroundAction(const UBBackgroundRuling &background, bool dark) +{ + QAction* action = new QAction{this}; + action->setIcon(createButtonIcon(background, dark)); + QString lang = QLocale().name().left(2); + QString descr = background.description(lang); + action->setToolTip(descr); + action->setProperty("uuid", background.uuid()); + action->setCheckable(true); + return action; +} + +void UBBackgroundManager::updateAction(QAction *action, bool dark) const +{ + const auto uuid = action->property("uuid").toUuid(); + const auto bg = background(uuid); + + if (bg) + { + action->setIcon(createButtonIcon(*bg, dark)); + } +} + +const UBBackgroundRuling* UBBackgroundManager::background(const QUuid &uuid) const +{ + for (auto& background : qAsConst(mBackgrounds)) + { + if (background.uuid() == uuid) + { + return &background; + } + } + + return nullptr; +} + +const UBBackgroundRuling* UBBackgroundManager::guessBackground(bool crossed, bool ruled, bool intermediateLines) const +{ + for (auto& background : qAsConst(mBackgrounds)) + { + if (background.isCrossed() == crossed + && background.isRuled() == ruled + && background.hasIntermediateLines() == intermediateLines) + { + return &background; + } + } + + return nullptr; +} + +void UBBackgroundManager::scan(const QString &dirname) +{ + const QDir dir{dirname}; + + if (dir.exists()) + { + const auto list = dir.entryInfoList({"*.xml"}, QDir::Files, QDir::Name); + + for (const auto& entry : list) + { + UBBackgroundRuling bg; + QFile file{entry.absoluteFilePath()}; + + if (!file.open(QFile::ReadOnly)) + { + continue; + } + + QXmlStreamReader reader(&file); + + if (reader.readNextStartElement()) + { + bg.parseXml(reader); + } + + if (bg.isValid()) + { + mBackgrounds.append(bg); + } + else + { + qWarning() << "Error reading background definitions from" << file; + } + } + } +} + +QByteArray UBBackgroundManager::renderToSvg(const UBBackgroundRuling &background, bool dark) const +{ + QSvgGenerator generator; + QBuffer buffer; + generator.setOutputDevice(&buffer); + generator.setSize(QSize(93, 75)); + generator.setViewBox(QRect(0, 0, 93, 75)); + + QPainter painter; + + painter.begin(&generator); + background.draw(&painter, {0, 0, 93, 75}, 0., {0, 0, 193, 75}, dark); + painter.end(); + + return buffer.buffer(); +} + +QPixmap UBBackgroundManager::createButtonPixmap(const UBBackgroundRuling &background, bool dark, bool on) const +{ + QString filename{"bgButtonTemplate"}; + + filename += dark ? "Dark" : "Light"; + filename += on ? "On" : "Off"; + filename += ".svg"; + + QFile templateFile(UBPlatformUtils::applicationTemplateDirectory() + "/background/" + filename); + + if (!templateFile.open(QFile::ReadOnly)) + { + qWarning() << "Cannot find template file" << templateFile; + return {}; + } + + QDomDocument doc; + + if (!doc.setContent(&templateFile, true)) + { + qWarning() << "Cannot load template file" << templateFile; + return {}; + } + + // find element with id="placeholder" + auto plist = doc.documentElement().elementsByTagName("g"); + + QDomElement placeholder; + + for (int i = 0; i < plist.size(); ++i) + { + QDomElement item = plist.at(i).toElement(); + + if (item.attribute("id") == "placeholder") + { + placeholder = item; + break; + } + } + + // now render background to SVG + QByteArray bgSvg = renderToSvg(background, dark); + QDomDocument bgDoc; + + if (!bgDoc.setContent(bgSvg)) + { + qWarning() << "Cannot load rendered ruling" << templateFile; + return {}; + } + + // find first element + auto bgElement = bgDoc.documentElement().firstChildElement("g"); + + // replace element in original document + auto bg = doc.importNode(bgElement, true); + placeholder.parentNode().replaceChild(bg, placeholder); + + QByteArray replaced = doc.toByteArray(2); + + // render SVG to pixmap by using an QImageReader + QBuffer buffer{&replaced}; + QImageReader reader(&buffer, "svg"); + QPixmap pixmap = QPixmap::fromImageReader(&reader); + + return pixmap; +} + +QIcon UBBackgroundManager::createButtonIcon(const UBBackgroundRuling &background, bool dark) const +{ + QIcon icon; + + QPixmap pix = createButtonPixmap(background, dark, false); + icon.addPixmap(pix, QIcon::Normal, QIcon::Off); + + pix = createButtonPixmap(background, dark, true); + icon.addPixmap(pix, QIcon::Normal, QIcon::On); + + return icon; +} diff --git a/src/gui/UBBackgroundManager.h b/src/gui/UBBackgroundManager.h new file mode 100644 index 000000000..8375079dd --- /dev/null +++ b/src/gui/UBBackgroundManager.h @@ -0,0 +1,33 @@ +#pragma once + +#include "gui/UBBackgroundRuling.h" + +#include + +// forward +class QAction; + +class UBBackgroundManager : public QObject +{ + Q_OBJECT +public: + explicit UBBackgroundManager(QObject *parent = nullptr); + + void scan(); + void addBackground(UBBackgroundRuling& background); + const QList& backgrounds() const; + QAction* backgroundAction(const UBBackgroundRuling& background, bool dark); + void updateAction(QAction* action, bool dark) const; + const UBBackgroundRuling* background(const QUuid& uuid) const; + const UBBackgroundRuling* guessBackground(bool crossed, bool ruled, bool intermediateLines) const; + +private: + void scan(const QString& dirname); + QByteArray renderToSvg(const UBBackgroundRuling& background, bool dark) const; + QPixmap createButtonPixmap(const UBBackgroundRuling& background, bool dark, bool on) const; + QIcon createButtonIcon(const UBBackgroundRuling& background, bool dark) const; + +private: + QList mBackgrounds; +}; + diff --git a/src/gui/UBBackgroundPalette.cpp b/src/gui/UBBackgroundPalette.cpp index 00cc44b5c..719f77a19 100644 --- a/src/gui/UBBackgroundPalette.cpp +++ b/src/gui/UBBackgroundPalette.cpp @@ -1,19 +1,13 @@ #include "UBBackgroundPalette.h" +#include "gui/UBBackgroundManager.h" #include "gui/UBMainWindow.h" -UBBackgroundPalette::UBBackgroundPalette(QList actions, QWidget * parent) - : UBActionPalette(parent) -{ - init(); - setActions(actions); -} - - UBBackgroundPalette::UBBackgroundPalette(QWidget * parent) : UBActionPalette(parent) { init(); + createActions(); } @@ -47,20 +41,22 @@ void UBBackgroundPalette::init() mSlider->setTracking(true); // valueChanged() is emitted during movement and not just upon releasing the slider mSliderLabel = new QLabel(tr("Grid size")); - mIntermediateLinesLabel = new QLabel(tr("Draw intermediate grid lines")); + mLightDarkModeLabel = new QLabel(tr("Switch background color")); mResetDefaultGridSizeButton = createPaletteButton(UBApplication::mainWindow->actionDefaultGridSize, this); mResetDefaultGridSizeButton->setFixedSize(24,24); mActions << UBApplication::mainWindow->actionDefaultGridSize; + UBApplication::mainWindow->actionDefaultGridSize->setProperty("ungrouped", true); // don't add to action group + + connect(UBApplication::mainWindow->actionDefaultGridSize, &QAction::triggered, this, &UBBackgroundPalette::defaultBackgroundGridSize); - connect(UBApplication::mainWindow->actionDefaultGridSize, SIGNAL(triggered()), this, SLOT(defaultBackgroundGridSize())); + mLightDarkModeSwitch = createPaletteButton(UBApplication::mainWindow->actionLightDarkMode, this); + mLightDarkModeSwitch->setFixedSize(44,26); + mLightDarkModeSwitch->setCheckable(true); + mActions << UBApplication::mainWindow->actionLightDarkMode; + UBApplication::mainWindow->actionLightDarkMode->setProperty("ungrouped", true); // don't add to action group - mDrawIntermediateLinesCheckBox = createPaletteButton(UBApplication::mainWindow->actionDrawIntermediateGridLines, this); - mDrawIntermediateLinesCheckBox->setFixedSize(24,24); - mDrawIntermediateLinesCheckBox->setCheckable(true); - mActions << UBApplication::mainWindow->actionDrawIntermediateGridLines; - UBApplication::mainWindow->actionDrawIntermediateGridLines->setProperty("ungrouped", true); - connect(UBApplication::mainWindow->actionDrawIntermediateGridLines, SIGNAL(toggled(bool)), this, SLOT(toggleIntermediateLines(bool))); + connect(UBApplication::mainWindow->actionLightDarkMode, &QAction::triggered, this, &UBBackgroundPalette::toggleBackgroundColor); mBottomLayout->addSpacing(16); mBottomLayout->addWidget(mSliderLabel); @@ -68,13 +64,56 @@ void UBBackgroundPalette::init() mBottomLayout->addWidget(mResetDefaultGridSizeButton); mBottomLayout->addSpacing(16); - mBottomLayout->addWidget(mIntermediateLinesLabel); - mBottomLayout->addWidget(mDrawIntermediateLinesCheckBox); + mBottomLayout->addWidget(mLightDarkModeLabel); + mBottomLayout->addWidget(mLightDarkModeSwitch); mBottomLayout->addSpacing(16); updateLayout(); } +void UBBackgroundPalette::createActions() +{ + const QList& backgrounds = UBApplication::boardController->backgroundManager()->backgrounds(); + const auto dark = false; //UBApplication::boardController->activeScene()->isDarkBackground(); + const auto bgManager = UBApplication::boardController->backgroundManager(); + + for (int i = 0; i < backgrounds.size() && i < 6; ++i) + { + const auto& background = backgrounds.at(i); + auto action = bgManager->backgroundAction(background, dark); + UBBackgroundPalette::addAction(action); + + connect(action, &QAction::triggered, this, &UBBackgroundPalette::changeBackground); + } + + actionChanged(); +} + +void UBBackgroundPalette::updateActions() +{ + const auto scene = UBApplication::boardController->activeScene(); + const auto dark = scene->isDarkBackground(); + UBApplication::mainWindow->actionLightDarkMode->setChecked(dark); + QUuid uuid; + + if (scene && scene->background()) + { + uuid = scene->background()->uuid(); + qDebug() << "updateActions" << scene->background()->description("en"); + } + + for (auto& action : mActions) + { + QUuid actionUuid = action->property("uuid").toUuid(); + + if (!actionUuid.isNull()) + { + UBApplication::boardController->backgroundManager()->updateAction(action, dark); + action->setChecked(uuid == actionUuid); + } + } +} + void UBBackgroundPalette::addAction(QAction* action) { UBActionPaletteButton* button = createPaletteButton(action, this); @@ -148,7 +187,10 @@ void UBBackgroundPalette::showEvent(QShowEvent* event) connect(mSlider, SIGNAL(valueChanged(int)), this, SLOT(sliderValueChanged(int))); - mDrawIntermediateLinesCheckBox->setChecked(UBApplication::boardController->activeScene()->intermediateLines()); + const auto scene = UBApplication::boardController->activeScene(); + mIsDark = scene->isDarkBackground(); + mLightDarkModeSwitch->setChecked(mIsDark); + mBackground = scene->background(); QWidget::showEvent(event); } @@ -167,10 +209,26 @@ void UBBackgroundPalette::defaultBackgroundGridSize() sliderValueChanged(UBSettings::settings()->defaultCrossSize); } -void UBBackgroundPalette::toggleIntermediateLines(bool checked) +void UBBackgroundPalette::toggleBackgroundColor(bool checked) +{ + mIsDark = checked; + UBApplication::boardController->activeScene()->setSceneBackground(mIsDark, mBackground); + backgroundChanged(); +} + +void UBBackgroundPalette::changeBackground(bool checked) { - UBApplication::boardController->activeScene()->setIntermediateLines(checked); - UBSettings::settings()->intermediateLines = checked; // since this function is called (indirectly, by refresh) when we switch scenes, the settings will always have the current scene's value. + if (checked) + { + QAction* action = dynamic_cast(sender()); + + if (action) + { + const auto uuid = action->property("uuid").toUuid(); + mBackground = UBApplication::boardController->backgroundManager()->background(uuid); + UBApplication::boardController->activeScene()->setSceneBackground(mIsDark, mBackground); + } + } } void UBBackgroundPalette::backgroundChanged() @@ -180,13 +238,15 @@ void UBBackgroundPalette::backgroundChanged() if (dark) { mSliderLabel->setStyleSheet("QLabel { color : white; }"); - mIntermediateLinesLabel->setStyleSheet("QLabel { color : white; }"); + mLightDarkModeLabel->setStyleSheet("QLabel { color : white; }"); } else { mSliderLabel->setStyleSheet("QLabel { color : black; }"); - mIntermediateLinesLabel->setStyleSheet("QLabel { color : black; }"); + mLightDarkModeLabel->setStyleSheet("QLabel { color : black; }"); } + + updateActions(); } void UBBackgroundPalette::refresh() diff --git a/src/gui/UBBackgroundPalette.h b/src/gui/UBBackgroundPalette.h index 5a149a0fe..41d219202 100644 --- a/src/gui/UBBackgroundPalette.h +++ b/src/gui/UBBackgroundPalette.h @@ -6,13 +6,14 @@ #include "board/UBBoardController.h" #include "domain/UBGraphicsScene.h" +// forward +class UBBackgroundManager; + class UBBackgroundPalette : public UBActionPalette { Q_OBJECT public: - - UBBackgroundPalette(QList actions, QWidget* parent = 0); UBBackgroundPalette(QWidget* parent = 0); void addAction(QAction *action); @@ -28,23 +29,28 @@ class UBBackgroundPalette : public UBActionPalette protected slots: void sliderValueChanged(int value); void defaultBackgroundGridSize(); - void toggleIntermediateLines(bool checked); + void toggleBackgroundColor(bool checked); + void changeBackground(bool checked); protected: virtual void updateLayout(); void init(); + void createActions(); + void updateActions(); - + private: QVBoxLayout* mVLayout; QHBoxLayout* mTopLayout; QHBoxLayout* mBottomLayout; QSlider* mSlider; QLabel* mSliderLabel; - QLabel* mIntermediateLinesLabel; + QLabel* mLightDarkModeLabel; UBActionPaletteButton* mResetDefaultGridSizeButton; - UBActionPaletteButton* mDrawIntermediateLinesCheckBox; + UBActionPaletteButton* mLightDarkModeSwitch; + bool mIsDark{false}; + const UBBackgroundRuling* mBackground{nullptr}; }; #endif // UBBACKGROUNDPALETTE_H diff --git a/src/gui/UBBackgroundRuling.cpp b/src/gui/UBBackgroundRuling.cpp new file mode 100644 index 000000000..866f532d6 --- /dev/null +++ b/src/gui/UBBackgroundRuling.cpp @@ -0,0 +1,957 @@ +#include "UBBackgroundRuling.h" + +#include "core/UBSettings.h" + +#include +#include +#include +#include +#include +#include + +// namespace and element names +static constexpr char const* namespaceURI{"http://openboard.org/template/background/"}; + + +// helper functions +static bool getStringValue(QXmlStreamReader& reader, const QString& name, QString& value) +{ + if (reader.isStartElement() && reader.namespaceUri() == namespaceURI && reader.name() == name) + { + const auto text = reader.readElementText(); + + if (!reader.hasError()) + { + value = text; + return true; + } + } + + return false; +} + +static bool getDecimalValue(QXmlStreamReader& reader, const QString& name, double& value) +{ + QString text; + + if (getStringValue(reader, name, text)) + { + bool ok{true}; + value = text.toDouble(&ok); + return ok; + } + + return false; +} + +static bool getColorValue(QXmlStreamReader& reader, const QString& name, QColor& color) +{ + QString colorValue; + + if (getStringValue(reader, name, colorValue)) + { + if (colorValue.startsWith("#")) + { + color = colorValue; + return true; + } + else + { + bool ok; + const auto alpha = colorValue.toDouble(&ok); + + if (ok) + { + color.setAlphaF(color.alphaF() * alpha); + return true; + } + } + } + + return false; +} + +static double distance(const QLineF& line, const QPointF& point) +{ + if (line.isNull()) + { + return QLineF(line.p1(), point).length(); + } + + const auto a = line.y1() - line.y2(); + const auto b = line.x2() - line.x1(); + const auto c = line.x1() * line.y2() - line.x2() * line.y1(); + + return (a * point.x() + b * point.y() + c) / std::sqrt(a * a + b * b); +} + +// Liang—Barsky line-clipping algorithm +// inspired by https://en.wikipedia.org/wiki/Liang%E2%80%93Barsky_algorithm +bool clip(const QRectF& rect, QLineF& line) +{ + // defining variables + const auto p1 = -line.dx(); + const auto p3 = -line.dy(); + + const auto q1 = line.x1() - rect.left(); + const auto q2 = rect.right() - line.x1(); + const auto q3 = line.y1() - rect.top(); + const auto q4 = rect.bottom() - line.y1(); + + qreal posarr[5]{1}; + qreal negarr[5]{0}; + int posind = 1; + int negind = 1; + + if ((p1 == 0 && q1 < 0) || (p1 == 0 && q2 < 0) || (p3 == 0 && q3 < 0) || (p3 == 0 && q4 < 0)) + { + return false; + } + + if (p1 != 0) + { + const auto r1 = q1 / p1; + const auto r2 = q2 / -p1; + + if (p1 < 0) + { + negarr[negind++] = r1; // for negative p1, add it to negative array + posarr[posind++] = r2; // and add r2 to positive array + } + else + { + negarr[negind++] = r2; + posarr[posind++] = r1; + } + } + + if (p3 != 0) + { + const auto r3 = q3 / p3; + const auto r4 = q4 / -p3; + + if (p3 < 0) + { + negarr[negind++] = r3; + posarr[posind++] = r4; + } + else + { + negarr[negind++] = r4; + posarr[posind++] = r3; + } + } + + const auto rn1 = *std::max_element(negarr, negarr + negind); // maximum of negative array + const auto rn2 = *std::min_element(posarr, posarr + posind); // minimum of positive array + + if (rn1 > rn2) + { + // reject + return false; + } + + // computing new points + qreal xn1, yn1, xn2, yn2; + xn1 = line.x1() - p1 * rn1; + yn1 = line.y1() - p3 * rn1; + + xn2 = line.x1() - p1 * rn2; + yn2 = line.y1() - p3 * rn2; + + line.setLine(xn1, yn1, xn2, yn2); + + return true; +} + + +UBBackgroundRuling::UBBackgroundRuling() +{ +} + +bool UBBackgroundRuling::parseXml(QXmlStreamReader &reader) +{ + mRules = std::shared_ptr(Rules::fromXml(reader)); + return mRules && !mRules->hasError(); +} + +bool UBBackgroundRuling::toXml(QXmlStreamWriter &writer) const +{ + if (mRules) + { + mRules->toXml(writer); + return true; + } + + return false; +} + +bool UBBackgroundRuling::isValid() const +{ + return mRules && !mRules->hasError(); +} + +QUuid UBBackgroundRuling::uuid() const +{ + if (!mRules) + { + return {}; + } + + return mRules->uuid(); +} + +QString UBBackgroundRuling::description(const QString& languagecode) const +{ + if (!mRules) + { + return {}; + } + + return mRules->description(languagecode); +} + +bool UBBackgroundRuling::isCrossed() const +{ + if (!mRules) + { + return false; + } + + return mRules->isCrossed(); +} + +bool UBBackgroundRuling::isRuled() const +{ + if (!mRules) + { + return false; + } + + return mRules->isRuled(); +} + +bool UBBackgroundRuling::hasIntermediateLines() const +{ + if (!mRules) + { + return false; + } + + return mRules->hasIntermediateLines(); +} + +void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double gridSize, const QRectF& nominalScene, + bool onDark) const +{ + if (!mRules) + { + return; + } + + if (gridSize == 0) + { + // guess reasonable grid size for buttons + // at least two spacings on rect, else 12. + double spacing{0}; + + if (!mRules->linegroups().empty()) + { + spacing = mRules->linegroups().at(0).spacing(); + } + + if (spacing > 0) + { + // factor 10: spacing is in mm + // factor 2.5: at least 2.5 repetitions in button + // limit 12: reasonable limit for small spacings, about 1/3 of grid size on screen + gridSize = std::min(rect.height() / (2.5 * spacing / 10.), 12.); + } + } + + painter->setRenderHint(QPainter::Antialiasing, true); + const auto defaultOnDark = QColor(UBSettings::settings()->boardCrossColorDarkBackground->get().toString()); + const auto defaultOnLight = QColor(UBSettings::settings()->boardCrossColorLightBackground->get().toString()); + + // loop through line groups + for (const auto& linegroup : mRules->linegroups()) + { + const auto angle = linegroup.angle(); + const auto spacing = linegroup.spacing() * gridSize / 10; + + auto origin{nominalScene.center()}; + + switch (linegroup.origin()) + { + case Linegroup::Origin::TopLeft: + origin = nominalScene.topLeft(); + break; + + case Linegroup::Origin::TopRight: + origin = nominalScene.topRight(); + break; + + case Linegroup::Origin::BottomLeft: + origin = nominalScene.bottomLeft(); + break; + + case Linegroup::Origin::BottomRight: + origin = nominalScene.bottomRight(); + break; + + default: + break; + } + + // border needs different calculation of start and end of line + // relative to left and right border + double leftBorder{0}; + double rightBorder{0}; + + bool hasLeftBorder{false}; + bool hasRightBorder{false}; + + QList borderLines; + + if (linegroup.border()) + { + const auto border = linegroup.border().value(); + + hasLeftBorder = border.left().has_value(); + hasRightBorder = border.right().has_value(); + + leftBorder = border.left().value_or(0); + rightBorder = border.right().value_or(0); + + leftBorder *= gridSize / 10; + rightBorder *= gridSize / 10; + + borderLines = border.lines(); + } + + // loop through lines + for (const auto& line : linegroup.lines()) + { + const auto offset = line.offset() * gridSize / 10; + + setLinePainter(painter, line, onDark, defaultOnDark, defaultOnLight); + + // get relevant corners of rectangle according to line angle + const bool ascending = int(angle / 90.) % 2 == 0; + + QPointF p1; + QPointF p2; + + if (ascending) + { + p1 = rect.topLeft(); + p2 = rect.bottomRight(); + } + else + { + p1 = rect.topRight(); + p2 = rect.bottomLeft(); + } + + // create a line through origin + auto originLine = QLineF::fromPolar(5000, angle).translated(origin); + originLine.setP1(origin + origin - originLine.p2()); // extend in other direction + + if (spacing > 0) + { + // calculate offsets for first and last lines + auto minIndex = int(distance(originLine, p1) / spacing); + auto maxIndex = int(distance(originLine, p2) / spacing); + + if (minIndex > maxIndex) + { + std::swap(minIndex, maxIndex); + } + + // normal vector for translations + auto normal = originLine.normalVector(); + normal.setLength(spacing); + auto spaceShift = normal.p1() - normal.p2(); + normal.setLength(offset); + auto offsetShift = normal.p1() - normal.p2(); + + const auto lastLine = &line == &linegroup.lines().last(); + + for (int index = minIndex - 1; index <= maxIndex; ++index) + { + auto gridLine = originLine.translated(index * spaceShift + offsetShift); + + if (hasLeftBorder) + { + auto p1 = gridLine.p1(); + p1.setX(nominalScene.left() + leftBorder); + gridLine.setP1(p1); + + if (lastLine) + { + // draw border lines on left side + QLineF borderLine{p1 - offsetShift, p1}; + + if (clip(rect, borderLine)) + { + drawBorderLines(painter, borderLines, borderLine, Qt::LeftEdge, gridSize, onDark, + defaultOnDark, defaultOnLight); + } + } + } + + if (hasRightBorder) + { + auto p2 = gridLine.p2(); + p2.setX(nominalScene.right() - rightBorder); + gridLine.setP2(p2); + + if (lastLine) + { + // draw border lines on right side + QLineF borderLine{p2 - offsetShift, p2}; + + if (clip(rect, borderLine)) + { + drawBorderLines(painter, borderLines, borderLine, Qt::RightEdge, gridSize, onDark, + defaultOnDark, defaultOnLight); + } + } + } + + if (clip(rect, gridLine)) + { + painter->drawLine(gridLine); + } + } + } + else if (spacing == 0) + { + // single line at offset + auto normal = originLine.normalVector(); + normal.setLength(offset); + auto offsetShift = normal.p1() - normal.p2(); + auto gridLine = originLine.translated(offsetShift); + + if (clip(rect, gridLine)) + { + painter->drawLine(gridLine); + } + } + } + } +} + +void UBBackgroundRuling::setLinePainter(QPainter* painter, const Line& line, bool onDark, QColor defaultOnDark, + QColor defaultOnLight) const +{ + const auto width = line.width(); + + const auto colorOnDark = line.color().onDark(); + const auto colorOnLight = line.color().onLight(); + + // apply alpha value to defaults + defaultOnDark.setAlphaF(colorOnDark.alphaF()); + defaultOnLight.setAlphaF(colorOnLight.alphaF()); + + auto pen = painter->pen(); + pen.setWidth(width); + pen.setColor(onDark ? (colorOnDark.isValid() ? colorOnDark : defaultOnDark) + : (colorOnLight.isValid() ? colorOnLight : defaultOnLight)); + pen.setCapStyle(Qt::FlatCap); + painter->setPen(pen); +} + +void UBBackgroundRuling::drawBorderLines(QPainter* painter, const QList& borderLines, QLineF line, Qt::Edge edge, + double gridSize, bool onDark, QColor defaultOnDark, QColor defaultOnLight) const +{ + painter->save(); + + for (const auto& borderLine : borderLines) + { + setLinePainter(painter, borderLine, onDark, defaultOnDark, defaultOnLight); + + auto offset = borderLine.offset(); + offset *= gridSize / 10; + + if (edge == Qt::RightEdge) + { + offset = -offset; + } + + painter->drawLine(line.translated({offset, 0})); + } + + painter->restore(); +} + +// ==================== +// private data classes +// ==================== + +UBBackgroundRuling::Data::Data(Rules& rules) + : mRules{&rules} +{ +} + +bool UBBackgroundRuling::Data::hasError() const +{ + return mError; +} + +void UBBackgroundRuling::Data::setError(bool error) +{ + mError = error; +} + +const UBBackgroundRuling::Rules& UBBackgroundRuling::Data::rules() const +{ + return *mRules; +} + +UBBackgroundRuling::LineColor::LineColor(const Rules &rules, QXmlStreamReader &reader) + : Data{rules} + , mOnDark{rules.defaultColor().onDark()} + , mOnLight{rules.defaultColor().onLight()} +{ + while (reader.readNextStartElement() && reader.namespaceUri() == namespaceURI) + { + if (getColorValue(reader, "onDark", mOnDark)) + { + } + else if (getColorValue(reader, "onLight", mOnLight)) + { + } + else + { + setError(); + } + } +} + +UBBackgroundRuling::LineColor::LineColor(const UBBackgroundRuling::Rules& rules, const QColor& colorOnDark, + const QColor& colorOnLight) + : Data{rules} + , mOnDark{colorOnDark} + , mOnLight{colorOnLight} +{ +} + +void UBBackgroundRuling::LineColor::toXml(QXmlStreamWriter &writer) const +{ + if (mOnDark.isValid()) + { + writer.writeTextElement(namespaceURI, "onDark", mOnDark.name(QColor::HexArgb)); + } + + if (mOnLight.isValid()) + { + writer.writeTextElement(namespaceURI, "onDark", mOnLight.name(QColor::HexArgb)); + } +} + +const QColor& UBBackgroundRuling::LineColor::onDark() const +{ + return mOnDark; +} + +const QColor& UBBackgroundRuling::LineColor::onLight() const +{ + return mOnLight; +} + +UBBackgroundRuling::Line::Line(const Rules &rules, QXmlStreamReader &reader) + : Data{rules} + , mColor{rules.defaultColor()} +{ + while (reader.readNextStartElement() && reader.namespaceUri() == namespaceURI) + { + if (getDecimalValue(reader, "offset", mOffset)) + { + } + else if (getDecimalValue(reader, "width", mWidth)) + { + } + else if (reader.name() == "color") + { + mColor = LineColor{rules, reader}; + } + else + { + setError(); + } + } +} + +void UBBackgroundRuling::Line::toXml(QXmlStreamWriter &writer) const +{ + writer.writeTextElement(namespaceURI, "offset", QString::number(mOffset)); + writer.writeTextElement(namespaceURI, "width", QString::number(mWidth)); + + if (mColor.onDark().isValid() || mColor.onLight().isValid()) + { + writer.writeStartElement(namespaceURI, "color"); + mColor.toXml(writer); + writer.writeEndElement(); + } +} + +double UBBackgroundRuling::Line::offset() const +{ + return mOffset; +} + +double UBBackgroundRuling::Line::width() const +{ + return mWidth; +} + +const UBBackgroundRuling::LineColor& UBBackgroundRuling::Line::color() const +{ + return mColor; +} + +UBBackgroundRuling::Border::Border(const Rules &rules, QXmlStreamReader &reader) + : Data{rules} +{ + while (reader.readNextStartElement() && reader.namespaceUri() == namespaceURI) + { + double value; + + if (getDecimalValue(reader, "left", value)) + { + mLeft.emplace(value); + } + else if (getDecimalValue(reader, "right", value)) + { + mRight.emplace(value); + } + else if (reader.name() == "line") + { + const Line bgLine{rules, reader}; + + if (bgLine.hasError()) + { + setError(); + } + else + { + mLines.append(bgLine); + } + } + } +} + +void UBBackgroundRuling::Border::toXml(QXmlStreamWriter &writer) const +{ + if (mLeft) + { + writer.writeTextElement(namespaceURI, "left", QString::number(mLeft.value())); + } + + if (mRight) + { + writer.writeTextElement(namespaceURI, "right", QString::number(mRight.value())); + } + + for (const auto& line : mLines) + { + writer.writeStartElement(namespaceURI, "line"); + line.toXml(writer); + writer.writeEndElement(); + } +} + +std::optional UBBackgroundRuling::Border::left() const +{ + return mLeft; +} + +std::optional UBBackgroundRuling::Border::right() const +{ + return mRight; +} + +const QList& UBBackgroundRuling::Border::lines() const +{ + return mLines; +} + +UBBackgroundRuling::Linegroup::Linegroup(const Rules &rules, QXmlStreamReader &reader) + : Data{rules} +{ + QString lineGroupOrigin; + + while (reader.readNextStartElement() && reader.namespaceUri() == namespaceURI) + { + if (getDecimalValue(reader, "angle", mAngle)) + { + } + else if (getDecimalValue(reader, "spacing", mSpacing)) + { + } + else if (getStringValue(reader, "origin", lineGroupOrigin)) + { + if (lineGroupOrigin == "topleft") + { + mOrigin = Origin::TopLeft; + } + else if (lineGroupOrigin == "topright") + { + mOrigin = Origin::TopRight; + } + else if (lineGroupOrigin == "bottomleft") + { + mOrigin = Origin::BottomLeft; + } + else if (lineGroupOrigin == "bottomright") + { + mOrigin = Origin::BottomRight; + } + else if (lineGroupOrigin == "center") + { + mOrigin = Origin::Center; + } + else + { + setError(); + } + } + else if (reader.name() == "line") + { + const Line bgLine{rules, reader}; + + if (bgLine.hasError()) + { + setError(); + } + else + { + mLines.append(bgLine); + } + } + else if (reader.name() == "border") + { + mBorder.emplace(rules, reader); + } + else + { + setError(); + } + } +} + +void UBBackgroundRuling::Linegroup::toXml(QXmlStreamWriter &writer) const +{ + writer.writeTextElement(namespaceURI, "angle", QString::number(mAngle)); + + if (mSpacing != 0) + { + writer.writeTextElement(namespaceURI, "spacing", QString::number(mSpacing)); + } + + QString origin; + + switch (mOrigin) + { + case Origin::Center: origin = "center"; break; + case Origin::TopLeft: origin = "topleft"; break; + case Origin::TopRight: origin = "topright"; break; + case Origin::BottomLeft: origin = "bottomleft"; break; + case Origin::BottomRight: origin = "bottomright"; break; + } + + writer.writeTextElement(namespaceURI, "origin", origin); + + for (const auto& line : mLines) + { + writer.writeStartElement(namespaceURI, "line"); + line.toXml(writer); + writer.writeEndElement(); + } + + if (mBorder) + { + writer.writeStartElement(namespaceURI, "border"); + mBorder.value().toXml(writer); + writer.writeEndElement(); + } +} + +double UBBackgroundRuling::Linegroup::angle() const +{ + return mAngle; +} + +double UBBackgroundRuling::Linegroup::spacing() const +{ + return mSpacing; +} + +UBBackgroundRuling::Linegroup::Origin UBBackgroundRuling::Linegroup::origin() const +{ + return mOrigin; +} + +const QList& UBBackgroundRuling::Linegroup::lines() const +{ + return mLines; +} + +std::optional UBBackgroundRuling::Linegroup::border() const +{ + return mBorder; +} + +UBBackgroundRuling::Rules::Rules(QXmlStreamReader &reader) + : Data{*this} + , mDefaultColor{*this, {}, {}} +{ + // current position of reader should be at the element + while (!reader.isEndElement()) + { + while (reader.readNextStartElement() && reader.namespaceUri() == namespaceURI) + { + const auto name = reader.name(); + + QString text; + + if (getStringValue(reader, "uuid", text)) + { + mUuid = QUuid(text); + } + else if (name == "description") + { + const auto attributes = reader.attributes(); + const auto lang = attributes.value("xml:lang").toString(); + + mDescriptions[lang.isEmpty() ? "en" : lang] = reader.readElementText(); + } + else if (name == "attributes") + { + const auto attributes = reader.attributes(); + mCrossed = attributes.value("crossed") == "true"; + mRuled = attributes.value("ruled") == "true"; + mIntermediateLines = attributes.value("intermediateLines") == "true"; + reader.skipCurrentElement(); + } + else if (name == "defaultColor") + { + mDefaultColor = LineColor{*this, reader}; + } + else if (name == "linegroup") + { + const Linegroup bgLinegroup{*this, reader}; + + if (bgLinegroup.hasError()) + { + setError(); + } + else + { + mLinegroups.append(bgLinegroup); + } + } + else + { + setError(); + } + } + } +} + +UBBackgroundRuling::Rules* UBBackgroundRuling::Rules::fromXml(QXmlStreamReader &reader) +{ + if (reader.namespaceUri() == namespaceURI && reader.name() == "background") + { + return new Rules(reader); + } + + return nullptr; +} + +void UBBackgroundRuling::Rules::toXml(QXmlStreamWriter &writer) const +{ + writer.writeNamespace(namespaceURI, "bg"); + writer.writeStartElement(namespaceURI, "background"); + writer.writeTextElement(namespaceURI, "uuid", mUuid.toString(QUuid::WithoutBraces)); + + for (auto description = mDescriptions.constKeyValueBegin(); description != mDescriptions.constKeyValueEnd(); ++description) + { + writer.writeStartElement(namespaceURI, "description"); + writer.writeAttribute("xml:lang", description->first); + writer.writeCharacters(description->second); + writer.writeEndElement(); + } + + if (mCrossed || mRuled) + { + writer.writeEmptyElement(namespaceURI, "attributes"); + + if (mCrossed) + { + writer.writeAttribute("crossed", "true"); + } + + if (mRuled) + { + writer.writeAttribute("ruled", "true"); + } + + if (mIntermediateLines) + { + writer.writeAttribute("intermediateLines", "true"); + } + } + + if (mDefaultColor.onDark().isValid() || mDefaultColor.onLight().isValid()) + { + writer.writeStartElement(namespaceURI, "defaultColor"); + mDefaultColor.toXml(writer); + writer.writeEndElement(); + } + + for (const auto& linegroup : mLinegroups) + { + writer.writeStartElement(namespaceURI, "linegroup"); + linegroup.toXml(writer); + writer.writeEndElement(); + } + + writer.writeEndElement(); +} + +QUuid UBBackgroundRuling::Rules::uuid() const +{ + return mUuid; +} + +QString UBBackgroundRuling::Rules::description(const QString& languagecode) const +{ + return mDescriptions.value(languagecode, mDescriptions.value("en")); +} + +bool UBBackgroundRuling::Rules::isCrossed() const +{ + return mCrossed; +} + +bool UBBackgroundRuling::Rules::isRuled() const +{ + return mRuled; +} + +bool UBBackgroundRuling::Rules::hasIntermediateLines() const +{ + return mIntermediateLines; +} + +UBBackgroundRuling::LineColor UBBackgroundRuling::Rules::defaultColor() const +{ + return mDefaultColor; +} + +const QList& UBBackgroundRuling::Rules::linegroups() const +{ + return mLinegroups; +} diff --git a/src/gui/UBBackgroundRuling.h b/src/gui/UBBackgroundRuling.h new file mode 100644 index 000000000..f3a9544c2 --- /dev/null +++ b/src/gui/UBBackgroundRuling.h @@ -0,0 +1,168 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +// forward +class QPainter; + + +class UBBackgroundRuling +{ +public: + UBBackgroundRuling(); + + bool parseXml(QXmlStreamReader& reader); + bool toXml(QXmlStreamWriter& writer) const; + + bool isValid() const; + QUuid uuid() const; + QString description(const QString& languagecode) const; + bool isCrossed() const; + bool isRuled() const; + bool hasIntermediateLines() const; + + void draw(QPainter *painter, const QRectF &rect, double gridSize, const QRectF &nominalScene, bool onDark) const; + +private: + class Line; + void setLinePainter(QPainter* painter, const Line& line, bool onDark, QColor defaultOnDark, QColor defaultOnLight) const; + void drawBorderLines(QPainter* painter, const QList& borderLines, QLineF line, Qt::Edge edge, double gridSize, bool onDark, QColor defaultOnDark, QColor defaultOnLight) const; + +private: + // data classes + class Rules; + + class Data + { + public: + explicit Data(Rules &rules); + + bool hasError() const; + virtual void toXml(QXmlStreamWriter& writer) const = 0; + + protected: + void setError(bool error = true); + const Rules& rules() const; + + private: + bool mError{false}; + Rules* mRules{nullptr}; + }; + + class LineColor : public Data + { + public: + LineColor(const Rules& rules, QXmlStreamReader &reader); + LineColor(const Rules& rules, const QColor &colorOnDark, const QColor &colorOnLight); + + virtual void toXml(QXmlStreamWriter& writer) const override; + + const QColor& onDark() const; + const QColor& onLight() const; + + private: + QColor mOnDark{}; + QColor mOnLight{}; + }; + + class Line : public Data + { + public: + Line(const Rules& rules, QXmlStreamReader& reader); + + virtual void toXml(QXmlStreamWriter& writer) const override; + + double offset() const; + double width() const; + const LineColor& color() const; + + private: + double mOffset{0.}; + double mWidth{1.}; + LineColor mColor; + }; + + class Border : public Data + { + public: + Border(const Rules& rules, QXmlStreamReader& reader); + + virtual void toXml(QXmlStreamWriter& writer) const override; + + std::optional left() const; + std::optional right() const; + const QList& lines() const; + + private: + std::optional mLeft{}; + std::optional mRight{}; + QList mLines{}; + }; + + class Linegroup : public Data + { + public: + enum class Origin + { + Center, + TopLeft, + TopRight, + BottomLeft, + BottomRight + }; + + Linegroup(const Rules& rules, QXmlStreamReader& reader); + + virtual void toXml(QXmlStreamWriter& writer) const override; + + double angle() const; + double spacing() const; + Origin origin() const; + const QList& lines() const; + std::optional border() const; + + private: + double mAngle{0.}; + double mSpacing{0.}; + Origin mOrigin{Origin::Center}; + QList mLines{}; + std::optional mBorder{}; + }; + + class Rules : public Data + { + public: + explicit Rules(QXmlStreamReader &reader); + + static Rules* fromXml(QXmlStreamReader& reader); + + virtual void toXml(QXmlStreamWriter& writer) const override; + + QUuid uuid() const; + QString description(const QString& languagecode = QString{}) const; + bool isCrossed() const; + bool isRuled() const; + bool hasIntermediateLines() const; + LineColor defaultColor() const; + const QList& linegroups() const; + + private: + QUuid mUuid{}; + QMap mDescriptions{}; + bool mCrossed{false}; + bool mRuled{false}; + bool mIntermediateLines{false}; + LineColor mDefaultColor; + QList mLinegroups{}; + }; + +private: + std::shared_ptr mRules{nullptr}; +}; + diff --git a/src/gui/gui.pri b/src/gui/gui.pri index 831d06d18..9e7b831a9 100644 --- a/src/gui/gui.pri +++ b/src/gui/gui.pri @@ -45,6 +45,8 @@ HEADERS += \ src/gui/UBFeaturesActionBar.h \ src/gui/UBMessagesDialog.h \ src/gui/UBBackgroundPalette.h \ + src/gui/UBBackgroundManager.h \ + src/gui/UBBackgroundRuling.h \ src/gui/UBBoardThumbnailsView.h \ src/gui/UBSnapIndicator.h SOURCES += \ @@ -94,8 +96,11 @@ SOURCES += \ src/gui/UBFeaturesActionBar.cpp \ src/gui/UBMessagesDialog.cpp \ src/gui/UBBackgroundPalette.cpp \ + src/gui/UBBackgroundManager.cpp \ + src/gui/UBBackgroundRuling.cpp \ src/gui/UBBoardThumbnailsView.cpp \ src/gui/UBSnapIndicator.cpp + win32:SOURCES += src/gui/UBKeyboardPalette_win.cpp macx:OBJECTIVE_SOURCES += src/gui/UBKeyboardPalette_mac.mm linux-g++:SOURCES += src/gui/UBKeyboardPalette_linux.cpp From 2ee1b99b80e53d7228f8a5b228f89ddb86e66da0 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 11 Feb 2024 18:15:04 +0100 Subject: [PATCH 085/133] feat: add preferences widget for preferred backgrounds - add a widget to the "Grid" preferences page - display all available background rulings - allow to reorder rulings by DnD - first six background rulings will be in background palette - persist preferred rulings --- resources/forms/preferences.ui | 33 ++-- src/core/UBPreferencesController.cpp | 4 +- src/gui/CMakeLists.txt | 4 + src/gui/UBActionPalette.cpp | 21 +++ src/gui/UBActionPalette.h | 1 + src/gui/UBBackgroundManager.cpp | 149 +++++++++------ src/gui/UBBackgroundManager.h | 10 +- src/gui/UBBackgroundPalette.cpp | 37 +++- src/gui/UBFlowLayout.cpp | 191 +++++++++++++++++++ src/gui/UBFlowLayout.h | 36 ++++ src/gui/UBPreferredBackgroundWidget.cpp | 232 ++++++++++++++++++++++++ src/gui/UBPreferredBackgroundWidget.h | 43 +++++ 12 files changed, 681 insertions(+), 80 deletions(-) create mode 100644 src/gui/UBFlowLayout.cpp create mode 100644 src/gui/UBFlowLayout.h create mode 100644 src/gui/UBPreferredBackgroundWidget.cpp create mode 100644 src/gui/UBPreferredBackgroundWidget.h diff --git a/resources/forms/preferences.ui b/resources/forms/preferences.ui index 45a2fc180..2b92868e8 100644 --- a/resources/forms/preferences.ui +++ b/resources/forms/preferences.ui @@ -673,6 +673,26 @@ Grid + + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 1032 + 220 + + + + + @@ -918,19 +938,6 @@ - - - - Qt::Vertical - - - - 20 - 342 - - - - diff --git a/src/core/UBPreferencesController.cpp b/src/core/UBPreferencesController.cpp index ed0e393d8..8b5e05a97 100644 --- a/src/core/UBPreferencesController.cpp +++ b/src/core/UBPreferencesController.cpp @@ -49,7 +49,7 @@ #include "ui_preferences.h" #include "core/memcheck.h" - +#include "gui/UBPreferredBackgroundWidget.h" qreal UBPreferencesController::sSliderRatio = 10.0; qreal UBPreferencesController::sMinPenWidth = 0.5; @@ -89,6 +89,8 @@ UBPreferencesController::UBPreferencesController(QWidget *parent) connect(UBApplication::displayManager, &UBDisplayManager::availableScreenCountChanged, this, &UBPreferencesController::adjustScreensPreferences); wire(); + auto* prefBgWidget = new UBPreferredBackgroundWidget(); + mPreferencesUI->bgScrollArea->setWidget(prefBgWidget); } diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 0d41ee950..66d3ecd4e 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -35,6 +35,8 @@ target_sources(${PROJECT_NAME} PRIVATE UBFeaturesActionBar.h UBFeaturesWidget.cpp UBFeaturesWidget.h + UBFlowLayout.cpp + UBFlowLayout.h UBFloatingPalette.cpp UBFloatingPalette.h UBIconButton.cpp @@ -55,6 +57,8 @@ target_sources(${PROJECT_NAME} PRIVATE UBMousePressFilter.h UBPageNavigationWidget.cpp UBPageNavigationWidget.h + UBPreferredBackgroundWidget.cpp + UBPreferredBackgroundWidget.h UBPropertyPalette.cpp UBPropertyPalette.h UBResources.cpp diff --git a/src/gui/UBActionPalette.cpp b/src/gui/UBActionPalette.cpp index 391020d6a..f39f1fbff 100644 --- a/src/gui/UBActionPalette.cpp +++ b/src/gui/UBActionPalette.cpp @@ -115,6 +115,27 @@ UBActionPaletteButton* UBActionPalette::createPaletteButton(QAction* action, QWi return button; } +QAction* UBActionPalette::removePaletteButton(UBActionPaletteButton* button) +{ + if (!button) + { + return nullptr; + } + + QAction* action = button->defaultAction(); + + mButtons.removeAll(button); + mActions.removeAll(action); + mMapActionToButton.remove(action); + + if (mActionGroup) + { + mActionGroup->removeAction(action); + } + + return action; +} + void UBActionPalette::addAction(QAction* action) { UBActionPaletteButton* button = createPaletteButton(action, this); diff --git a/src/gui/UBActionPalette.h b/src/gui/UBActionPalette.h index 9c1859be5..caea49928 100644 --- a/src/gui/UBActionPalette.h +++ b/src/gui/UBActionPalette.h @@ -104,6 +104,7 @@ class UBActionPalette : public UBFloatingPalette QSize mButtonSize; QPoint mMousePos; UBActionPaletteButton *createPaletteButton(QAction* action, QWidget *parent); + QAction* removePaletteButton(UBActionPaletteButton* button); protected slots: void buttonClicked(); diff --git a/src/gui/UBBackgroundManager.cpp b/src/gui/UBBackgroundManager.cpp index 8e6ffb773..58073dbe4 100644 --- a/src/gui/UBBackgroundManager.cpp +++ b/src/gui/UBBackgroundManager.cpp @@ -36,9 +36,32 @@ void UBBackgroundManager::addBackground(UBBackgroundRuling &background) } } -const QList &UBBackgroundManager::backgrounds() const +const QList UBBackgroundManager::backgrounds() const { - return mBackgrounds; + QList backgroundList; + + QStringList uuidList = UBSettings::settings()->value("Board/BackgroundRulingList").toStringList(); + + // first add rulings from list + for (const auto& uuid : uuidList) + { + const auto& ruling = background(uuid); + + if (ruling && ruling->isValid()) + { + backgroundList << ruling; + } + } + + for (const auto& ruling : mBackgrounds) + { + if (!uuidList.contains(ruling.uuid().toString())) + { + backgroundList << &ruling; + } + } + + return backgroundList; } QAction *UBBackgroundManager::backgroundAction(const UBBackgroundRuling &background, bool dark) @@ -92,60 +115,6 @@ const UBBackgroundRuling* UBBackgroundManager::guessBackground(bool crossed, boo return nullptr; } -void UBBackgroundManager::scan(const QString &dirname) -{ - const QDir dir{dirname}; - - if (dir.exists()) - { - const auto list = dir.entryInfoList({"*.xml"}, QDir::Files, QDir::Name); - - for (const auto& entry : list) - { - UBBackgroundRuling bg; - QFile file{entry.absoluteFilePath()}; - - if (!file.open(QFile::ReadOnly)) - { - continue; - } - - QXmlStreamReader reader(&file); - - if (reader.readNextStartElement()) - { - bg.parseXml(reader); - } - - if (bg.isValid()) - { - mBackgrounds.append(bg); - } - else - { - qWarning() << "Error reading background definitions from" << file; - } - } - } -} - -QByteArray UBBackgroundManager::renderToSvg(const UBBackgroundRuling &background, bool dark) const -{ - QSvgGenerator generator; - QBuffer buffer; - generator.setOutputDevice(&buffer); - generator.setSize(QSize(93, 75)); - generator.setViewBox(QRect(0, 0, 93, 75)); - - QPainter painter; - - painter.begin(&generator); - background.draw(&painter, {0, 0, 93, 75}, 0., {0, 0, 193, 75}, dark); - painter.end(); - - return buffer.buffer(); -} - QPixmap UBBackgroundManager::createButtonPixmap(const UBBackgroundRuling &background, bool dark, bool on) const { QString filename{"bgButtonTemplate"}; @@ -225,3 +194,71 @@ QIcon UBBackgroundManager::createButtonIcon(const UBBackgroundRuling &background return icon; } + +void UBBackgroundManager::savePreferredBackgrounds(QList& uuidList) const +{ + QStringList uuids; + + for (const auto& uuid : uuidList) + { + uuids << uuid.toString(); + } + + UBSettings::settings()->setValue("Board/BackgroundRulingList", uuids); + emit preferredBackgroundChanged(); +} + +void UBBackgroundManager::scan(const QString &dirname) +{ + const QDir dir{dirname}; + + if (dir.exists()) + { + const auto list = dir.entryInfoList({"*.xml"}, QDir::Files, QDir::Name); + + for (const auto& entry : list) + { + UBBackgroundRuling bg; + QFile file{entry.absoluteFilePath()}; + + if (!file.open(QFile::ReadOnly)) + { + continue; + } + + QXmlStreamReader reader(&file); + + if (reader.readNextStartElement()) + { + bg.parseXml(reader); + } + + if (bg.isValid()) + { + mBackgrounds.append(bg); + } + else + { + qWarning() << "Error reading background definitions from" << file; + } + } + } +} + +QByteArray UBBackgroundManager::renderToSvg(const UBBackgroundRuling &background, bool dark) const +{ + QSvgGenerator generator; + QBuffer buffer; + generator.setOutputDevice(&buffer); + generator.setSize(QSize(93, 75)); + generator.setViewBox(QRect(0, 0, 93, 75)); + + QPainter painter; + + painter.begin(&generator); + background.draw(&painter, {0, 0, 93, 75}, 0., {0, 0, 193, 75}, dark); + painter.end(); + + return buffer.buffer(); +} + diff --git a/src/gui/UBBackgroundManager.h b/src/gui/UBBackgroundManager.h index 8375079dd..53b98aec0 100644 --- a/src/gui/UBBackgroundManager.h +++ b/src/gui/UBBackgroundManager.h @@ -15,17 +15,21 @@ class UBBackgroundManager : public QObject void scan(); void addBackground(UBBackgroundRuling& background); - const QList& backgrounds() const; + const QList backgrounds() const; QAction* backgroundAction(const UBBackgroundRuling& background, bool dark); void updateAction(QAction* action, bool dark) const; const UBBackgroundRuling* background(const QUuid& uuid) const; const UBBackgroundRuling* guessBackground(bool crossed, bool ruled, bool intermediateLines) const; + QPixmap createButtonPixmap(const UBBackgroundRuling& background, bool dark, bool on) const; + QIcon createButtonIcon(const UBBackgroundRuling& background, bool dark) const; + void savePreferredBackgrounds(QList& uuidList) const; + +signals: + void preferredBackgroundChanged() const; private: void scan(const QString& dirname); QByteArray renderToSvg(const UBBackgroundRuling& background, bool dark) const; - QPixmap createButtonPixmap(const UBBackgroundRuling& background, bool dark, bool on) const; - QIcon createButtonIcon(const UBBackgroundRuling& background, bool dark) const; private: QList mBackgrounds; diff --git a/src/gui/UBBackgroundPalette.cpp b/src/gui/UBBackgroundPalette.cpp index 719f77a19..9395795fc 100644 --- a/src/gui/UBBackgroundPalette.cpp +++ b/src/gui/UBBackgroundPalette.cpp @@ -8,9 +8,10 @@ UBBackgroundPalette::UBBackgroundPalette(QWidget * parent) { init(); createActions(); -} - + connect(UBApplication::boardController->backgroundManager(), &UBBackgroundManager::preferredBackgroundChanged, + this, &UBBackgroundPalette::createActions); +} void UBBackgroundPalette::init() { @@ -73,33 +74,55 @@ void UBBackgroundPalette::init() void UBBackgroundPalette::createActions() { - const QList& backgrounds = UBApplication::boardController->backgroundManager()->backgrounds(); + // first delete everything from the top layout + while(!mTopLayout->isEmpty()) + { + QLayoutItem* pItem = mTopLayout->itemAt(0); + QWidget* pW = pItem->widget(); + mTopLayout->removeItem(pItem); + delete pItem; + mTopLayout->removeWidget(pW); + + QAction* action = removePaletteButton(dynamic_cast(pW)); + + delete pW; + delete action; + } + + // then add actions for the first 6 backgrounds from the background manager + const QList backgrounds = UBApplication::boardController->backgroundManager()->backgrounds(); const auto dark = false; //UBApplication::boardController->activeScene()->isDarkBackground(); const auto bgManager = UBApplication::boardController->backgroundManager(); for (int i = 0; i < backgrounds.size() && i < 6; ++i) { - const auto& background = backgrounds.at(i); - auto action = bgManager->backgroundAction(background, dark); + const auto background = backgrounds.at(i); + auto action = bgManager->backgroundAction(*background, dark); UBBackgroundPalette::addAction(action); connect(action, &QAction::triggered, this, &UBBackgroundPalette::changeBackground); } actionChanged(); + updateActions(); } void UBBackgroundPalette::updateActions() { const auto scene = UBApplication::boardController->activeScene(); + + if (!scene) + { + return; + } + const auto dark = scene->isDarkBackground(); UBApplication::mainWindow->actionLightDarkMode->setChecked(dark); QUuid uuid; - if (scene && scene->background()) + if (scene->background()) { uuid = scene->background()->uuid(); - qDebug() << "updateActions" << scene->background()->description("en"); } for (auto& action : mActions) diff --git a/src/gui/UBFlowLayout.cpp b/src/gui/UBFlowLayout.cpp new file mode 100644 index 000000000..71aeb91c6 --- /dev/null +++ b/src/gui/UBFlowLayout.cpp @@ -0,0 +1,191 @@ +#include "UBFlowLayout.h" +#include "qwidget.h" + +// inspired by https://doc.qt.io/qt-5/qtwidgets-layouts-flowlayout-example.html + +UBFlowLayout::UBFlowLayout(QWidget* parent, int margin, int hSpacing, int vSpacing) + : QLayout(parent) + , m_hSpace(hSpacing) + , m_vSpace(vSpacing) +{ + setContentsMargins(margin, margin, margin, margin); +} + +UBFlowLayout::UBFlowLayout(int margin, int hSpacing, int vSpacing) + : m_hSpace(hSpacing) + , m_vSpace(vSpacing) +{ + setContentsMargins(margin, margin, margin, margin); +} + +UBFlowLayout::~UBFlowLayout() +{ + QLayoutItem* item; + while ((item = UBFlowLayout::takeAt(0))) + delete item; +} + +void UBFlowLayout::addItem(QLayoutItem* item) +{ + itemList.append(item); +} + +void UBFlowLayout::insertItem(int index, QLayoutItem* item) +{ + itemList.insert(index, item); +} + +int UBFlowLayout::horizontalSpacing() const +{ + if (m_hSpace >= 0) + { + return m_hSpace; + } + else + { + return smartSpacing(QStyle::PM_LayoutHorizontalSpacing); + } +} + +int UBFlowLayout::verticalSpacing() const +{ + if (m_vSpace >= 0) + { + return m_vSpace; + } + else + { + return smartSpacing(QStyle::PM_LayoutVerticalSpacing); + } +} + +int UBFlowLayout::count() const +{ + return itemList.size(); +} + +QLayoutItem* UBFlowLayout::itemAt(int index) const +{ + return itemList.value(index); +} + +QLayoutItem* UBFlowLayout::takeAt(int index) +{ + if (index >= 0 && index < itemList.size()) + return itemList.takeAt(index); + + return nullptr; +} + +QLayoutItem* UBFlowLayout::replaceAt(int index, QLayoutItem* item) +{ + if (!item) + { + return nullptr; + } + + QLayoutItem* b = itemList.value(index); + + if (!b) + { + return nullptr; + } + + itemList.replace(index, item); + invalidate(); + return b; +} + +Qt::Orientations UBFlowLayout::expandingDirections() const +{ + return {}; +} + +bool UBFlowLayout::hasHeightForWidth() const +{ + return true; +} + +int UBFlowLayout::heightForWidth(int width) const +{ + int height = doLayout(QRect(0, 0, width, 0), true); + return height; +} + +void UBFlowLayout::setGeometry(const QRect& rect) +{ + QLayout::setGeometry(rect); + doLayout(rect, false); +} + +QSize UBFlowLayout::sizeHint() const +{ + return minimumSize(); +} + +QSize UBFlowLayout::minimumSize() const +{ + QSize size; + + for (const QLayoutItem* item : qAsConst(itemList)) + size = size.expandedTo(item->minimumSize()); + + const QMargins margins = contentsMargins(); + size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom()); + return size; +} + +int UBFlowLayout::doLayout(const QRect& rect, bool testOnly) const +{ + int left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); + int x = effectiveRect.x(); + int y = effectiveRect.y(); + int lineHeight = 0; + + for (QLayoutItem* item : qAsConst(itemList)) + { + const QWidget* wid = item->widget(); + int spaceX = horizontalSpacing(); + if (spaceX == -1) + spaceX = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal); + int spaceY = verticalSpacing(); + if (spaceY == -1) + spaceY = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); + int nextX = x + item->sizeHint().width() + spaceX; + if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) + { + x = effectiveRect.x(); + y = y + lineHeight + spaceY; + nextX = x + item->sizeHint().width() + spaceX; + lineHeight = 0; + } + + if (!testOnly) + item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); + + x = nextX; + lineHeight = qMax(lineHeight, item->sizeHint().height()); + } + return y + lineHeight - rect.y() + bottom; +} + +int UBFlowLayout::smartSpacing(QStyle::PixelMetric pm) const +{ + QObject* parent = this->parent(); + + if (!parent) + { + return -1; + } + else if (parent->isWidgetType()) + { + QWidget* pw = static_cast(parent); + return pw->style()->pixelMetric(pm, nullptr, pw); + } + else + { + return static_cast(parent)->spacing(); + } +} diff --git a/src/gui/UBFlowLayout.h b/src/gui/UBFlowLayout.h new file mode 100644 index 000000000..170cf4445 --- /dev/null +++ b/src/gui/UBFlowLayout.h @@ -0,0 +1,36 @@ +#pragma once + + +#include +#include + +class UBFlowLayout : public QLayout +{ +public: + explicit UBFlowLayout(QWidget* parent, int margin = -1, int hSpacing = -1, int vSpacing = -1); + explicit UBFlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1); + ~UBFlowLayout(); + + void addItem(QLayoutItem* item) override; + void insertItem(int index, QLayoutItem* item); + int horizontalSpacing() const; + int verticalSpacing() const; + Qt::Orientations expandingDirections() const override; + bool hasHeightForWidth() const override; + int heightForWidth(int) const override; + int count() const override; + QLayoutItem* itemAt(int index) const override; + QSize minimumSize() const override; + void setGeometry(const QRect& rect) override; + QSize sizeHint() const override; + QLayoutItem* takeAt(int index) override; + QLayoutItem* replaceAt(int index, QLayoutItem* item); + +private: + int doLayout(const QRect& rect, bool testOnly) const; + int smartSpacing(QStyle::PixelMetric pm) const; + + QList itemList; + int m_hSpace; + int m_vSpace; +}; diff --git a/src/gui/UBPreferredBackgroundWidget.cpp b/src/gui/UBPreferredBackgroundWidget.cpp new file mode 100644 index 000000000..2e927ff27 --- /dev/null +++ b/src/gui/UBPreferredBackgroundWidget.cpp @@ -0,0 +1,232 @@ +#include "UBPreferredBackgroundWidget.h" + +#include "board/UBBoardController.h" +#include "core/UBApplication.h" +#include "gui/UBBackgroundManager.h" +#include "gui/UBFlowLayout.h" + + + +UBPreferredBackgroundWidget::UBPreferredBackgroundWidget(QWidget* parent) + : QWidget(parent) +{ + setAcceptDrops(true); + + mLayout = new UBFlowLayout(this, -1, 0, 0); + mLayout->setSizeConstraint(QLayout::SetMaximumSize); + setLayout(mLayout); + + auto* bgManager = UBApplication::boardController->backgroundManager(); + const auto backgrounds = bgManager->backgrounds(); + + for (const auto& background : backgrounds) + { + auto pixmap = bgManager->createButtonPixmap(*background, false, false); + auto text = background->description(QLocale().name().left(2)); + auto* label = new BackgroundWidget{pixmap, text, this}; + label->setProperty("uuid", background->uuid()); + label->setToolTip(text); + + mLayout->addWidget(label); + } + + mPlaceholder = new QLabel(this); + QPixmap pixmap(QSize{128, 128}); + pixmap.fill(QColor(Qt::transparent)); + + QPainter painter(&pixmap); + QPen pen = painter.pen(); + pen.setWidth(4); + pen.setColor(QColor(0x888888)); + pen.setStyle(Qt::DashLine); + painter.setPen(pen); + painter.drawRoundedRect(6, 20, 115, 88, 15, 15); + + mPlaceholder->setPixmap(pixmap); + mPlaceholder->setVisible(false); + + updateStyle(); +} + +void UBPreferredBackgroundWidget::dragEnterEvent(QDragEnterEvent* event) +{ + event->accept(); + QWidget::dragEnterEvent(event); +} + +void UBPreferredBackgroundWidget::dragMoveEvent(QDragMoveEvent* event) +{ + QScrollArea* scrollArea = dynamic_cast(parentWidget()->parentWidget()); + + if (scrollArea) + { + QPoint p = mapFromGlobal(event->pos()); + p = event->pos(); + scrollArea->ensureVisible(p.x(), p.y(), 15); + } + + QWidget* child = childAt(event->pos()); + + while (child && child->parentWidget() != this) + { + child = child->parentWidget(); + } + + if (!child) + { + return; + } + + //is the child the placeholder label? + if (child == mPlaceholder) + { + return; + } + + // move the placeholder to the appropiate place + auto pl = mLayout->indexOf(mPlaceholder); + auto ix = mLayout->indexOf(child); + + if (pl >= 0 && ix >= 0) + { + QLayoutItem* plItem = mLayout->takeAt(pl); + + mLayout->insertItem(ix, plItem); + updateStyle(); + } +} + +void UBPreferredBackgroundWidget::dropEvent(QDropEvent* event) +{ + QWidget* child = childAt(event->pos()); + + // child must be placeholder + if (child != mPlaceholder) + { + return; + } + + auto ix = mLayout->indexOf(child); + + if (ix < 0) + { + return; + } + + mLayout->replaceAt(ix, mDraggedItem); + mPlaceholder->setVisible(false); + updateStyle(); + + event->acceptProposedAction(); +} + +void UBPreferredBackgroundWidget::mousePressEvent(QMouseEvent* event) +{ + auto* child = childAt(event->pos()); + + while (child && child->parentWidget() != this) + { + child = child->parentWidget(); + } + + auto* backgroundWidget = dynamic_cast(child); + + if (!backgroundWidget) + { + return; + } + + mDraggedItemPos = mLayout->indexOf(backgroundWidget); + QLayoutItem* item = new QWidgetItem(mPlaceholder); + mDraggedItem = mLayout->replaceAt(mDraggedItemPos, item); + mPlaceholder->setVisible(true); + mDraggedItem->widget()->setVisible(false); + + QPixmap pixmap = backgroundWidget->pixmap(); + + QMimeData* mimeData = new QMimeData; + QDrag* drag = new QDrag(this); + drag->setMimeData(mimeData); + drag->setPixmap(pixmap); + drag->setHotSpot(event->pos() - backgroundWidget->pos()); + const auto dropAction = drag->exec(Qt::MoveAction); + + if (dropAction != Qt::MoveAction) + { + // abort DnD and put dragged item at original position + if (mDraggedItem && mDraggedItemPos >= 0) + { + auto ix = mLayout->indexOf(mPlaceholder); + + if (ix >= 0) + { + mLayout->takeAt(ix); + mLayout->insertItem(mDraggedItemPos, mDraggedItem); + mPlaceholder->setVisible(false); + } + } + } + else + { + savePreferrdBackgrounds(); + } + + if (mDraggedItem && mDraggedItem->widget()) + { + mDraggedItem->widget()->setVisible(true); + } +} + +void UBPreferredBackgroundWidget::updateStyle() const +{ + for (int i = 0; i < mLayout->count(); ++i) + { + QWidget* widget = mLayout->itemAt(i)->widget(); + QLabel* icon = widget->findChild("backgroundIcon"); + + if (icon) + { + icon->setStyleSheet(i < 6 ? "background-color: #bbddff" : ""); + } + } +} + +void UBPreferredBackgroundWidget::savePreferrdBackgrounds() const +{ + QList uuidList; + + for (int i = 0; i < mLayout->count() && i < 6; ++i) + { + uuidList << mLayout->itemAt(i)->widget()->property("uuid").toUuid(); + } + + UBApplication::boardController->backgroundManager()->savePreferredBackgrounds(uuidList); +} + +UBPreferredBackgroundWidget::BackgroundWidget::BackgroundWidget(const QPixmap& pixmap, const QString& text, QWidget* parent) + : QWidget{parent} + , mPixmap{pixmap} +{ + QLabel* icon = new QLabel{this}; + icon->setPixmap(pixmap); + icon->setAlignment(Qt::AlignCenter); + icon->setObjectName("backgroundIcon"); + + QLabel* label = new QLabel{this}; + label->setText(text); + label->setAlignment(Qt::AlignCenter); + label->setWordWrap(true); + label->setMaximumWidth(pixmap.width()); + + QVBoxLayout* layout = new QVBoxLayout{this}; + layout->setSpacing(0); + layout->setMargin(0); + layout->addWidget(icon); + layout->addWidget(label); + setLayout(layout); +} + +QPixmap UBPreferredBackgroundWidget::BackgroundWidget::pixmap() const +{ + return mPixmap; +} diff --git a/src/gui/UBPreferredBackgroundWidget.h b/src/gui/UBPreferredBackgroundWidget.h new file mode 100644 index 000000000..d0014011b --- /dev/null +++ b/src/gui/UBPreferredBackgroundWidget.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +// forward +class UBFlowLayout; +class QLabel; +class QLayoutItem; + +class UBPreferredBackgroundWidget : public QWidget +{ + Q_OBJECT + +public: + explicit UBPreferredBackgroundWidget(QWidget* parent = nullptr); + +protected: + void dragEnterEvent(QDragEnterEvent* event) override; + void dragMoveEvent(QDragMoveEvent* event) override; + void dropEvent(QDropEvent* event) override; + void mousePressEvent(QMouseEvent* event) override; + +private: + void updateStyle() const; + void savePreferrdBackgrounds() const; + +private: + UBFlowLayout* mLayout; + QLabel* mPlaceholder{nullptr}; + QLayoutItem* mDraggedItem{nullptr}; + int mDraggedItemPos{-1}; + + class BackgroundWidget : public QWidget + { + public: + explicit BackgroundWidget(const QPixmap& pixmap, const QString& text, QWidget* parent = nullptr); + + QPixmap pixmap() const; + + private: + QPixmap mPixmap; + }; +}; From 4586cc3d32ac0ca5c2d455d4aad87ba0ea51776b Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Tue, 13 Feb 2024 08:37:56 +0100 Subject: [PATCH 086/133] feat: handle user provided background patterns and more - save patterns when loading a document - allow to delete user provided patterns in preferences - move background button templates to resources - add copyright header - improve code style for new classes - add missing classes to gui.pri --- resources/OpenBoard.qrc | 4 + resources/forms/preferences.ui | 8 +- .../bgButtonTemplateDarkOff.svg | 0 .../bgButtonTemplateDarkOn.svg | 0 .../bgButtonTemplateLightOff.svg | 0 .../bgButtonTemplateLightOn.svg | 0 src/core/UBPreferencesController.cpp | 3 - src/gui/UBBackgroundManager.cpp | 229 ++++++++++------ src/gui/UBBackgroundManager.h | 37 ++- src/gui/UBBackgroundRuling.cpp | 258 ++++++++++++------ src/gui/UBBackgroundRuling.h | 50 +++- src/gui/UBFlowLayout.cpp | 107 +++++--- src/gui/UBFlowLayout.h | 29 +- src/gui/UBPreferredBackgroundWidget.cpp | 181 ++++++++---- src/gui/UBPreferredBackgroundWidget.h | 29 +- src/gui/gui.pri | 4 + 16 files changed, 673 insertions(+), 266 deletions(-) rename resources/{etc/background => images/backgroundPalette}/bgButtonTemplateDarkOff.svg (100%) rename resources/{etc/background => images/backgroundPalette}/bgButtonTemplateDarkOn.svg (100%) rename resources/{etc/background => images/backgroundPalette}/bgButtonTemplateLightOff.svg (100%) rename resources/{etc/background => images/backgroundPalette}/bgButtonTemplateLightOn.svg (100%) diff --git a/resources/OpenBoard.qrc b/resources/OpenBoard.qrc index 1020ea5ed..b856f78c7 100644 --- a/resources/OpenBoard.qrc +++ b/resources/OpenBoard.qrc @@ -386,5 +386,9 @@ images/moveTool.svg images/lightMode.svg images/darkMode.svg + images/backgroundPalette/bgButtonTemplateDarkOff.svg + images/backgroundPalette/bgButtonTemplateDarkOn.svg + images/backgroundPalette/bgButtonTemplateLightOff.svg + images/backgroundPalette/bgButtonTemplateLightOn.svg diff --git a/resources/forms/preferences.ui b/resources/forms/preferences.ui index 2b92868e8..9f468533e 100644 --- a/resources/forms/preferences.ui +++ b/resources/forms/preferences.ui @@ -681,7 +681,7 @@ true - + 0 @@ -3306,6 +3306,12 @@ hr { height: 1px; border-width: 0; } QLineEdit
core/UBPreferencesController.h
+ + UBPreferredBackgroundWidget + QWidget +
gui/UBPreferredBackgroundWidget.h
+ 1 +
useExternalBrowserCheckBox diff --git a/resources/etc/background/bgButtonTemplateDarkOff.svg b/resources/images/backgroundPalette/bgButtonTemplateDarkOff.svg similarity index 100% rename from resources/etc/background/bgButtonTemplateDarkOff.svg rename to resources/images/backgroundPalette/bgButtonTemplateDarkOff.svg diff --git a/resources/etc/background/bgButtonTemplateDarkOn.svg b/resources/images/backgroundPalette/bgButtonTemplateDarkOn.svg similarity index 100% rename from resources/etc/background/bgButtonTemplateDarkOn.svg rename to resources/images/backgroundPalette/bgButtonTemplateDarkOn.svg diff --git a/resources/etc/background/bgButtonTemplateLightOff.svg b/resources/images/backgroundPalette/bgButtonTemplateLightOff.svg similarity index 100% rename from resources/etc/background/bgButtonTemplateLightOff.svg rename to resources/images/backgroundPalette/bgButtonTemplateLightOff.svg diff --git a/resources/etc/background/bgButtonTemplateLightOn.svg b/resources/images/backgroundPalette/bgButtonTemplateLightOn.svg similarity index 100% rename from resources/etc/background/bgButtonTemplateLightOn.svg rename to resources/images/backgroundPalette/bgButtonTemplateLightOn.svg diff --git a/src/core/UBPreferencesController.cpp b/src/core/UBPreferencesController.cpp index 8b5e05a97..0dce85bc5 100644 --- a/src/core/UBPreferencesController.cpp +++ b/src/core/UBPreferencesController.cpp @@ -49,7 +49,6 @@ #include "ui_preferences.h" #include "core/memcheck.h" -#include "gui/UBPreferredBackgroundWidget.h" qreal UBPreferencesController::sSliderRatio = 10.0; qreal UBPreferencesController::sMinPenWidth = 0.5; @@ -89,8 +88,6 @@ UBPreferencesController::UBPreferencesController(QWidget *parent) connect(UBApplication::displayManager, &UBDisplayManager::availableScreenCountChanged, this, &UBPreferencesController::adjustScreensPreferences); wire(); - auto* prefBgWidget = new UBPreferredBackgroundWidget(); - mPreferencesUI->bgScrollArea->setWidget(prefBgWidget); } diff --git a/src/gui/UBBackgroundManager.cpp b/src/gui/UBBackgroundManager.cpp index 58073dbe4..729a07b2d 100644 --- a/src/gui/UBBackgroundManager.cpp +++ b/src/gui/UBBackgroundManager.cpp @@ -1,3 +1,26 @@ +/* + * Copyright (C) 2015-2024 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + + #include "UBBackgroundManager.h" #include "core/UBSettings.h" @@ -17,22 +40,64 @@ UBBackgroundManager::UBBackgroundManager(QObject *parent) void UBBackgroundManager::scan() { // scan application and user directories for background rules - QString appDir = UBPlatformUtils::applicationTemplateDirectory() + "/background"; - QString usrDir = UBSettings::userDataDirectory() + "/template/background"; + const QString appDir{UBPlatformUtils::applicationTemplateDirectory() + "/background"}; + const QString usrDir{UBSettings::userDataDirectory() + "/template/background"}; - scan(appDir); - scan(usrDir); + scan(appDir, false); + scan(usrDir, true); } void UBBackgroundManager::addBackground(UBBackgroundRuling &background) { - if (background.isValid() && !this->background(background.uuid())) + if (background.isValid()) { - mBackgrounds.append(background); + if (!this->background(background.uuid())) + { + mBackgrounds.append(background); + + // store in user template directory + const QString usrDir{UBSettings::userDataDirectory() + "/template/background/"}; + QDir dir; + dir.mkpath(usrDir); + + QFile file{usrDir + background.uuid().toString() + ".xml"}; + + if (!file.open(QFile::WriteOnly)) + { + qWarning() << "Cannot open" << file; + return; + } + + QXmlStreamWriter writer{&file}; + + writer.setAutoFormatting(true); + writer.setAutoFormattingIndent(2); + writer.writeStartDocument(); + background.toXml(writer); + writer.writeEndDocument(); + + file.close(); + + emit backgroundListChanged(); + } } else { - qWarning() << "Invalid or duplicate background ruling" << background.description("en"); + qWarning() << "Invalid background ruling" << background.description(); + } +} + +void UBBackgroundManager::deleteBackground(const QUuid& uuid) +{ + const auto bg{background(uuid)}; + + if (bg->isValid() && bg->isUserProvided()) + { + mBackgrounds.removeAll(*bg); + const QString usrDir{UBSettings::userDataDirectory() + "/template/background/"}; + QFile::remove(usrDir + uuid.toString() + ".xml"); + + emit backgroundListChanged(); } } @@ -40,12 +105,12 @@ const QList UBBackgroundManager::backgrounds() const { QList backgroundList; - QStringList uuidList = UBSettings::settings()->value("Board/BackgroundRulingList").toStringList(); + QStringList uuidList{UBSettings::settings()->value("Board/BackgroundRulingList").toStringList()}; // first add rulings from list for (const auto& uuid : uuidList) { - const auto& ruling = background(uuid); + const auto ruling = background(uuid); if (ruling && ruling->isValid()) { @@ -66,10 +131,10 @@ const QList UBBackgroundManager::backgrounds() const QAction *UBBackgroundManager::backgroundAction(const UBBackgroundRuling &background, bool dark) { - QAction* action = new QAction{this}; + auto action = new QAction{this}; action->setIcon(createButtonIcon(background, dark)); - QString lang = QLocale().name().left(2); - QString descr = background.description(lang); + const QString lang{QLocale().name().left(2)}; + const QString descr{background.description(lang)}; action->setToolTip(descr); action->setProperty("uuid", background.uuid()); action->setCheckable(true); @@ -78,8 +143,8 @@ QAction *UBBackgroundManager::backgroundAction(const UBBackgroundRuling &backgro void UBBackgroundManager::updateAction(QAction *action, bool dark) const { - const auto uuid = action->property("uuid").toUuid(); - const auto bg = background(uuid); + const auto uuid{action->property("uuid").toUuid()}; + const auto bg{background(uuid)}; if (bg) { @@ -115,87 +180,43 @@ const UBBackgroundRuling* UBBackgroundManager::guessBackground(bool crossed, boo return nullptr; } -QPixmap UBBackgroundManager::createButtonPixmap(const UBBackgroundRuling &background, bool dark, bool on) const +QPixmap UBBackgroundManager::createButtonPixmap(const UBBackgroundRuling& background, bool dark, bool on) const { - QString filename{"bgButtonTemplate"}; - - filename += dark ? "Dark" : "Light"; - filename += on ? "On" : "Off"; - filename += ".svg"; - - QFile templateFile(UBPlatformUtils::applicationTemplateDirectory() + "/background/" + filename); - - if (!templateFile.open(QFile::ReadOnly)) - { - qWarning() << "Cannot find template file" << templateFile; - return {}; - } - - QDomDocument doc; + QByteArray bgSvg{renderToSvg(background, dark)}; + QDomDocument bgDoc; - if (!doc.setContent(&templateFile, true)) + if (!bgDoc.setContent(bgSvg)) { - qWarning() << "Cannot load template file" << templateFile; + qWarning() << "Cannot load rendered ruling" << background.description(); return {}; } - // find element with id="placeholder" - auto plist = doc.documentElement().elementsByTagName("g"); - - QDomElement placeholder; - - for (int i = 0; i < plist.size(); ++i) - { - QDomElement item = plist.at(i).toElement(); - - if (item.attribute("id") == "placeholder") - { - placeholder = item; - break; - } - } + return createButtonPixmap(bgDoc, dark, on); +} - // now render background to SVG - QByteArray bgSvg = renderToSvg(background, dark); +QIcon UBBackgroundManager::createButtonIcon(const UBBackgroundRuling &background, bool dark) const +{ + QByteArray bgSvg{renderToSvg(background, dark)}; QDomDocument bgDoc; if (!bgDoc.setContent(bgSvg)) { - qWarning() << "Cannot load rendered ruling" << templateFile; + qWarning() << "Cannot load rendered ruling" << background.description(); return {}; } - // find first element - auto bgElement = bgDoc.documentElement().firstChildElement("g"); - - // replace element in original document - auto bg = doc.importNode(bgElement, true); - placeholder.parentNode().replaceChild(bg, placeholder); - - QByteArray replaced = doc.toByteArray(2); - - // render SVG to pixmap by using an QImageReader - QBuffer buffer{&replaced}; - QImageReader reader(&buffer, "svg"); - QPixmap pixmap = QPixmap::fromImageReader(&reader); - - return pixmap; -} - -QIcon UBBackgroundManager::createButtonIcon(const UBBackgroundRuling &background, bool dark) const -{ QIcon icon; - QPixmap pix = createButtonPixmap(background, dark, false); + QPixmap pix{createButtonPixmap(bgDoc, dark, false)}; icon.addPixmap(pix, QIcon::Normal, QIcon::Off); - pix = createButtonPixmap(background, dark, true); + pix = createButtonPixmap(bgDoc, dark, true); icon.addPixmap(pix, QIcon::Normal, QIcon::On); return icon; } -void UBBackgroundManager::savePreferredBackgrounds(QList& uuidList) const +void UBBackgroundManager::savePreferredBackgrounds(QList& uuidList) { QStringList uuids; @@ -208,13 +229,13 @@ void UBBackgroundManager::savePreferredBackgrounds(QList& uuidList) const emit preferredBackgroundChanged(); } -void UBBackgroundManager::scan(const QString &dirname) +void UBBackgroundManager::scan(const QString &dirname, bool userProvided) { const QDir dir{dirname}; if (dir.exists()) { - const auto list = dir.entryInfoList({"*.xml"}, QDir::Files, QDir::Name); + const auto list{dir.entryInfoList({"*.xml"}, QDir::Files, QDir::Name)}; for (const auto& entry : list) { @@ -226,11 +247,11 @@ void UBBackgroundManager::scan(const QString &dirname) continue; } - QXmlStreamReader reader(&file); + QXmlStreamReader reader{&file}; if (reader.readNextStartElement()) { - bg.parseXml(reader); + bg.parseXml(reader, userProvided); } if (bg.isValid()) @@ -262,3 +283,59 @@ QByteArray UBBackgroundManager::renderToSvg(const UBBackgroundRuling &background return buffer.buffer(); } +QPixmap UBBackgroundManager::createButtonPixmap(const QDomDocument& bgDoc, bool dark, bool on) const +{ + QString filename{"bgButtonTemplate"}; + + filename += dark ? "Dark" : "Light"; + filename += on ? "On" : "Off"; + filename += ".svg"; + + QFile templateFile{":/images/backgroundPalette/" + filename}; + + if (!templateFile.open(QFile::ReadOnly)) + { + qWarning() << "Cannot find template file" << templateFile; + return {}; + } + + QDomDocument doc; + + if (!doc.setContent(&templateFile, true)) + { + qWarning() << "Cannot load template file" << templateFile; + return {}; + } + + // find element with id="placeholder" + auto plist{doc.documentElement().elementsByTagName("g")}; + + QDomElement placeholder; + + for (int i = 0; i < plist.size(); ++i) + { + const auto item{plist.at(i).toElement()}; + + if (item.attribute("id") == "placeholder") + { + placeholder = item; + break; + } + } + + // now process background SVG + // find first element + const auto bgElement{bgDoc.documentElement().firstChildElement("g")}; + + // replace element in original document + const auto bg{doc.importNode(bgElement, true)}; + placeholder.parentNode().replaceChild(bg, placeholder); + + QByteArray replaced{doc.toByteArray(2)}; + + // render SVG to pixmap by using an QImageReader + QBuffer buffer{&replaced}; + QImageReader reader{&buffer, "svg"}; + + return QPixmap::fromImageReader(&reader); +} diff --git a/src/gui/UBBackgroundManager.h b/src/gui/UBBackgroundManager.h index 53b98aec0..db7d3872b 100644 --- a/src/gui/UBBackgroundManager.h +++ b/src/gui/UBBackgroundManager.h @@ -1,3 +1,26 @@ +/* + * Copyright (C) 2015-2024 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + + #pragma once #include "gui/UBBackgroundRuling.h" @@ -6,15 +29,18 @@ // forward class QAction; +class QDomDocument; class UBBackgroundManager : public QObject { Q_OBJECT + public: - explicit UBBackgroundManager(QObject *parent = nullptr); + explicit UBBackgroundManager(QObject* parent = nullptr); void scan(); void addBackground(UBBackgroundRuling& background); + void deleteBackground(const QUuid& uuid); const QList backgrounds() const; QAction* backgroundAction(const UBBackgroundRuling& background, bool dark); void updateAction(QAction* action, bool dark) const; @@ -22,16 +48,17 @@ class UBBackgroundManager : public QObject const UBBackgroundRuling* guessBackground(bool crossed, bool ruled, bool intermediateLines) const; QPixmap createButtonPixmap(const UBBackgroundRuling& background, bool dark, bool on) const; QIcon createButtonIcon(const UBBackgroundRuling& background, bool dark) const; - void savePreferredBackgrounds(QList& uuidList) const; + void savePreferredBackgrounds(QList& uuidList); signals: - void preferredBackgroundChanged() const; + void preferredBackgroundChanged(); + void backgroundListChanged(); private: - void scan(const QString& dirname); + void scan(const QString& dirname, bool userProvided); QByteArray renderToSvg(const UBBackgroundRuling& background, bool dark) const; + QPixmap createButtonPixmap(const QDomDocument& bgDoc, bool dark, bool on) const; private: QList mBackgrounds; }; - diff --git a/src/gui/UBBackgroundRuling.cpp b/src/gui/UBBackgroundRuling.cpp index 866f532d6..95ddc6c6a 100644 --- a/src/gui/UBBackgroundRuling.cpp +++ b/src/gui/UBBackgroundRuling.cpp @@ -1,3 +1,26 @@ +/* + * Copyright (C) 2015-2024 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + + #include "UBBackgroundRuling.h" #include "core/UBSettings.h" @@ -11,6 +34,39 @@ // namespace and element names static constexpr char const* namespaceURI{"http://openboard.org/template/background/"}; +static constexpr char const* namespacePrefix{"bg"}; + +static constexpr char const* attributeCrossed{"crossed"}; +static constexpr char const* attributeIntermediateLines{"intermediateLines"}; +static constexpr char const* attributeRuled{"ruled"}; +static constexpr char const* attributeXmlLang{"xml:lang"}; + +static constexpr char const* elementAngle{"angle"}; +static constexpr char const* elementAttributes{"attributes"}; +static constexpr char const* elementBackground{"background"}; +static constexpr char const* elementBorder{"border"}; +static constexpr char const* elementColor{"color"}; +static constexpr char const* elementDefaultColor{"defaultColor"}; +static constexpr char const* elementDescription{"description"}; +static constexpr char const* elementLeft{"left"}; +static constexpr char const* elementLinegroup{"linegroup"}; +static constexpr char const* elementLine{"line"}; +static constexpr char const* elementOffset{"offset"}; +static constexpr char const* elementOnDark{"onDark"}; +static constexpr char const* elementOnLight{"onLight"}; +static constexpr char const* elementOrigin{"origin"}; +static constexpr char const* elementRight{"right"}; +static constexpr char const* elementSpacing{"spacing"}; +static constexpr char const* elementUuid{"uuid"}; +static constexpr char const* elementWidth{"width"}; + +static constexpr char const* originBottomleft{"bottomleft"}; +static constexpr char const* originBottomright{"bottomright"}; +static constexpr char const* originCenter{"center"}; +static constexpr char const* originTopleft{"topleft"}; +static constexpr char const* originTopright{"topright"}; + +static constexpr char const* valueTrue{"true"}; // helper functions @@ -65,6 +121,12 @@ static bool getColorValue(QXmlStreamReader& reader, const QString& name, QColor& color.setAlphaF(color.alphaF() * alpha); return true; } + else + { + // try to interpret as color name + color = colorValue; + return color.isValid(); + } } } @@ -152,12 +214,11 @@ bool clip(const QRectF& rect, QLineF& line) } // computing new points - qreal xn1, yn1, xn2, yn2; - xn1 = line.x1() - p1 * rn1; - yn1 = line.y1() - p3 * rn1; + const auto xn1 = line.x1() - p1 * rn1; + const auto yn1 = line.y1() - p3 * rn1; - xn2 = line.x1() - p1 * rn2; - yn2 = line.y1() - p3 * rn2; + const auto xn2 = line.x1() - p1 * rn2; + const auto yn2 = line.y1() - p3 * rn2; line.setLine(xn1, yn1, xn2, yn2); @@ -169,13 +230,19 @@ UBBackgroundRuling::UBBackgroundRuling() { } -bool UBBackgroundRuling::parseXml(QXmlStreamReader &reader) +bool UBBackgroundRuling::operator==(const UBBackgroundRuling& other) const +{ + return uuid() == other.uuid(); +} + +bool UBBackgroundRuling::parseXml(QXmlStreamReader& reader, bool userProvided) { mRules = std::shared_ptr(Rules::fromXml(reader)); + mUserProvided = userProvided; return mRules && !mRules->hasError(); } -bool UBBackgroundRuling::toXml(QXmlStreamWriter &writer) const +bool UBBackgroundRuling::toXml(QXmlStreamWriter& writer) const { if (mRules) { @@ -241,8 +308,13 @@ bool UBBackgroundRuling::hasIntermediateLines() const return mRules->hasIntermediateLines(); } +bool UBBackgroundRuling::isUserProvided() const +{ + return mUserProvided; +} + void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double gridSize, const QRectF& nominalScene, - bool onDark) const + bool onDark) const { if (!mRules) { @@ -270,8 +342,8 @@ void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double grid } painter->setRenderHint(QPainter::Antialiasing, true); - const auto defaultOnDark = QColor(UBSettings::settings()->boardCrossColorDarkBackground->get().toString()); - const auto defaultOnLight = QColor(UBSettings::settings()->boardCrossColorLightBackground->get().toString()); + const QColor defaultOnDark{UBSettings::settings()->boardCrossColorDarkBackground->get().toString()}; + const QColor defaultOnLight{UBSettings::settings()->boardCrossColorLightBackground->get().toString()}; // loop through line groups for (const auto& linegroup : mRules->linegroups()) @@ -371,9 +443,9 @@ void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double grid // normal vector for translations auto normal = originLine.normalVector(); normal.setLength(spacing); - auto spaceShift = normal.p1() - normal.p2(); + const auto spaceShift = normal.p1() - normal.p2(); normal.setLength(offset); - auto offsetShift = normal.p1() - normal.p2(); + const auto offsetShift = normal.p1() - normal.p2(); const auto lastLine = &line == &linegroup.lines().last(); @@ -430,7 +502,7 @@ void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double grid // single line at offset auto normal = originLine.normalVector(); normal.setLength(offset); - auto offsetShift = normal.p1() - normal.p2(); + const auto offsetShift = normal.p1() - normal.p2(); auto gridLine = originLine.translated(offsetShift); if (clip(rect, gridLine)) @@ -443,10 +515,8 @@ void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double grid } void UBBackgroundRuling::setLinePainter(QPainter* painter, const Line& line, bool onDark, QColor defaultOnDark, - QColor defaultOnLight) const + QColor defaultOnLight) const { - const auto width = line.width(); - const auto colorOnDark = line.color().onDark(); const auto colorOnLight = line.color().onLight(); @@ -455,7 +525,7 @@ void UBBackgroundRuling::setLinePainter(QPainter* painter, const Line& line, boo defaultOnLight.setAlphaF(colorOnLight.alphaF()); auto pen = painter->pen(); - pen.setWidth(width); + pen.setWidth(line.width()); pen.setColor(onDark ? (colorOnDark.isValid() ? colorOnDark : defaultOnDark) : (colorOnLight.isValid() ? colorOnLight : defaultOnLight)); pen.setCapStyle(Qt::FlatCap); @@ -463,7 +533,8 @@ void UBBackgroundRuling::setLinePainter(QPainter* painter, const Line& line, boo } void UBBackgroundRuling::drawBorderLines(QPainter* painter, const QList& borderLines, QLineF line, Qt::Edge edge, - double gridSize, bool onDark, QColor defaultOnDark, QColor defaultOnLight) const + double gridSize, bool onDark, QColor defaultOnDark, + QColor defaultOnLight) const { painter->save(); @@ -509,17 +580,17 @@ const UBBackgroundRuling::Rules& UBBackgroundRuling::Data::rules() const return *mRules; } -UBBackgroundRuling::LineColor::LineColor(const Rules &rules, QXmlStreamReader &reader) +UBBackgroundRuling::LineColor::LineColor(const Rules& rules, QXmlStreamReader& reader) : Data{rules} , mOnDark{rules.defaultColor().onDark()} , mOnLight{rules.defaultColor().onLight()} { while (reader.readNextStartElement() && reader.namespaceUri() == namespaceURI) { - if (getColorValue(reader, "onDark", mOnDark)) + if (getColorValue(reader, elementOnDark, mOnDark)) { } - else if (getColorValue(reader, "onLight", mOnLight)) + else if (getColorValue(reader, elementOnLight, mOnLight)) { } else @@ -530,23 +601,23 @@ UBBackgroundRuling::LineColor::LineColor(const Rules &rules, QXmlStreamReader &r } UBBackgroundRuling::LineColor::LineColor(const UBBackgroundRuling::Rules& rules, const QColor& colorOnDark, - const QColor& colorOnLight) + const QColor& colorOnLight) : Data{rules} , mOnDark{colorOnDark} , mOnLight{colorOnLight} { } -void UBBackgroundRuling::LineColor::toXml(QXmlStreamWriter &writer) const +void UBBackgroundRuling::LineColor::toXml(QXmlStreamWriter& writer) const { if (mOnDark.isValid()) { - writer.writeTextElement(namespaceURI, "onDark", mOnDark.name(QColor::HexArgb)); + writer.writeTextElement(namespaceURI, elementOnDark, mOnDark.name(QColor::HexArgb)); } if (mOnLight.isValid()) { - writer.writeTextElement(namespaceURI, "onDark", mOnLight.name(QColor::HexArgb)); + writer.writeTextElement(namespaceURI, elementOnLight, mOnLight.name(QColor::HexArgb)); } } @@ -560,19 +631,19 @@ const QColor& UBBackgroundRuling::LineColor::onLight() const return mOnLight; } -UBBackgroundRuling::Line::Line(const Rules &rules, QXmlStreamReader &reader) +UBBackgroundRuling::Line::Line(const Rules& rules, QXmlStreamReader& reader) : Data{rules} , mColor{rules.defaultColor()} { while (reader.readNextStartElement() && reader.namespaceUri() == namespaceURI) { - if (getDecimalValue(reader, "offset", mOffset)) + if (getDecimalValue(reader, elementOffset, mOffset)) { } - else if (getDecimalValue(reader, "width", mWidth)) + else if (getDecimalValue(reader, elementWidth, mWidth)) { } - else if (reader.name() == "color") + else if (reader.name() == elementColor) { mColor = LineColor{rules, reader}; } @@ -583,14 +654,14 @@ UBBackgroundRuling::Line::Line(const Rules &rules, QXmlStreamReader &reader) } } -void UBBackgroundRuling::Line::toXml(QXmlStreamWriter &writer) const +void UBBackgroundRuling::Line::toXml(QXmlStreamWriter& writer) const { - writer.writeTextElement(namespaceURI, "offset", QString::number(mOffset)); - writer.writeTextElement(namespaceURI, "width", QString::number(mWidth)); + writer.writeTextElement(namespaceURI, elementOffset, QString::number(mOffset)); + writer.writeTextElement(namespaceURI, elementWidth, QString::number(mWidth)); if (mColor.onDark().isValid() || mColor.onLight().isValid()) { - writer.writeStartElement(namespaceURI, "color"); + writer.writeStartElement(namespaceURI, elementColor); mColor.toXml(writer); writer.writeEndElement(); } @@ -611,22 +682,22 @@ const UBBackgroundRuling::LineColor& UBBackgroundRuling::Line::color() const return mColor; } -UBBackgroundRuling::Border::Border(const Rules &rules, QXmlStreamReader &reader) +UBBackgroundRuling::Border::Border(const Rules& rules, QXmlStreamReader& reader) : Data{rules} { while (reader.readNextStartElement() && reader.namespaceUri() == namespaceURI) { double value; - if (getDecimalValue(reader, "left", value)) + if (getDecimalValue(reader, elementLeft, value)) { mLeft.emplace(value); } - else if (getDecimalValue(reader, "right", value)) + else if (getDecimalValue(reader, elementRight, value)) { mRight.emplace(value); } - else if (reader.name() == "line") + else if (reader.name() == elementLine) { const Line bgLine{rules, reader}; @@ -642,21 +713,21 @@ UBBackgroundRuling::Border::Border(const Rules &rules, QXmlStreamReader &reader) } } -void UBBackgroundRuling::Border::toXml(QXmlStreamWriter &writer) const +void UBBackgroundRuling::Border::toXml(QXmlStreamWriter& writer) const { if (mLeft) { - writer.writeTextElement(namespaceURI, "left", QString::number(mLeft.value())); + writer.writeTextElement(namespaceURI, elementLeft, QString::number(mLeft.value())); } if (mRight) { - writer.writeTextElement(namespaceURI, "right", QString::number(mRight.value())); + writer.writeTextElement(namespaceURI, elementRight, QString::number(mRight.value())); } for (const auto& line : mLines) { - writer.writeStartElement(namespaceURI, "line"); + writer.writeStartElement(namespaceURI, elementLine); line.toXml(writer); writer.writeEndElement(); } @@ -677,38 +748,38 @@ const QList& UBBackgroundRuling::Border::lines() const return mLines; } -UBBackgroundRuling::Linegroup::Linegroup(const Rules &rules, QXmlStreamReader &reader) +UBBackgroundRuling::Linegroup::Linegroup(const Rules& rules, QXmlStreamReader& reader) : Data{rules} { QString lineGroupOrigin; while (reader.readNextStartElement() && reader.namespaceUri() == namespaceURI) { - if (getDecimalValue(reader, "angle", mAngle)) + if (getDecimalValue(reader, elementAngle, mAngle)) { } - else if (getDecimalValue(reader, "spacing", mSpacing)) + else if (getDecimalValue(reader, elementSpacing, mSpacing)) { } - else if (getStringValue(reader, "origin", lineGroupOrigin)) + else if (getStringValue(reader, elementOrigin, lineGroupOrigin)) { - if (lineGroupOrigin == "topleft") + if (lineGroupOrigin == originTopleft) { mOrigin = Origin::TopLeft; } - else if (lineGroupOrigin == "topright") + else if (lineGroupOrigin == originTopright) { mOrigin = Origin::TopRight; } - else if (lineGroupOrigin == "bottomleft") + else if (lineGroupOrigin == originBottomleft) { mOrigin = Origin::BottomLeft; } - else if (lineGroupOrigin == "bottomright") + else if (lineGroupOrigin == originBottomright) { mOrigin = Origin::BottomRight; } - else if (lineGroupOrigin == "center") + else if (lineGroupOrigin == originCenter) { mOrigin = Origin::Center; } @@ -717,7 +788,7 @@ UBBackgroundRuling::Linegroup::Linegroup(const Rules &rules, QXmlStreamReader &r setError(); } } - else if (reader.name() == "line") + else if (reader.name() == elementLine) { const Line bgLine{rules, reader}; @@ -730,7 +801,7 @@ UBBackgroundRuling::Linegroup::Linegroup(const Rules &rules, QXmlStreamReader &r mLines.append(bgLine); } } - else if (reader.name() == "border") + else if (reader.name() == elementBorder) { mBorder.emplace(rules, reader); } @@ -741,38 +812,48 @@ UBBackgroundRuling::Linegroup::Linegroup(const Rules &rules, QXmlStreamReader &r } } -void UBBackgroundRuling::Linegroup::toXml(QXmlStreamWriter &writer) const +void UBBackgroundRuling::Linegroup::toXml(QXmlStreamWriter& writer) const { - writer.writeTextElement(namespaceURI, "angle", QString::number(mAngle)); + writer.writeTextElement(namespaceURI, elementAngle, QString::number(mAngle)); if (mSpacing != 0) { - writer.writeTextElement(namespaceURI, "spacing", QString::number(mSpacing)); + writer.writeTextElement(namespaceURI, elementSpacing, QString::number(mSpacing)); } QString origin; switch (mOrigin) { - case Origin::Center: origin = "center"; break; - case Origin::TopLeft: origin = "topleft"; break; - case Origin::TopRight: origin = "topright"; break; - case Origin::BottomLeft: origin = "bottomleft"; break; - case Origin::BottomRight: origin = "bottomright"; break; + case Origin::Center: + origin = originCenter; + break; + case Origin::TopLeft: + origin = originTopleft; + break; + case Origin::TopRight: + origin = originTopright; + break; + case Origin::BottomLeft: + origin = originBottomleft; + break; + case Origin::BottomRight: + origin = originBottomright; + break; } - writer.writeTextElement(namespaceURI, "origin", origin); + writer.writeTextElement(namespaceURI, elementOrigin, origin); for (const auto& line : mLines) { - writer.writeStartElement(namespaceURI, "line"); + writer.writeStartElement(namespaceURI, elementLine); line.toXml(writer); writer.writeEndElement(); } if (mBorder) { - writer.writeStartElement(namespaceURI, "border"); + writer.writeStartElement(namespaceURI, elementBorder); mBorder.value().toXml(writer); writer.writeEndElement(); } @@ -803,7 +884,7 @@ std::optional UBBackgroundRuling::Linegroup::border( return mBorder; } -UBBackgroundRuling::Rules::Rules(QXmlStreamReader &reader) +UBBackgroundRuling::Rules::Rules(QXmlStreamReader& reader) : Data{*this} , mDefaultColor{*this, {}, {}} { @@ -816,30 +897,30 @@ UBBackgroundRuling::Rules::Rules(QXmlStreamReader &reader) QString text; - if (getStringValue(reader, "uuid", text)) + if (getStringValue(reader, elementUuid, text)) { mUuid = QUuid(text); } - else if (name == "description") + else if (name == elementDescription) { const auto attributes = reader.attributes(); - const auto lang = attributes.value("xml:lang").toString(); + const auto lang = attributes.value(attributeXmlLang).toString(); mDescriptions[lang.isEmpty() ? "en" : lang] = reader.readElementText(); } - else if (name == "attributes") + else if (name == elementAttributes) { const auto attributes = reader.attributes(); - mCrossed = attributes.value("crossed") == "true"; - mRuled = attributes.value("ruled") == "true"; - mIntermediateLines = attributes.value("intermediateLines") == "true"; + mCrossed = attributes.value(attributeCrossed) == valueTrue; + mRuled = attributes.value(attributeRuled) == valueTrue; + mIntermediateLines = attributes.value(attributeIntermediateLines) == valueTrue; reader.skipCurrentElement(); } - else if (name == "defaultColor") + else if (name == elementDefaultColor) { mDefaultColor = LineColor{*this, reader}; } - else if (name == "linegroup") + else if (name == elementLinegroup) { const Linegroup bgLinegroup{*this, reader}; @@ -860,9 +941,9 @@ UBBackgroundRuling::Rules::Rules(QXmlStreamReader &reader) } } -UBBackgroundRuling::Rules* UBBackgroundRuling::Rules::fromXml(QXmlStreamReader &reader) +UBBackgroundRuling::Rules* UBBackgroundRuling::Rules::fromXml(QXmlStreamReader& reader) { - if (reader.namespaceUri() == namespaceURI && reader.name() == "background") + if (reader.namespaceUri() == namespaceURI && reader.name() == elementBackground) { return new Rules(reader); } @@ -870,50 +951,51 @@ UBBackgroundRuling::Rules* UBBackgroundRuling::Rules::fromXml(QXmlStreamReader & return nullptr; } -void UBBackgroundRuling::Rules::toXml(QXmlStreamWriter &writer) const +void UBBackgroundRuling::Rules::toXml(QXmlStreamWriter& writer) const { - writer.writeNamespace(namespaceURI, "bg"); - writer.writeStartElement(namespaceURI, "background"); - writer.writeTextElement(namespaceURI, "uuid", mUuid.toString(QUuid::WithoutBraces)); + writer.writeNamespace(namespaceURI, namespacePrefix); + writer.writeStartElement(namespaceURI, elementBackground); + writer.writeTextElement(namespaceURI, elementUuid, mUuid.toString(QUuid::WithoutBraces)); - for (auto description = mDescriptions.constKeyValueBegin(); description != mDescriptions.constKeyValueEnd(); ++description) + for (auto description = mDescriptions.constKeyValueBegin(); description != mDescriptions.constKeyValueEnd(); + ++description) { - writer.writeStartElement(namespaceURI, "description"); - writer.writeAttribute("xml:lang", description->first); + writer.writeStartElement(namespaceURI, elementDescription); + writer.writeAttribute(attributeXmlLang, description->first); writer.writeCharacters(description->second); writer.writeEndElement(); } if (mCrossed || mRuled) { - writer.writeEmptyElement(namespaceURI, "attributes"); + writer.writeEmptyElement(namespaceURI, elementAttributes); if (mCrossed) { - writer.writeAttribute("crossed", "true"); + writer.writeAttribute(attributeCrossed, valueTrue); } if (mRuled) { - writer.writeAttribute("ruled", "true"); + writer.writeAttribute(attributeRuled, valueTrue); } if (mIntermediateLines) { - writer.writeAttribute("intermediateLines", "true"); + writer.writeAttribute(attributeIntermediateLines, valueTrue); } } if (mDefaultColor.onDark().isValid() || mDefaultColor.onLight().isValid()) { - writer.writeStartElement(namespaceURI, "defaultColor"); + writer.writeStartElement(namespaceURI, elementDefaultColor); mDefaultColor.toXml(writer); writer.writeEndElement(); } for (const auto& linegroup : mLinegroups) { - writer.writeStartElement(namespaceURI, "linegroup"); + writer.writeStartElement(namespaceURI, elementLinegroup); linegroup.toXml(writer); writer.writeEndElement(); } diff --git a/src/gui/UBBackgroundRuling.h b/src/gui/UBBackgroundRuling.h index f3a9544c2..1dee4f254 100644 --- a/src/gui/UBBackgroundRuling.h +++ b/src/gui/UBBackgroundRuling.h @@ -1,3 +1,26 @@ +/* + * Copyright (C) 2015-2024 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + + #pragma once #include @@ -17,22 +40,27 @@ class UBBackgroundRuling public: UBBackgroundRuling(); - bool parseXml(QXmlStreamReader& reader); + bool operator==(const UBBackgroundRuling& other) const; + + bool parseXml(QXmlStreamReader& reader, bool userProvided = true); bool toXml(QXmlStreamWriter& writer) const; bool isValid() const; QUuid uuid() const; - QString description(const QString& languagecode) const; + QString description(const QString& languagecode = "en") const; bool isCrossed() const; bool isRuled() const; bool hasIntermediateLines() const; + bool isUserProvided() const; - void draw(QPainter *painter, const QRectF &rect, double gridSize, const QRectF &nominalScene, bool onDark) const; + void draw(QPainter* painter, const QRectF& rect, double gridSize, const QRectF& nominalScene, bool onDark) const; private: - class Line; - void setLinePainter(QPainter* painter, const Line& line, bool onDark, QColor defaultOnDark, QColor defaultOnLight) const; - void drawBorderLines(QPainter* painter, const QList& borderLines, QLineF line, Qt::Edge edge, double gridSize, bool onDark, QColor defaultOnDark, QColor defaultOnLight) const; + class Line; // forward + void setLinePainter(QPainter* painter, const Line& line, bool onDark, QColor defaultOnDark, + QColor defaultOnLight) const; + void drawBorderLines(QPainter* painter, const QList& borderLines, QLineF line, Qt::Edge edge, double gridSize, + bool onDark, QColor defaultOnDark, QColor defaultOnLight) const; private: // data classes @@ -41,7 +69,7 @@ class UBBackgroundRuling class Data { public: - explicit Data(Rules &rules); + explicit Data(Rules& rules); bool hasError() const; virtual void toXml(QXmlStreamWriter& writer) const = 0; @@ -58,8 +86,8 @@ class UBBackgroundRuling class LineColor : public Data { public: - LineColor(const Rules& rules, QXmlStreamReader &reader); - LineColor(const Rules& rules, const QColor &colorOnDark, const QColor &colorOnLight); + LineColor(const Rules& rules, QXmlStreamReader& reader); + LineColor(const Rules& rules, const QColor& colorOnDark, const QColor& colorOnLight); virtual void toXml(QXmlStreamWriter& writer) const override; @@ -138,7 +166,7 @@ class UBBackgroundRuling class Rules : public Data { public: - explicit Rules(QXmlStreamReader &reader); + explicit Rules(QXmlStreamReader& reader); static Rules* fromXml(QXmlStreamReader& reader); @@ -164,5 +192,5 @@ class UBBackgroundRuling private: std::shared_ptr mRules{nullptr}; + bool mUserProvided{false}; }; - diff --git a/src/gui/UBFlowLayout.cpp b/src/gui/UBFlowLayout.cpp index 71aeb91c6..4876d8791 100644 --- a/src/gui/UBFlowLayout.cpp +++ b/src/gui/UBFlowLayout.cpp @@ -1,19 +1,43 @@ +/* + * Copyright (C) 2015-2024 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + + #include "UBFlowLayout.h" -#include "qwidget.h" + +#include // inspired by https://doc.qt.io/qt-5/qtwidgets-layouts-flowlayout-example.html UBFlowLayout::UBFlowLayout(QWidget* parent, int margin, int hSpacing, int vSpacing) - : QLayout(parent) - , m_hSpace(hSpacing) - , m_vSpace(vSpacing) + : QLayout{parent} + , mHSpace{hSpacing} + , mVSpace{vSpacing} { setContentsMargins(margin, margin, margin, margin); } UBFlowLayout::UBFlowLayout(int margin, int hSpacing, int vSpacing) - : m_hSpace(hSpacing) - , m_vSpace(vSpacing) + : mHSpace{hSpacing} + , mVSpace{vSpacing} { setContentsMargins(margin, margin, margin, margin); } @@ -21,25 +45,28 @@ UBFlowLayout::UBFlowLayout(int margin, int hSpacing, int vSpacing) UBFlowLayout::~UBFlowLayout() { QLayoutItem* item; + while ((item = UBFlowLayout::takeAt(0))) + { delete item; + } } void UBFlowLayout::addItem(QLayoutItem* item) { - itemList.append(item); + mItemList.append(item); } void UBFlowLayout::insertItem(int index, QLayoutItem* item) { - itemList.insert(index, item); + mItemList.insert(index, item); } int UBFlowLayout::horizontalSpacing() const { - if (m_hSpace >= 0) + if (mHSpace >= 0) { - return m_hSpace; + return mHSpace; } else { @@ -49,9 +76,9 @@ int UBFlowLayout::horizontalSpacing() const int UBFlowLayout::verticalSpacing() const { - if (m_vSpace >= 0) + if (mVSpace >= 0) { - return m_vSpace; + return mVSpace; } else { @@ -61,18 +88,20 @@ int UBFlowLayout::verticalSpacing() const int UBFlowLayout::count() const { - return itemList.size(); + return mItemList.size(); } QLayoutItem* UBFlowLayout::itemAt(int index) const { - return itemList.value(index); + return mItemList.value(index); } QLayoutItem* UBFlowLayout::takeAt(int index) { - if (index >= 0 && index < itemList.size()) - return itemList.takeAt(index); + if (index >= 0 && index < mItemList.size()) + { + return mItemList.takeAt(index); + } return nullptr; } @@ -84,14 +113,14 @@ QLayoutItem* UBFlowLayout::replaceAt(int index, QLayoutItem* item) return nullptr; } - QLayoutItem* b = itemList.value(index); + auto b = mItemList.value(index); if (!b) { return nullptr; } - itemList.replace(index, item); + mItemList.replace(index, item); invalidate(); return b; } @@ -108,7 +137,7 @@ bool UBFlowLayout::hasHeightForWidth() const int UBFlowLayout::heightForWidth(int width) const { - int height = doLayout(QRect(0, 0, width, 0), true); + auto height = doLayout({0, 0, width, 0}, true); return height; } @@ -127,11 +156,13 @@ QSize UBFlowLayout::minimumSize() const { QSize size; - for (const QLayoutItem* item : qAsConst(itemList)) + for (const auto item : qAsConst(mItemList)) + { size = size.expandedTo(item->minimumSize()); + } - const QMargins margins = contentsMargins(); - size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom()); + const auto margins = contentsMargins(); + size += QSize{margins.left() + margins.right(), margins.top() + margins.bottom()}; return size; } @@ -139,21 +170,30 @@ int UBFlowLayout::doLayout(const QRect& rect, bool testOnly) const { int left, top, right, bottom; getContentsMargins(&left, &top, &right, &bottom); - QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); - int x = effectiveRect.x(); - int y = effectiveRect.y(); + const auto effectiveRect = rect.adjusted(+left, +top, -right, -bottom); + auto x = effectiveRect.x(); + auto y = effectiveRect.y(); int lineHeight = 0; - for (QLayoutItem* item : qAsConst(itemList)) + for (auto item : qAsConst(mItemList)) { - const QWidget* wid = item->widget(); - int spaceX = horizontalSpacing(); + const auto wid = item->widget(); + auto spaceX = horizontalSpacing(); + if (spaceX == -1) + { spaceX = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal); - int spaceY = verticalSpacing(); + } + + auto spaceY = verticalSpacing(); + if (spaceY == -1) + { spaceY = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); - int nextX = x + item->sizeHint().width() + spaceX; + } + + auto nextX = x + item->sizeHint().width() + spaceX; + if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) { x = effectiveRect.x(); @@ -163,17 +203,20 @@ int UBFlowLayout::doLayout(const QRect& rect, bool testOnly) const } if (!testOnly) + { item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); + } x = nextX; lineHeight = qMax(lineHeight, item->sizeHint().height()); } + return y + lineHeight - rect.y() + bottom; } int UBFlowLayout::smartSpacing(QStyle::PixelMetric pm) const { - QObject* parent = this->parent(); + auto parent = this->parent(); if (!parent) { @@ -181,7 +224,7 @@ int UBFlowLayout::smartSpacing(QStyle::PixelMetric pm) const } else if (parent->isWidgetType()) { - QWidget* pw = static_cast(parent); + const auto pw = static_cast(parent); return pw->style()->pixelMetric(pm, nullptr, pw); } else diff --git a/src/gui/UBFlowLayout.h b/src/gui/UBFlowLayout.h index 170cf4445..77320a0a5 100644 --- a/src/gui/UBFlowLayout.h +++ b/src/gui/UBFlowLayout.h @@ -1,3 +1,25 @@ +/* + * Copyright (C) 2015-2024 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + #pragma once @@ -30,7 +52,8 @@ class UBFlowLayout : public QLayout int doLayout(const QRect& rect, bool testOnly) const; int smartSpacing(QStyle::PixelMetric pm) const; - QList itemList; - int m_hSpace; - int m_vSpace; +private: + QList mItemList; + int mHSpace; + int mVSpace; }; diff --git a/src/gui/UBPreferredBackgroundWidget.cpp b/src/gui/UBPreferredBackgroundWidget.cpp index 2e927ff27..da0cdcde8 100644 --- a/src/gui/UBPreferredBackgroundWidget.cpp +++ b/src/gui/UBPreferredBackgroundWidget.cpp @@ -1,3 +1,26 @@ +/* + * Copyright (C) 2015-2024 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + + #include "UBPreferredBackgroundWidget.h" #include "board/UBBoardController.h" @@ -6,38 +29,23 @@ #include "gui/UBFlowLayout.h" - UBPreferredBackgroundWidget::UBPreferredBackgroundWidget(QWidget* parent) - : QWidget(parent) + : QWidget{parent} { setAcceptDrops(true); - mLayout = new UBFlowLayout(this, -1, 0, 0); + mLayout = new UBFlowLayout{this, -1, 0, 0}; mLayout->setSizeConstraint(QLayout::SetMaximumSize); setLayout(mLayout); - auto* bgManager = UBApplication::boardController->backgroundManager(); - const auto backgrounds = bgManager->backgrounds(); - - for (const auto& background : backgrounds) - { - auto pixmap = bgManager->createButtonPixmap(*background, false, false); - auto text = background->description(QLocale().name().left(2)); - auto* label = new BackgroundWidget{pixmap, text, this}; - label->setProperty("uuid", background->uuid()); - label->setToolTip(text); - - mLayout->addWidget(label); - } - - mPlaceholder = new QLabel(this); - QPixmap pixmap(QSize{128, 128}); - pixmap.fill(QColor(Qt::transparent)); + mPlaceholder = new QLabel{this}; + QPixmap pixmap{QSize{128, 128}}; + pixmap.fill(QColor{Qt::transparent}); - QPainter painter(&pixmap); + QPainter painter{&pixmap}; QPen pen = painter.pen(); pen.setWidth(4); - pen.setColor(QColor(0x888888)); + pen.setColor(QColor{0xbbbbbb}); pen.setStyle(Qt::DashLine); painter.setPen(pen); painter.drawRoundedRect(6, 20, 115, 88, 15, 15); @@ -45,7 +53,18 @@ UBPreferredBackgroundWidget::UBPreferredBackgroundWidget(QWidget* parent) mPlaceholder->setPixmap(pixmap); mPlaceholder->setVisible(false); + QPixmap trash{":/images/trash-document-page.png"}; + painter.drawPixmap({26, 30, 68, 68}, trash); + + mTrash = new QLabel{this}; + mTrash->setPixmap(pixmap); + mTrash->setVisible(false); + + updateBackgroundButtons(); updateStyle(); + + connect(UBApplication::boardController->backgroundManager(), &UBBackgroundManager::backgroundListChanged, this, + &UBPreferredBackgroundWidget::updateBackgroundButtons); } void UBPreferredBackgroundWidget::dragEnterEvent(QDragEnterEvent* event) @@ -56,17 +75,18 @@ void UBPreferredBackgroundWidget::dragEnterEvent(QDragEnterEvent* event) void UBPreferredBackgroundWidget::dragMoveEvent(QDragMoveEvent* event) { - QScrollArea* scrollArea = dynamic_cast(parentWidget()->parentWidget()); + // auto-scroll if widget is in a scroll area + auto scrollArea = dynamic_cast(parentWidget()->parentWidget()); if (scrollArea) { - QPoint p = mapFromGlobal(event->pos()); - p = event->pos(); + const auto p = event->pos(); scrollArea->ensureVisible(p.x(), p.y(), 15); } - QWidget* child = childAt(event->pos()); + auto child = childAt(event->pos()); + // walk up to a direct child while (child && child->parentWidget() != this) { child = child->parentWidget(); @@ -77,20 +97,19 @@ void UBPreferredBackgroundWidget::dragMoveEvent(QDragMoveEvent* event) return; } - //is the child the placeholder label? - if (child == mPlaceholder) + // is the child the placeholder or trash label? + if (child == mPlaceholder || child == mTrash) { return; } // move the placeholder to the appropiate place - auto pl = mLayout->indexOf(mPlaceholder); - auto ix = mLayout->indexOf(child); + const auto pl = mLayout->indexOf(mPlaceholder); + const auto ix = mLayout->indexOf(child); if (pl >= 0 && ix >= 0) { - QLayoutItem* plItem = mLayout->takeAt(pl); - + auto plItem = mLayout->takeAt(pl); mLayout->insertItem(ix, plItem); updateStyle(); } @@ -98,7 +117,34 @@ void UBPreferredBackgroundWidget::dragMoveEvent(QDragMoveEvent* event) void UBPreferredBackgroundWidget::dropEvent(QDropEvent* event) { - QWidget* child = childAt(event->pos()); + auto child = childAt(event->pos()); + + // is the child the trash? + if (child == mTrash) + { + // ask user whether to delete the background ruling + const auto uuid = mDraggedItem->widget()->property("uuid").toUuid(); + auto bgManager = UBApplication::boardController->backgroundManager(); + const auto background = bgManager->background(uuid); + const auto lang = QLocale().name().left(2); + + const auto answer = + QMessageBox::question(this, tr("Delete background"), + tr("Do you want to delete the background") + " " + background->description(lang)); + + if (answer == QMessageBox::Yes) + { + bgManager->deleteBackground(uuid); + delete mDraggedItem->widget(); + delete mDraggedItem; + mDraggedItem = nullptr; + mLayout->removeWidget(mPlaceholder); + mPlaceholder->setVisible(false); + mTrash->setVisible(false); + } + + return; + } // child must be placeholder if (child != mPlaceholder) @@ -114,7 +160,9 @@ void UBPreferredBackgroundWidget::dropEvent(QDropEvent* event) } mLayout->replaceAt(ix, mDraggedItem); + mLayout->removeWidget(mPlaceholder); mPlaceholder->setVisible(false); + mTrash->setVisible(false); updateStyle(); event->acceptProposedAction(); @@ -122,14 +170,15 @@ void UBPreferredBackgroundWidget::dropEvent(QDropEvent* event) void UBPreferredBackgroundWidget::mousePressEvent(QMouseEvent* event) { - auto* child = childAt(event->pos()); + auto child = childAt(event->pos()); + // walk up to a direct child while (child && child->parentWidget() != this) { child = child->parentWidget(); } - auto* backgroundWidget = dynamic_cast(child); + auto backgroundWidget = dynamic_cast(child); if (!backgroundWidget) { @@ -137,15 +186,20 @@ void UBPreferredBackgroundWidget::mousePressEvent(QMouseEvent* event) } mDraggedItemPos = mLayout->indexOf(backgroundWidget); - QLayoutItem* item = new QWidgetItem(mPlaceholder); + auto item = new QWidgetItem{mPlaceholder}; mDraggedItem = mLayout->replaceAt(mDraggedItemPos, item); mPlaceholder->setVisible(true); mDraggedItem->widget()->setVisible(false); - QPixmap pixmap = backgroundWidget->pixmap(); + const auto uuid = mDraggedItem->widget()->property("uuid").toUuid(); + const auto background = UBApplication::boardController->backgroundManager()->background(uuid); + + mTrash->setVisible(background && background->isUserProvided()); - QMimeData* mimeData = new QMimeData; - QDrag* drag = new QDrag(this); + auto pixmap = backgroundWidget->pixmap(); + + auto mimeData = new QMimeData; + auto drag = new QDrag{this}; drag->setMimeData(mimeData); drag->setPixmap(pixmap); drag->setHotSpot(event->pos() - backgroundWidget->pos()); @@ -156,13 +210,15 @@ void UBPreferredBackgroundWidget::mousePressEvent(QMouseEvent* event) // abort DnD and put dragged item at original position if (mDraggedItem && mDraggedItemPos >= 0) { - auto ix = mLayout->indexOf(mPlaceholder); + const auto ix = mLayout->indexOf(mPlaceholder); if (ix >= 0) { mLayout->takeAt(ix); mLayout->insertItem(mDraggedItemPos, mDraggedItem); + mLayout->removeWidget(mPlaceholder); mPlaceholder->setVisible(false); + mTrash->setVisible(false); } } } @@ -181,8 +237,8 @@ void UBPreferredBackgroundWidget::updateStyle() const { for (int i = 0; i < mLayout->count(); ++i) { - QWidget* widget = mLayout->itemAt(i)->widget(); - QLabel* icon = widget->findChild("backgroundIcon"); + auto widget = mLayout->itemAt(i)->widget(); + auto icon = widget->findChild("backgroundIcon"); if (icon) { @@ -203,22 +259,55 @@ void UBPreferredBackgroundWidget::savePreferrdBackgrounds() const UBApplication::boardController->backgroundManager()->savePreferredBackgrounds(uuidList); } -UBPreferredBackgroundWidget::BackgroundWidget::BackgroundWidget(const QPixmap& pixmap, const QString& text, QWidget* parent) +void UBPreferredBackgroundWidget::updateBackgroundButtons() +{ + while (!mLayout->isEmpty()) + { + auto item = mLayout->takeAt(0); + auto widget = item->widget(); + + if (widget != mPlaceholder && widget != mTrash) + { + delete widget; + } + + delete item; + } + + auto* bgManager = UBApplication::boardController->backgroundManager(); + const auto backgrounds = bgManager->backgrounds(); + + for (const auto& background : backgrounds) + { + auto pixmap = bgManager->createButtonPixmap(*background, false, false); + auto text = background->description(QLocale().name().left(2)); + auto widget = new BackgroundWidget{pixmap, text, this}; + widget->setProperty("uuid", background->uuid()); + widget->setToolTip(text); + + mLayout->addWidget(widget); + } + + mLayout->addWidget(mTrash); +} + +UBPreferredBackgroundWidget::BackgroundWidget::BackgroundWidget(const QPixmap& pixmap, const QString& text, + QWidget* parent) : QWidget{parent} , mPixmap{pixmap} { - QLabel* icon = new QLabel{this}; + auto icon = new QLabel{this}; icon->setPixmap(pixmap); icon->setAlignment(Qt::AlignCenter); icon->setObjectName("backgroundIcon"); - QLabel* label = new QLabel{this}; + auto label = new QLabel{this}; label->setText(text); label->setAlignment(Qt::AlignCenter); label->setWordWrap(true); label->setMaximumWidth(pixmap.width()); - QVBoxLayout* layout = new QVBoxLayout{this}; + auto layout = new QVBoxLayout{this}; layout->setSpacing(0); layout->setMargin(0); layout->addWidget(icon); diff --git a/src/gui/UBPreferredBackgroundWidget.h b/src/gui/UBPreferredBackgroundWidget.h index d0014011b..e69f02608 100644 --- a/src/gui/UBPreferredBackgroundWidget.h +++ b/src/gui/UBPreferredBackgroundWidget.h @@ -1,3 +1,26 @@ +/* + * Copyright (C) 2015-2024 Département de l'Instruction Publique (DIP-SEM) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + + #pragma once #include @@ -24,9 +47,13 @@ class UBPreferredBackgroundWidget : public QWidget void updateStyle() const; void savePreferrdBackgrounds() const; +private slots: + void updateBackgroundButtons(); + private: - UBFlowLayout* mLayout; + UBFlowLayout* mLayout{nullptr}; QLabel* mPlaceholder{nullptr}; + QLabel* mTrash{nullptr}; QLayoutItem* mDraggedItem{nullptr}; int mDraggedItemPos{-1}; diff --git a/src/gui/gui.pri b/src/gui/gui.pri index 9e7b831a9..5d9614ec1 100644 --- a/src/gui/gui.pri +++ b/src/gui/gui.pri @@ -47,6 +47,8 @@ HEADERS += \ src/gui/UBBackgroundPalette.h \ src/gui/UBBackgroundManager.h \ src/gui/UBBackgroundRuling.h \ + src/gui/UBFlowLayout.h \ + src/gui/UBPreferredBackgroundWidget.h \ src/gui/UBBoardThumbnailsView.h \ src/gui/UBSnapIndicator.h SOURCES += \ @@ -98,6 +100,8 @@ SOURCES += \ src/gui/UBBackgroundPalette.cpp \ src/gui/UBBackgroundManager.cpp \ src/gui/UBBackgroundRuling.cpp \ + src/gui/UBFlowLayout.cpp \ + src/gui/UBPreferredBackgroundWidget.cpp \ src/gui/UBBoardThumbnailsView.cpp \ src/gui/UBSnapIndicator.cpp From 1b6b35fb227200be660627c2ee55abba9f5f668b Mon Sep 17 00:00:00 2001 From: sebojolais Date: Wed, 14 Feb 2024 22:42:31 +0100 Subject: [PATCH 087/133] Add support of Qt6 and fixes include of . --- src/core/UBSettings.cpp | 2 +- src/gui/UBBackgroundManager.cpp | 13 +++++---- src/gui/UBBackgroundRuling.cpp | 36 ++++++++++++------------- src/gui/UBBackgroundRuling.h | 1 + src/gui/UBPreferredBackgroundWidget.cpp | 2 +- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/core/UBSettings.cpp b/src/core/UBSettings.cpp index c3eb58b6f..b7c8285ab 100644 --- a/src/core/UBSettings.cpp +++ b/src/core/UBSettings.cpp @@ -815,7 +815,7 @@ bool UBSettings::isDarkBackground() QUuid UBSettings::pageBackgroundUuid() { - QUuid uuid = value("Board/PageBackground", 0).toString(); + QUuid uuid = value("Board/PageBackground", 0).toUuid(); return uuid; } diff --git a/src/gui/UBBackgroundManager.cpp b/src/gui/UBBackgroundManager.cpp index 729a07b2d..b99309bdc 100644 --- a/src/gui/UBBackgroundManager.cpp +++ b/src/gui/UBBackgroundManager.cpp @@ -64,7 +64,7 @@ void UBBackgroundManager::addBackground(UBBackgroundRuling &background) if (!file.open(QFile::WriteOnly)) { - qWarning() << "Cannot open" << file; + qWarning() << "Cannot open" << file.fileName(); return; } @@ -110,8 +110,11 @@ const QList UBBackgroundManager::backgrounds() const // first add rulings from list for (const auto& uuid : uuidList) { +#if(QT_VERSION_MAJOR == 6) + const auto ruling = background(QUuid(QAnyStringView(uuid))); +#else const auto ruling = background(uuid); - +#endif if (ruling && ruling->isValid()) { backgroundList << ruling; @@ -260,7 +263,7 @@ void UBBackgroundManager::scan(const QString &dirname, bool userProvided) } else { - qWarning() << "Error reading background definitions from" << file; + qWarning() << "Error reading background definitions from" << file.fileName(); } } } @@ -295,7 +298,7 @@ QPixmap UBBackgroundManager::createButtonPixmap(const QDomDocument& bgDoc, bool if (!templateFile.open(QFile::ReadOnly)) { - qWarning() << "Cannot find template file" << templateFile; + qWarning() << "Cannot find template file" << templateFile.fileName(); return {}; } @@ -303,7 +306,7 @@ QPixmap UBBackgroundManager::createButtonPixmap(const QDomDocument& bgDoc, bool if (!doc.setContent(&templateFile, true)) { - qWarning() << "Cannot load template file" << templateFile; + qWarning() << "Cannot load template file" << templateFile.fileName(); return {}; } diff --git a/src/gui/UBBackgroundRuling.cpp b/src/gui/UBBackgroundRuling.cpp index 95ddc6c6a..cb84d1247 100644 --- a/src/gui/UBBackgroundRuling.cpp +++ b/src/gui/UBBackgroundRuling.cpp @@ -72,7 +72,7 @@ static constexpr char const* valueTrue{"true"}; // helper functions static bool getStringValue(QXmlStreamReader& reader, const QString& name, QString& value) { - if (reader.isStartElement() && reader.namespaceUri() == namespaceURI && reader.name() == name) + if (reader.isStartElement() && reader.namespaceUri().toString() == namespaceURI && reader.name() == name) { const auto text = reader.readElementText(); @@ -585,7 +585,7 @@ UBBackgroundRuling::LineColor::LineColor(const Rules& rules, QXmlStreamReader& r , mOnDark{rules.defaultColor().onDark()} , mOnLight{rules.defaultColor().onLight()} { - while (reader.readNextStartElement() && reader.namespaceUri() == namespaceURI) + while (reader.readNextStartElement() && reader.namespaceUri().toString() == namespaceURI) { if (getColorValue(reader, elementOnDark, mOnDark)) { @@ -635,7 +635,7 @@ UBBackgroundRuling::Line::Line(const Rules& rules, QXmlStreamReader& reader) : Data{rules} , mColor{rules.defaultColor()} { - while (reader.readNextStartElement() && reader.namespaceUri() == namespaceURI) + while (reader.readNextStartElement() && reader.namespaceUri().toString() == namespaceURI) { if (getDecimalValue(reader, elementOffset, mOffset)) { @@ -643,7 +643,7 @@ UBBackgroundRuling::Line::Line(const Rules& rules, QXmlStreamReader& reader) else if (getDecimalValue(reader, elementWidth, mWidth)) { } - else if (reader.name() == elementColor) + else if (reader.name().toString() == elementColor) { mColor = LineColor{rules, reader}; } @@ -685,7 +685,7 @@ const UBBackgroundRuling::LineColor& UBBackgroundRuling::Line::color() const UBBackgroundRuling::Border::Border(const Rules& rules, QXmlStreamReader& reader) : Data{rules} { - while (reader.readNextStartElement() && reader.namespaceUri() == namespaceURI) + while (reader.readNextStartElement() && reader.namespaceUri().toString() == namespaceURI) { double value; @@ -697,7 +697,7 @@ UBBackgroundRuling::Border::Border(const Rules& rules, QXmlStreamReader& reader) { mRight.emplace(value); } - else if (reader.name() == elementLine) + else if (reader.name().toString() == elementLine) { const Line bgLine{rules, reader}; @@ -753,7 +753,7 @@ UBBackgroundRuling::Linegroup::Linegroup(const Rules& rules, QXmlStreamReader& r { QString lineGroupOrigin; - while (reader.readNextStartElement() && reader.namespaceUri() == namespaceURI) + while (reader.readNextStartElement() && reader.namespaceUri().toString() == namespaceURI) { if (getDecimalValue(reader, elementAngle, mAngle)) { @@ -788,7 +788,7 @@ UBBackgroundRuling::Linegroup::Linegroup(const Rules& rules, QXmlStreamReader& r setError(); } } - else if (reader.name() == elementLine) + else if (reader.name().toString() == elementLine) { const Line bgLine{rules, reader}; @@ -801,7 +801,7 @@ UBBackgroundRuling::Linegroup::Linegroup(const Rules& rules, QXmlStreamReader& r mLines.append(bgLine); } } - else if (reader.name() == elementBorder) + else if (reader.name().toString() == elementBorder) { mBorder.emplace(rules, reader); } @@ -891,7 +891,7 @@ UBBackgroundRuling::Rules::Rules(QXmlStreamReader& reader) // current position of reader should be at the element while (!reader.isEndElement()) { - while (reader.readNextStartElement() && reader.namespaceUri() == namespaceURI) + while (reader.readNextStartElement() && reader.namespaceUri().toString() == namespaceURI) { const auto name = reader.name(); @@ -901,26 +901,26 @@ UBBackgroundRuling::Rules::Rules(QXmlStreamReader& reader) { mUuid = QUuid(text); } - else if (name == elementDescription) + else if (name.toString() == elementDescription) { const auto attributes = reader.attributes(); const auto lang = attributes.value(attributeXmlLang).toString(); mDescriptions[lang.isEmpty() ? "en" : lang] = reader.readElementText(); } - else if (name == elementAttributes) + else if (name.toString() == elementAttributes) { const auto attributes = reader.attributes(); - mCrossed = attributes.value(attributeCrossed) == valueTrue; - mRuled = attributes.value(attributeRuled) == valueTrue; - mIntermediateLines = attributes.value(attributeIntermediateLines) == valueTrue; + mCrossed = attributes.value(attributeCrossed).toString() == valueTrue; + mRuled = attributes.value(attributeRuled).toString() == valueTrue; + mIntermediateLines = attributes.value(attributeIntermediateLines).toString() == valueTrue; reader.skipCurrentElement(); } - else if (name == elementDefaultColor) + else if (name.toString() == elementDefaultColor) { mDefaultColor = LineColor{*this, reader}; } - else if (name == elementLinegroup) + else if (name.toString() == elementLinegroup) { const Linegroup bgLinegroup{*this, reader}; @@ -943,7 +943,7 @@ UBBackgroundRuling::Rules::Rules(QXmlStreamReader& reader) UBBackgroundRuling::Rules* UBBackgroundRuling::Rules::fromXml(QXmlStreamReader& reader) { - if (reader.namespaceUri() == namespaceURI && reader.name() == elementBackground) + if (reader.namespaceUri().toString() == namespaceURI && reader.name().toString() == elementBackground) { return new Rules(reader); } diff --git a/src/gui/UBBackgroundRuling.h b/src/gui/UBBackgroundRuling.h index 1dee4f254..6586eba37 100644 --- a/src/gui/UBBackgroundRuling.h +++ b/src/gui/UBBackgroundRuling.h @@ -30,6 +30,7 @@ #include #include +#include // forward class QPainter; diff --git a/src/gui/UBPreferredBackgroundWidget.cpp b/src/gui/UBPreferredBackgroundWidget.cpp index da0cdcde8..fdc2366a9 100644 --- a/src/gui/UBPreferredBackgroundWidget.cpp +++ b/src/gui/UBPreferredBackgroundWidget.cpp @@ -309,7 +309,7 @@ UBPreferredBackgroundWidget::BackgroundWidget::BackgroundWidget(const QPixmap& p auto layout = new QVBoxLayout{this}; layout->setSpacing(0); - layout->setMargin(0); + layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(icon); layout->addWidget(label); setLayout(layout); From 407c84ecf796bf562939be5b8e1d9d4856c9b2b4 Mon Sep 17 00:00:00 2001 From: sebojolais Date: Tue, 20 Feb 2024 21:36:52 +0100 Subject: [PATCH 088/133] No mention of QAnyStringView and no Qt version checking are beter. --- src/gui/UBBackgroundManager.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/gui/UBBackgroundManager.cpp b/src/gui/UBBackgroundManager.cpp index b99309bdc..3da6749f8 100644 --- a/src/gui/UBBackgroundManager.cpp +++ b/src/gui/UBBackgroundManager.cpp @@ -110,11 +110,7 @@ const QList UBBackgroundManager::backgrounds() const // first add rulings from list for (const auto& uuid : uuidList) { -#if(QT_VERSION_MAJOR == 6) - const auto ruling = background(QUuid(QAnyStringView(uuid))); -#else - const auto ruling = background(uuid); -#endif + const auto ruling = background(QUuid::fromString(uuid)); if (ruling && ruling->isValid()) { backgroundList << ruling; From 460aea7b0bada87dffc4c716435bc325c2f545b7 Mon Sep 17 00:00:00 2001 From: sebojolais Date: Tue, 20 Feb 2024 21:46:07 +0100 Subject: [PATCH 089/133] Minimal changes. --- src/gui/UBBackgroundManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/UBBackgroundManager.cpp b/src/gui/UBBackgroundManager.cpp index 3da6749f8..2bda34193 100644 --- a/src/gui/UBBackgroundManager.cpp +++ b/src/gui/UBBackgroundManager.cpp @@ -111,6 +111,7 @@ const QList UBBackgroundManager::backgrounds() const for (const auto& uuid : uuidList) { const auto ruling = background(QUuid::fromString(uuid)); + if (ruling && ruling->isValid()) { backgroundList << ruling; From c1c943432a9f0b14825095acc83cb5bb01e581e0 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Wed, 21 Feb 2024 07:47:20 +0100 Subject: [PATCH 090/133] feat: store local patterns in background directory - remove the extra template subdirectory from the path --- src/gui/UBBackgroundManager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/UBBackgroundManager.cpp b/src/gui/UBBackgroundManager.cpp index 2bda34193..ded74c79d 100644 --- a/src/gui/UBBackgroundManager.cpp +++ b/src/gui/UBBackgroundManager.cpp @@ -41,7 +41,7 @@ void UBBackgroundManager::scan() { // scan application and user directories for background rules const QString appDir{UBPlatformUtils::applicationTemplateDirectory() + "/background"}; - const QString usrDir{UBSettings::userDataDirectory() + "/template/background"}; + const QString usrDir{UBSettings::userDataDirectory() + "/background"}; scan(appDir, false); scan(usrDir, true); @@ -55,8 +55,8 @@ void UBBackgroundManager::addBackground(UBBackgroundRuling &background) { mBackgrounds.append(background); - // store in user template directory - const QString usrDir{UBSettings::userDataDirectory() + "/template/background/"}; + // store in user background template directory + const QString usrDir{UBSettings::userDataDirectory() + "/background/"}; QDir dir; dir.mkpath(usrDir); @@ -94,7 +94,7 @@ void UBBackgroundManager::deleteBackground(const QUuid& uuid) if (bg->isValid() && bg->isUserProvided()) { mBackgrounds.removeAll(*bg); - const QString usrDir{UBSettings::userDataDirectory() + "/template/background/"}; + const QString usrDir{UBSettings::userDataDirectory() + "/background/"}; QFile::remove(usrDir + uuid.toString() + ".xml"); emit backgroundListChanged(); From 8083e9ec8372c248a765dd76c05d021c1ab28279 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 25 Feb 2024 08:20:51 +0100 Subject: [PATCH 091/133] feat: replace border by stretch and stack - use stretch element to limit length of lines - positive values extend outside of page border - negative values restrict to inside page border - keep option to draw border lines - fix algorithm so that it works for any line group angle - stretch now also works for single lines (spacing = 0) - add stack element to limit stacking of line groups - positive values extend outside of page border - negative values restrict to inside page border - update XML schema accordingly - update rules accordingly --- resources/etc/background/05_seyes.xml | 26 +- resources/etc/background/06_staveBorder.xml | 12 +- resources/etc/background/background.xsd | 33 ++- resources/etc/background/de-primary1.xml | 8 +- resources/etc/background/de-primary2.xml | 8 +- resources/etc/background/de-primary3.xml | 8 +- src/gui/UBBackgroundRuling.cpp | 308 ++++++++++++-------- src/gui/UBBackgroundRuling.h | 20 +- 8 files changed, 264 insertions(+), 159 deletions(-) diff --git a/resources/etc/background/05_seyes.xml b/resources/etc/background/05_seyes.xml index cad1b5226..9dd1549de 100644 --- a/resources/etc/background/05_seyes.xml +++ b/resources/etc/background/05_seyes.xml @@ -37,10 +37,14 @@ #996fa8dc - - 0 - 0 - + + 50 + 0 + + + 0 + 0 + 90 @@ -54,17 +58,29 @@ #8e7cc3 + + 0 + 50 + + + 0 + 0 + 90 topleft - 20 + 0 2 #ff0000 #ff0000 + + 0 + 50 + diff --git a/resources/etc/background/06_staveBorder.xml b/resources/etc/background/06_staveBorder.xml index 102540dca..33cd8df21 100644 --- a/resources/etc/background/06_staveBorder.xml +++ b/resources/etc/background/06_staveBorder.xml @@ -26,13 +26,17 @@ 20 1 - - 5 - 5 + + -5 + -5 0 1 - + + + 0 + 0 + diff --git a/resources/etc/background/background.xsd b/resources/etc/background/background.xsd index 8ff787d21..303b74265 100644 --- a/resources/etc/background/background.xsd +++ b/resources/etc/background/background.xsd @@ -45,7 +45,7 @@ - + @@ -58,10 +58,11 @@ defining the point relative to which the line distances are calculated; useful for single lines relative to border. - a set of lines in the group. - - an optional border, which is closing the line group to the left and/or - the right. If one of the elements "left" or "right" is set, lines in the group - do not continue endlessly, but end at the specified distance from the page border. - Offsets of a border line are calculated inwards from the respecive side. + - an optional stretch, which limits the length of lines at the start or end. + The stretch element can contain optional line elements, which draw a closing + line connecting the lines of a line group. Offsets of a border line are + calculated inwards from the respecive side. + - an optional stack, which limits the stacking of line groups. --> @@ -78,13 +79,21 @@ - - + + - - - + + + + + + + + + + + @@ -99,8 +108,8 @@ --> - - + + diff --git a/resources/etc/background/de-primary1.xml b/resources/etc/background/de-primary1.xml index 6055a6b12..d3f9d1c04 100644 --- a/resources/etc/background/de-primary1.xml +++ b/resources/etc/background/de-primary1.xml @@ -21,13 +21,13 @@ 15 1 - - 5 - 5 + + -5 + -5 0 1 - + diff --git a/resources/etc/background/de-primary2.xml b/resources/etc/background/de-primary2.xml index f3d2d3399..be103166b 100644 --- a/resources/etc/background/de-primary2.xml +++ b/resources/etc/background/de-primary2.xml @@ -21,13 +21,13 @@ 12 1 - - 5 - 5 + + -5 + -5 0 1 - + diff --git a/resources/etc/background/de-primary3.xml b/resources/etc/background/de-primary3.xml index 964025d90..fd5622347 100644 --- a/resources/etc/background/de-primary3.xml +++ b/resources/etc/background/de-primary3.xml @@ -13,13 +13,13 @@ 3.5 1 - - 5 - 5 + + -5 + -5 0 1 - + diff --git a/src/gui/UBBackgroundRuling.cpp b/src/gui/UBBackgroundRuling.cpp index cb84d1247..903d26e4a 100644 --- a/src/gui/UBBackgroundRuling.cpp +++ b/src/gui/UBBackgroundRuling.cpp @@ -44,19 +44,20 @@ static constexpr char const* attributeXmlLang{"xml:lang"}; static constexpr char const* elementAngle{"angle"}; static constexpr char const* elementAttributes{"attributes"}; static constexpr char const* elementBackground{"background"}; -static constexpr char const* elementBorder{"border"}; static constexpr char const* elementColor{"color"}; static constexpr char const* elementDefaultColor{"defaultColor"}; static constexpr char const* elementDescription{"description"}; -static constexpr char const* elementLeft{"left"}; +static constexpr char const* elementFrom{"from"}; static constexpr char const* elementLinegroup{"linegroup"}; static constexpr char const* elementLine{"line"}; static constexpr char const* elementOffset{"offset"}; static constexpr char const* elementOnDark{"onDark"}; static constexpr char const* elementOnLight{"onLight"}; static constexpr char const* elementOrigin{"origin"}; -static constexpr char const* elementRight{"right"}; static constexpr char const* elementSpacing{"spacing"}; +static constexpr char const* elementStack{"stack"}; +static constexpr char const* elementStretch{"stretch"}; +static constexpr char const* elementTo{"to"}; static constexpr char const* elementUuid{"uuid"}; static constexpr char const* elementWidth{"width"}; @@ -341,6 +342,8 @@ void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double grid } } + const auto dotsPerMm = gridSize / 10; + painter->setRenderHint(QPainter::Antialiasing, true); const QColor defaultOnDark{UBSettings::settings()->boardCrossColorDarkBackground->get().toString()}; const QColor defaultOnLight{UBSettings::settings()->boardCrossColorLightBackground->get().toString()}; @@ -349,7 +352,7 @@ void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double grid for (const auto& linegroup : mRules->linegroups()) { const auto angle = linegroup.angle(); - const auto spacing = linegroup.spacing() * gridSize / 10; + const auto spacing = linegroup.spacing() * dotsPerMm; auto origin{nominalScene.center()}; @@ -375,135 +378,190 @@ void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double grid break; } - // border needs different calculation of start and end of line - // relative to left and right border - double leftBorder{0}; - double rightBorder{0}; + // determine minimum and maximum offset of line group + std::vector offsets; + offsets.reserve(linegroup.lines().count()); + + for (const auto& line : linegroup.lines()) + { + offsets.push_back(line.offset()); + } + + const auto minmax = std::minmax_element(offsets.cbegin(), offsets.cend()); + const double minOffset = *minmax.first * dotsPerMm; + const double maxOffset = *minmax.second * dotsPerMm; + + // stretch needs different calculation of start and end of line + double fromStretch{0}; + double toStretch{0}; - bool hasLeftBorder{false}; - bool hasRightBorder{false}; + bool hasFromStretch{false}; + bool hasToStretch{false}; QList borderLines; - if (linegroup.border()) + if (linegroup.stretch()) { - const auto border = linegroup.border().value(); + const auto stretch = linegroup.stretch().value(); - hasLeftBorder = border.left().has_value(); - hasRightBorder = border.right().has_value(); + hasFromStretch = stretch.from().has_value(); + hasToStretch = stretch.to().has_value(); - leftBorder = border.left().value_or(0); - rightBorder = border.right().value_or(0); + fromStretch = stretch.from().value_or(0) * dotsPerMm; + toStretch = stretch.to().value_or(0) * dotsPerMm; - leftBorder *= gridSize / 10; - rightBorder *= gridSize / 10; + borderLines = stretch.lines(); + } + + // stack adds additional constraints to repetition of line group + double fromStack{0}; + double toStack{0}; - borderLines = border.lines(); + bool hasFromStack{false}; + bool hasToStack{false}; + + if (linegroup.stack()) + { + const auto stack = linegroup.stack().value(); + + hasFromStack = stack.from().has_value(); + hasToStack = stack.to().has_value(); + + fromStack = stack.from().value_or(0) * dotsPerMm; + toStack = stack.to().value_or(0) * dotsPerMm; } - // loop through lines - for (const auto& line : linegroup.lines()) + // determine relevant corners + QPointF stackFrom = nominalScene.topLeft(); + QPointF stackTo = nominalScene.bottomRight(); + QPointF stretchFrom = nominalScene.bottomLeft(); + QPointF stretchTo = nominalScene.topRight(); + QPointF rectFrom = rect.topLeft(); + QPointF rectTo = rect.bottomRight(); + + const bool descending = int(angle / 90.) % 2 != 0; + const bool flipped = int(angle / 180.) % 2 != 0; + + if (descending) { - const auto offset = line.offset() * gridSize / 10; + // swap circularly counter-clockwise + std::swap(stretchTo, stackTo); + std::swap(stackFrom, stretchTo); + std::swap(stretchFrom, stackFrom); + + rectFrom = rect.topRight(); + rectTo = rect.bottomLeft(); + } + + if (flipped) + { + // swap diagonal + std::swap(stretchFrom, stretchTo); + std::swap(stackFrom, stackTo); + + std::swap(rectFrom, rectTo); + } + + // create a line through origin + auto originLine = QLineF::fromPolar(5000, angle).translated(origin); + originLine.setP1(origin + origin - originLine.p2()); // extend in other direction - setLinePainter(painter, line, onDark, defaultOnDark, defaultOnLight); + // normal vector for translations + auto normal = originLine.normalVector(); + QPointF spaceShift{0, 0}; - // get relevant corners of rectangle according to line angle - const bool ascending = int(angle / 90.) % 2 == 0; + auto minIndex{0}; + auto maxIndex{0}; - QPointF p1; - QPointF p2; + if (spacing > 0) + { + normal.setLength(spacing); + spaceShift = normal.p1() - normal.p2(); - if (ascending) + // calculate offsets for first and last lines + minIndex = int(distance(originLine, rectFrom) / spacing); + maxIndex = int(distance(originLine, rectTo) / spacing); + + if (minIndex > maxIndex) { - p1 = rect.topLeft(); - p2 = rect.bottomRight(); + std::swap(minIndex, maxIndex); } - else + } + + const auto distFrom = distance(originLine, stackFrom); + const auto distTo = distance(originLine, stackTo); + + for (int index = minIndex; index <= maxIndex; ++index) + { + if (hasFromStack && distFrom - (index * spacing + minOffset) > fromStack) { - p1 = rect.topRight(); - p2 = rect.bottomLeft(); + continue; } - // create a line through origin - auto originLine = QLineF::fromPolar(5000, angle).translated(origin); - originLine.setP1(origin + origin - originLine.p2()); // extend in other direction - - if (spacing > 0) + if (hasToStack && (index * spacing + maxOffset) - distTo > toStack) { - // calculate offsets for first and last lines - auto minIndex = int(distance(originLine, p1) / spacing); - auto maxIndex = int(distance(originLine, p2) / spacing); + break; + } - if (minIndex > maxIndex) - { - std::swap(minIndex, maxIndex); - } + // loop through lines + for (const auto& line : linegroup.lines()) + { + const auto offset = line.offset() * dotsPerMm; + const auto offsetShift = (normal.p1() - normal.p2()) / normal.length() * offset; - // normal vector for translations - auto normal = originLine.normalVector(); - normal.setLength(spacing); - const auto spaceShift = normal.p1() - normal.p2(); - normal.setLength(offset); - const auto offsetShift = normal.p1() - normal.p2(); + setLinePainter(painter, line, onDark, defaultOnDark, defaultOnLight); - const auto lastLine = &line == &linegroup.lines().last(); + auto gridLine = originLine.translated(index * spaceShift + offsetShift); - for (int index = minIndex - 1; index <= maxIndex; ++index) + if (hasFromStretch) { - auto gridLine = originLine.translated(index * spaceShift + offsetShift); + // calculate base point using normal through stretchFrom + const auto border = normal.translated(stretchFrom - normal.p1()); + QPointF basePoint; + gridLine.intersects(border, &basePoint); + + QLineF shift = gridLine.unitVector(); + shift.translate(basePoint - shift.p1()); + shift.setLength(-fromStretch); + gridLine.setP1(shift.p2()); - if (hasLeftBorder) + if (&line == &linegroup.lines().last()) { - auto p1 = gridLine.p1(); - p1.setX(nominalScene.left() + leftBorder); - gridLine.setP1(p1); + // draw border lines on "from" side + QLineF borderLine{gridLine.p1() - offsetShift, gridLine.p1()}; - if (lastLine) + if (clip(rect, borderLine)) { - // draw border lines on left side - QLineF borderLine{p1 - offsetShift, p1}; - - if (clip(rect, borderLine)) - { - drawBorderLines(painter, borderLines, borderLine, Qt::LeftEdge, gridSize, onDark, - defaultOnDark, defaultOnLight); - } + drawBorderLines(painter, borderLines, borderLine, Qt::LeftEdge, dotsPerMm, onDark, + defaultOnDark, defaultOnLight); } } + } - if (hasRightBorder) + if (hasToStretch) + { + // calculate base point using normal through stretchTo + const auto border = normal.translated(stretchTo - normal.p1()); + QPointF basePoint; + gridLine.intersects(border, &basePoint); + + QLineF shift = gridLine.unitVector(); + shift.translate(basePoint - shift.p1()); + shift.setLength(toStretch); + gridLine.setP2(shift.p2()); + + if (&line == &linegroup.lines().last()) { - auto p2 = gridLine.p2(); - p2.setX(nominalScene.right() - rightBorder); - gridLine.setP2(p2); + // draw border lines on "to" side + QLineF borderLine{gridLine.p2() - offsetShift, gridLine.p2()}; - if (lastLine) + if (clip(rect, borderLine)) { - // draw border lines on right side - QLineF borderLine{p2 - offsetShift, p2}; - - if (clip(rect, borderLine)) - { - drawBorderLines(painter, borderLines, borderLine, Qt::RightEdge, gridSize, onDark, - defaultOnDark, defaultOnLight); - } + drawBorderLines(painter, borderLines, borderLine, Qt::RightEdge, dotsPerMm, onDark, + defaultOnDark, defaultOnLight); } } - - if (clip(rect, gridLine)) - { - painter->drawLine(gridLine); - } } - } - else if (spacing == 0) - { - // single line at offset - auto normal = originLine.normalVector(); - normal.setLength(offset); - const auto offsetShift = normal.p1() - normal.p2(); - auto gridLine = originLine.translated(offsetShift); if (clip(rect, gridLine)) { @@ -533,7 +591,7 @@ void UBBackgroundRuling::setLinePainter(QPainter* painter, const Line& line, boo } void UBBackgroundRuling::drawBorderLines(QPainter* painter, const QList& borderLines, QLineF line, Qt::Edge edge, - double gridSize, bool onDark, QColor defaultOnDark, + double dotsPerMm, bool onDark, QColor defaultOnDark, QColor defaultOnLight) const { painter->save(); @@ -543,7 +601,7 @@ void UBBackgroundRuling::drawBorderLines(QPainter* painter, const QList& b setLinePainter(painter, borderLine, onDark, defaultOnDark, defaultOnLight); auto offset = borderLine.offset(); - offset *= gridSize / 10; + offset *= dotsPerMm; if (edge == Qt::RightEdge) { @@ -682,20 +740,20 @@ const UBBackgroundRuling::LineColor& UBBackgroundRuling::Line::color() const return mColor; } -UBBackgroundRuling::Border::Border(const Rules& rules, QXmlStreamReader& reader) +UBBackgroundRuling::Limit::Limit(const Rules& rules, QXmlStreamReader& reader) : Data{rules} { while (reader.readNextStartElement() && reader.namespaceUri().toString() == namespaceURI) { double value; - if (getDecimalValue(reader, elementLeft, value)) + if (getDecimalValue(reader, elementFrom, value)) { - mLeft.emplace(value); + mFrom.emplace(value); } - else if (getDecimalValue(reader, elementRight, value)) + else if (getDecimalValue(reader, elementTo, value)) { - mRight.emplace(value); + mTo.emplace(value); } else if (reader.name().toString() == elementLine) { @@ -713,16 +771,16 @@ UBBackgroundRuling::Border::Border(const Rules& rules, QXmlStreamReader& reader) } } -void UBBackgroundRuling::Border::toXml(QXmlStreamWriter& writer) const +void UBBackgroundRuling::Limit::toXml(QXmlStreamWriter& writer) const { - if (mLeft) + if (mFrom) { - writer.writeTextElement(namespaceURI, elementLeft, QString::number(mLeft.value())); + writer.writeTextElement(namespaceURI, elementFrom, QString::number(mFrom.value())); } - if (mRight) + if (mTo) { - writer.writeTextElement(namespaceURI, elementRight, QString::number(mRight.value())); + writer.writeTextElement(namespaceURI, elementTo, QString::number(mTo.value())); } for (const auto& line : mLines) @@ -733,17 +791,17 @@ void UBBackgroundRuling::Border::toXml(QXmlStreamWriter& writer) const } } -std::optional UBBackgroundRuling::Border::left() const +std::optional UBBackgroundRuling::Limit::from() const { - return mLeft; + return mFrom; } -std::optional UBBackgroundRuling::Border::right() const +std::optional UBBackgroundRuling::Limit::to() const { - return mRight; + return mTo; } -const QList& UBBackgroundRuling::Border::lines() const +const QList& UBBackgroundRuling::Limit::lines() const { return mLines; } @@ -801,9 +859,13 @@ UBBackgroundRuling::Linegroup::Linegroup(const Rules& rules, QXmlStreamReader& r mLines.append(bgLine); } } - else if (reader.name().toString() == elementBorder) + else if (reader.name().toString() == elementStretch) { - mBorder.emplace(rules, reader); + mStretch.emplace(rules, reader); + } + else if (reader.name().toString() == elementStack) + { + mStack.emplace(rules, reader); } else { @@ -851,10 +913,17 @@ void UBBackgroundRuling::Linegroup::toXml(QXmlStreamWriter& writer) const writer.writeEndElement(); } - if (mBorder) + if (mStretch) { - writer.writeStartElement(namespaceURI, elementBorder); - mBorder.value().toXml(writer); + writer.writeStartElement(namespaceURI, elementStretch); + mStretch.value().toXml(writer); + writer.writeEndElement(); + } + + if (mStack) + { + writer.writeStartElement(namespaceURI, elementStack); + mStack.value().toXml(writer); writer.writeEndElement(); } } @@ -879,9 +948,14 @@ const QList& UBBackgroundRuling::Linegroup::lines() co return mLines; } -std::optional UBBackgroundRuling::Linegroup::border() const +std::optional UBBackgroundRuling::Linegroup::stretch() const +{ + return mStretch; +} + +std::optional UBBackgroundRuling::Linegroup::stack() const { - return mBorder; + return mStack; } UBBackgroundRuling::Rules::Rules(QXmlStreamReader& reader) diff --git a/src/gui/UBBackgroundRuling.h b/src/gui/UBBackgroundRuling.h index 6586eba37..f61da6e7f 100644 --- a/src/gui/UBBackgroundRuling.h +++ b/src/gui/UBBackgroundRuling.h @@ -60,7 +60,7 @@ class UBBackgroundRuling class Line; // forward void setLinePainter(QPainter* painter, const Line& line, bool onDark, QColor defaultOnDark, QColor defaultOnLight) const; - void drawBorderLines(QPainter* painter, const QList& borderLines, QLineF line, Qt::Edge edge, double gridSize, + void drawBorderLines(QPainter* painter, const QList& borderLines, QLineF line, Qt::Edge edge, double dotsPerMm, bool onDark, QColor defaultOnDark, QColor defaultOnLight) const; private: @@ -117,20 +117,20 @@ class UBBackgroundRuling LineColor mColor; }; - class Border : public Data + class Limit : public Data { public: - Border(const Rules& rules, QXmlStreamReader& reader); + Limit(const Rules& rules, QXmlStreamReader& reader); virtual void toXml(QXmlStreamWriter& writer) const override; - std::optional left() const; - std::optional right() const; + std::optional from() const; + std::optional to() const; const QList& lines() const; private: - std::optional mLeft{}; - std::optional mRight{}; + std::optional mFrom{}; + std::optional mTo{}; QList mLines{}; }; @@ -154,14 +154,16 @@ class UBBackgroundRuling double spacing() const; Origin origin() const; const QList& lines() const; - std::optional border() const; + std::optional stretch() const; + std::optional stack() const; private: double mAngle{0.}; double mSpacing{0.}; Origin mOrigin{Origin::Center}; QList mLines{}; - std::optional mBorder{}; + std::optional mStretch{}; + std::optional mStack{}; }; class Rules : public Data From 4c355ce798340827867bd3f112a5cdba9baaf023 Mon Sep 17 00:00:00 2001 From: sebojolais Date: Sun, 25 Feb 2024 17:27:50 +0100 Subject: [PATCH 092/133] Fixes the Seyes pattern. --- resources/etc/background/05_seyes.xml | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/resources/etc/background/05_seyes.xml b/resources/etc/background/05_seyes.xml index 9dd1549de..8109fcd7d 100644 --- a/resources/etc/background/05_seyes.xml +++ b/resources/etc/background/05_seyes.xml @@ -37,50 +37,33 @@ #996fa8dc - - 50 - 0 - - - 0 - 0 - 90 20 topleft - 0 + 20 2 #8e7cc3 #8e7cc3 - - 0 - 50 - - 0 - 0 + -20 90 topleft - 0 + 20 2 #ff0000 #ff0000 - - 0 - 50 - From e32272c81bac07fdf6654e6e4a8ac13ef2b12bd3 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 25 Feb 2024 18:07:40 +0100 Subject: [PATCH 093/133] fix: topmost line group was not painted - the topmost line group was not painted in some cases - re-introduce a decrement lost in previous rework --- src/gui/UBBackgroundRuling.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/UBBackgroundRuling.cpp b/src/gui/UBBackgroundRuling.cpp index 903d26e4a..2b70516a6 100644 --- a/src/gui/UBBackgroundRuling.cpp +++ b/src/gui/UBBackgroundRuling.cpp @@ -486,6 +486,8 @@ void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double grid { std::swap(minIndex, maxIndex); } + + --minIndex; } const auto distFrom = distance(originLine, stackFrom); From 16c258a305819ce8bd7516044bc5273a8625c91c Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 26 Feb 2024 07:46:45 +0100 Subject: [PATCH 094/133] fix: unintentional change of background color - fixed regression - initialization of the black scene caused unintentional switch to dark background during startup --- src/domain/UBGraphicsScene.cpp | 2 -- src/gui/UBBackgroundPalette.cpp | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/domain/UBGraphicsScene.cpp b/src/domain/UBGraphicsScene.cpp index 5c49b5b15..b6df4c82d 100644 --- a/src/domain/UBGraphicsScene.cpp +++ b/src/domain/UBGraphicsScene.cpp @@ -1158,14 +1158,12 @@ void UBGraphicsScene::setSceneBackground(bool pIsDark, const UBBackgroundRuling updatePenCircleColor(); recolorAllItems(); - UBSettings::settings()->setDarkBackground(mDarkBackground); needRepaint = true; } if (mBackground != background) { mBackground = background; - UBSettings::settings()->setPageBackgroundUuid(mBackground ? mBackground->uuid() : QUuid{}); needRepaint = true; } diff --git a/src/gui/UBBackgroundPalette.cpp b/src/gui/UBBackgroundPalette.cpp index 9395795fc..0bfd7d63f 100644 --- a/src/gui/UBBackgroundPalette.cpp +++ b/src/gui/UBBackgroundPalette.cpp @@ -235,7 +235,7 @@ void UBBackgroundPalette::defaultBackgroundGridSize() void UBBackgroundPalette::toggleBackgroundColor(bool checked) { mIsDark = checked; - UBApplication::boardController->activeScene()->setSceneBackground(mIsDark, mBackground); + UBApplication::boardController->setBackground(mIsDark, mBackground); backgroundChanged(); } @@ -249,7 +249,7 @@ void UBBackgroundPalette::changeBackground(bool checked) { const auto uuid = action->property("uuid").toUuid(); mBackground = UBApplication::boardController->backgroundManager()->background(uuid); - UBApplication::boardController->activeScene()->setSceneBackground(mIsDark, mBackground); + UBApplication::boardController->setBackground(mIsDark, mBackground); } } } From 8107228ecdc23767d02ab2413edf322ecf4f0160 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 26 Feb 2024 08:02:43 +0100 Subject: [PATCH 095/133] feat: add two more ruling definitions - ruled with border - crossed with border --- resources/etc/background/crossed5Border.xml | 52 +++++++++++++++++++++ resources/etc/background/ruledBorder.xml | 25 ++++++++++ 2 files changed, 77 insertions(+) create mode 100644 resources/etc/background/crossed5Border.xml create mode 100644 resources/etc/background/ruledBorder.xml diff --git a/resources/etc/background/crossed5Border.xml b/resources/etc/background/crossed5Border.xml new file mode 100644 index 000000000..b1e009826 --- /dev/null +++ b/resources/etc/background/crossed5Border.xml @@ -0,0 +1,52 @@ + + 9057d897-bbfe-4764-9867-1c75ad4da2e3 + Crossed 5mm with border + Kariert 5mm mit Rand + + + 0 + 10 + + 0 + 1 + + + 5 + 1 + + 0.5 + 0.5 + + + + -30 + + + + 90 + 10 + + 0 + 1 + + + 5 + 1 + + 0.5 + 0.5 + + + + -30 + + + + 90 + topleft + + 30 + 1 + + + diff --git a/resources/etc/background/ruledBorder.xml b/resources/etc/background/ruledBorder.xml new file mode 100644 index 000000000..c1021972a --- /dev/null +++ b/resources/etc/background/ruledBorder.xml @@ -0,0 +1,25 @@ + + c155edf1-bb46-4f4c-a665-a5800eeed465 + Ruled with border + Liniert mit Rand + + + 0 + 10 + + 0 + 1 + + + -30 + + + + 90 + topleft + + 30 + 1 + + + From b5b2368c00cc3b67ce9d443d0258bc971216f6ce Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 9 Sep 2024 11:37:10 +0200 Subject: [PATCH 096/133] feat: snap to grid for flexible backgrounds - move the snap function from UBGraphicsScene to UBBackgroundRuling - calculate snap points based on ruling description - factor out common code with background drawing --- src/domain/UBGraphicsScene.cpp | 52 +---------- src/gui/UBBackgroundRuling.cpp | 166 +++++++++++++++++++++++++++++---- src/gui/UBBackgroundRuling.h | 14 ++- 3 files changed, 163 insertions(+), 69 deletions(-) diff --git a/src/domain/UBGraphicsScene.cpp b/src/domain/UBGraphicsScene.cpp index b6df4c82d..523c7f0af 100644 --- a/src/domain/UBGraphicsScene.cpp +++ b/src/domain/UBGraphicsScene.cpp @@ -2480,56 +2480,14 @@ bool UBGraphicsScene::isSnapping() const QPointF UBGraphicsScene::snap(const QPointF& point, double* force, std::optional proposedPoint, QPointF* gridSnapPoint) const { - QPointF snapPoint{point}; - double snapForce{0}; - double gridSize = backgroundGridSize(); - - if (mIntermediateLines) - { - gridSize /= 2.; - } - - // y axis - double floorY = std::floor(point.y () / gridSize) * gridSize; - snapPoint.setY(point.y() - floorY < gridSize / 2. ? floorY : floorY + gridSize); - - // for blank background, use same snapping as for grid - if (mPageBackground == UBPageBackground::crossed || mPageBackground == UBPageBackground::plain) - { - // x axis - double floorX = std::floor(point.x () / gridSize) * gridSize; - snapPoint.setX(point.x() - floorX < gridSize / 2. ? floorX : floorX + gridSize); - } - - // force is a number between 0 and 1 based on the manhattan distance of the snap point - // from the original point - double relativeDist = (snapPoint - point).manhattanLength() / gridSize; - snapForce = std::max(1. - relativeDist, 0.); - - if (gridSnapPoint) - { - *gridSnapPoint = snapPoint; - } - - if (proposedPoint) - { - // compute force for proposed point and take that if it has higher force - double relativeDist = (proposedPoint.value() - point).manhattanLength() / gridSize; - double proposedForce = std::max(1. - relativeDist, 0.); - - if (proposedForce > snapForce) - { - snapForce = proposedForce; - snapPoint = proposedPoint.value(); - } - } - - if (force) + if (!mBackground) { - *force = snapForce; + return {}; } - return snapPoint - point; + QRectF nominalScene{{0, 0}, mNominalSize}; + nominalScene.moveCenter({0, 0}); + return mBackground->snap(point, backgroundGridSize(), nominalScene, force, proposedPoint, gridSnapPoint); } QPointF UBGraphicsScene::snap(const std::vector& corners, int* snapIndex) const diff --git a/src/gui/UBBackgroundRuling.cpp b/src/gui/UBBackgroundRuling.cpp index 2b70516a6..4ba451322 100644 --- a/src/gui/UBBackgroundRuling.cpp +++ b/src/gui/UBBackgroundRuling.cpp @@ -322,6 +322,147 @@ void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double grid return; } + const auto dotsPerMm = gridSize / 10; + const QColor defaultOnDark{UBSettings::settings()->boardCrossColorDarkBackground->get().toString()}; + const QColor defaultOnLight{UBSettings::settings()->boardCrossColorLightBackground->get().toString()}; + painter->setRenderHint(QPainter::Antialiasing, true); + + auto paintGridLine = [this, painter, rect, onDark, defaultOnDark, defaultOnLight](Line line, QLineF gridLine){ + if (clip(rect, gridLine)) + { + setLinePainter(painter, line, onDark, defaultOnDark, defaultOnLight); + painter->drawLine(gridLine); + } + }; + + auto paintBorderLine = [this, painter, dotsPerMm, onDark, defaultOnDark, defaultOnLight](const QList& borderLines, QLineF line, Qt::Edge edge){ + drawBorderLines(painter, borderLines, line, edge, dotsPerMm, onDark, defaultOnDark, defaultOnLight); + }; + + determineGridLines(rect, gridSize, nominalScene, paintGridLine, paintBorderLine); +} + +QPointF UBBackgroundRuling::snap(const QPointF& point, double gridSize, const QRectF& nominalScene, double* force, std::optional proposedPoint, + QPointF* gridSnapPoint) const +{ + // algorithm: + // - determine the lines within one grid size around the point + // - if we have only one line group, snap orthogonally to the closest line + // - if we have more than one line group, compute all intersections of the lines + // - snap to the closest intersection + + QRectF rect{0, 0, 2 * gridSize, 2 * gridSize}; + rect.moveCenter(point); + QList lines; + determineGridLines(rect, gridSize, nominalScene, [&lines](const Line& line, QLineF gridLine){ + lines << gridLine; + }); + + if (lines.empty()) + { + return {}; + } + + QPointF snapPoint{point}; + bool haveSnapPoint{false}; + + if (mRules->linegroups().size() == 1) + { + // snap to closest line + std::vector distances; + distances.reserve(lines.size()); + + for (const auto& line : lines) + { + distances.push_back(std::fabs(distance(line, point))); + } + + const auto minElement = std::min_element(distances.cbegin(), distances.cend()); + const auto index = std::distance(distances.cbegin(), minElement); + + // now compute the base point of the normal vector + QLineF gridLine = lines.at(index); + QLineF normal = gridLine.normalVector(); + normal.translate(point - normal.p1()); + gridLine.intersects(normal, &snapPoint); + haveSnapPoint = true; + } + else + { + // we have multiple line groups; calculate all intersections + QList intersections; + + for (int i = 0; i < lines.size() - 1; ++i) + { + for (int j = i + 1; j < lines.size(); ++j) + { + QPointF intersection; + + if (lines.at(i).intersects(lines.at(j), &intersection) == QLineF::BoundedIntersection) + { + intersections << intersection; + } + } + } + + if (!intersections.isEmpty()) + { + // find the closest intersection + std::vector distances; + distances.reserve(intersections.size()); + + for (const auto& intersection : intersections) + { + distances.push_back(QLineF(point, intersection).length()); + } + + const auto closestIntersection = std::min_element(distances.cbegin(), distances.cend()); + const auto index = std::distance(distances.cbegin(), closestIntersection); + snapPoint = intersections.at(index); + haveSnapPoint = true; + } + } + + if (haveSnapPoint && gridSnapPoint) + { + *gridSnapPoint = snapPoint; + } + + // force is a number between 0 and 1 based on the manhattan distance of the snap point + // from the original point + const double relativeDist = (snapPoint - point).manhattanLength() / gridSize; + double snapForce = haveSnapPoint ? std::max(1. - relativeDist, 0.) : 0; + + if (proposedPoint) + { + // compute force for proposed point and take that if it has higher force + const double relativeDist = (proposedPoint.value() - point).manhattanLength() / gridSize; + double proposedForce = std::max(1. - relativeDist, 0.); + + if (proposedForce > snapForce) + { + snapForce = proposedForce; + snapPoint = proposedPoint.value(); + } + } + + if (force) + { + *force = snapForce; + } + + return snapPoint - point; +} + +void UBBackgroundRuling::determineGridLines(const QRectF& rect, double gridSize, const QRectF& nominalScene, + std::function handleGridLine, + std::function&, QLineF, Qt::Edge)> handleBorder) const +{ + if (!mRules) + { + return; + } + if (gridSize == 0) { // guess reasonable grid size for buttons @@ -344,10 +485,6 @@ void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double grid const auto dotsPerMm = gridSize / 10; - painter->setRenderHint(QPainter::Antialiasing, true); - const QColor defaultOnDark{UBSettings::settings()->boardCrossColorDarkBackground->get().toString()}; - const QColor defaultOnLight{UBSettings::settings()->boardCrossColorLightBackground->get().toString()}; - // loop through line groups for (const auto& linegroup : mRules->linegroups()) { @@ -511,8 +648,6 @@ void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double grid const auto offset = line.offset() * dotsPerMm; const auto offsetShift = (normal.p1() - normal.p2()) / normal.length() * offset; - setLinePainter(painter, line, onDark, defaultOnDark, defaultOnLight); - auto gridLine = originLine.translated(index * spaceShift + offsetShift); if (hasFromStretch) @@ -527,15 +662,14 @@ void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double grid shift.setLength(-fromStretch); gridLine.setP1(shift.p2()); - if (&line == &linegroup.lines().last()) + if (handleBorder && &line == &linegroup.lines().last()) { // draw border lines on "from" side QLineF borderLine{gridLine.p1() - offsetShift, gridLine.p1()}; if (clip(rect, borderLine)) { - drawBorderLines(painter, borderLines, borderLine, Qt::LeftEdge, dotsPerMm, onDark, - defaultOnDark, defaultOnLight); + handleBorder(borderLines, borderLine, Qt::LeftEdge); } } } @@ -552,30 +686,26 @@ void UBBackgroundRuling::draw(QPainter* painter, const QRectF& rect, double grid shift.setLength(toStretch); gridLine.setP2(shift.p2()); - if (&line == &linegroup.lines().last()) + if (handleBorder && &line == &linegroup.lines().last()) { // draw border lines on "to" side QLineF borderLine{gridLine.p2() - offsetShift, gridLine.p2()}; if (clip(rect, borderLine)) { - drawBorderLines(painter, borderLines, borderLine, Qt::RightEdge, dotsPerMm, onDark, - defaultOnDark, defaultOnLight); + handleBorder(borderLines, borderLine, Qt::RightEdge); } } } - if (clip(rect, gridLine)) - { - painter->drawLine(gridLine); - } + handleGridLine(line, gridLine); } } } } void UBBackgroundRuling::setLinePainter(QPainter* painter, const Line& line, bool onDark, QColor defaultOnDark, - QColor defaultOnLight) const + QColor defaultOnLight) { const auto colorOnDark = line.color().onDark(); const auto colorOnLight = line.color().onLight(); @@ -594,7 +724,7 @@ void UBBackgroundRuling::setLinePainter(QPainter* painter, const Line& line, boo void UBBackgroundRuling::drawBorderLines(QPainter* painter, const QList& borderLines, QLineF line, Qt::Edge edge, double dotsPerMm, bool onDark, QColor defaultOnDark, - QColor defaultOnLight) const + QColor defaultOnLight) { painter->save(); diff --git a/src/gui/UBBackgroundRuling.h b/src/gui/UBBackgroundRuling.h index f61da6e7f..7a26e49fb 100644 --- a/src/gui/UBBackgroundRuling.h +++ b/src/gui/UBBackgroundRuling.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -55,13 +56,18 @@ class UBBackgroundRuling bool isUserProvided() const; void draw(QPainter* painter, const QRectF& rect, double gridSize, const QRectF& nominalScene, bool onDark) const; + QPointF snap(const QPointF& point, double gridSize, const QRectF& nominalScene, double* force = nullptr, + std::optional proposedPoint = {}, QPointF* gridSnapPoint = nullptr) const; private: class Line; // forward - void setLinePainter(QPainter* painter, const Line& line, bool onDark, QColor defaultOnDark, - QColor defaultOnLight) const; - void drawBorderLines(QPainter* painter, const QList& borderLines, QLineF line, Qt::Edge edge, double dotsPerMm, - bool onDark, QColor defaultOnDark, QColor defaultOnLight) const; + void determineGridLines(const QRectF& rect, double gridSize, const QRectF& nominalScene, + std::function handleGridLine = nullptr, + std::function&, QLineF, Qt::Edge)> handleBorder = nullptr) const; + static void setLinePainter(QPainter* painter, const Line& line, bool onDark, QColor defaultOnDark, + QColor defaultOnLight); + static void drawBorderLines(QPainter* painter, const QList& borderLines, QLineF line, Qt::Edge edge, double dotsPerMm, + bool onDark, QColor defaultOnDark, QColor defaultOnLight); private: // data classes From 4f10c07a3c400ad54f9837de7d407635bd86df08 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Tue, 2 Dec 2025 15:41:21 +0100 Subject: [PATCH 097/133] refactor: avoid deprecation warnings - use std::as_const instead of qAsConst - use event->position or event->pos depending on Qt version Signed-off-by: letsfindaway --- src/gui/UBBackgroundManager.cpp | 4 ++-- src/gui/UBFlowLayout.cpp | 4 ++-- src/gui/UBPreferredBackgroundWidget.cpp | 17 ++++++++++++++--- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/gui/UBBackgroundManager.cpp b/src/gui/UBBackgroundManager.cpp index ded74c79d..7e32abeb4 100644 --- a/src/gui/UBBackgroundManager.cpp +++ b/src/gui/UBBackgroundManager.cpp @@ -154,7 +154,7 @@ void UBBackgroundManager::updateAction(QAction *action, bool dark) const const UBBackgroundRuling* UBBackgroundManager::background(const QUuid &uuid) const { - for (auto& background : qAsConst(mBackgrounds)) + for (auto& background : std::as_const(mBackgrounds)) { if (background.uuid() == uuid) { @@ -167,7 +167,7 @@ const UBBackgroundRuling* UBBackgroundManager::background(const QUuid &uuid) con const UBBackgroundRuling* UBBackgroundManager::guessBackground(bool crossed, bool ruled, bool intermediateLines) const { - for (auto& background : qAsConst(mBackgrounds)) + for (auto& background : std::as_const(mBackgrounds)) { if (background.isCrossed() == crossed && background.isRuled() == ruled diff --git a/src/gui/UBFlowLayout.cpp b/src/gui/UBFlowLayout.cpp index 4876d8791..b896be257 100644 --- a/src/gui/UBFlowLayout.cpp +++ b/src/gui/UBFlowLayout.cpp @@ -156,7 +156,7 @@ QSize UBFlowLayout::minimumSize() const { QSize size; - for (const auto item : qAsConst(mItemList)) + for (const auto item : std::as_const(mItemList)) { size = size.expandedTo(item->minimumSize()); } @@ -175,7 +175,7 @@ int UBFlowLayout::doLayout(const QRect& rect, bool testOnly) const auto y = effectiveRect.y(); int lineHeight = 0; - for (auto item : qAsConst(mItemList)) + for (auto item : std::as_const(mItemList)) { const auto wid = item->widget(); auto spaceX = horizontalSpacing(); diff --git a/src/gui/UBPreferredBackgroundWidget.cpp b/src/gui/UBPreferredBackgroundWidget.cpp index fdc2366a9..8e29e714d 100644 --- a/src/gui/UBPreferredBackgroundWidget.cpp +++ b/src/gui/UBPreferredBackgroundWidget.cpp @@ -75,16 +75,21 @@ void UBPreferredBackgroundWidget::dragEnterEvent(QDragEnterEvent* event) void UBPreferredBackgroundWidget::dragMoveEvent(QDragMoveEvent* event) { +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + const auto p = event->position().toPoint(); +#else + const auto p = event->pos(); +#endif + // auto-scroll if widget is in a scroll area auto scrollArea = dynamic_cast(parentWidget()->parentWidget()); if (scrollArea) { - const auto p = event->pos(); scrollArea->ensureVisible(p.x(), p.y(), 15); } - auto child = childAt(event->pos()); + auto child = childAt(p); // walk up to a direct child while (child && child->parentWidget() != this) @@ -117,7 +122,13 @@ void UBPreferredBackgroundWidget::dragMoveEvent(QDragMoveEvent* event) void UBPreferredBackgroundWidget::dropEvent(QDropEvent* event) { - auto child = childAt(event->pos()); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + const auto p = event->position().toPoint(); +#else + const auto p = event->pos(); +#endif + + auto child = childAt(p); // is the child the trash? if (child == mTrash) From 7e9b3edc493751f3570a172b604c2da6eacc4f15 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Thu, 4 Dec 2025 16:43:04 +0100 Subject: [PATCH 098/133] feat: show all backgrounds in background palette - use a scroll area to show the backgrounds - adjust size of palette so that second row is already visible - remove blue background for first 6 pattern in preferences - rearranging of patterns is still only possible in the preferences Signed-off-by: letsfindaway --- src/gui/UBBackgroundPalette.cpp | 34 ++++++++++++++++++++----- src/gui/UBBackgroundPalette.h | 4 ++- src/gui/UBPreferredBackgroundWidget.cpp | 18 +------------ src/gui/UBPreferredBackgroundWidget.h | 1 - 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/gui/UBBackgroundPalette.cpp b/src/gui/UBBackgroundPalette.cpp index 0bfd7d63f..ca64548f0 100644 --- a/src/gui/UBBackgroundPalette.cpp +++ b/src/gui/UBBackgroundPalette.cpp @@ -1,6 +1,7 @@ #include "UBBackgroundPalette.h" #include "gui/UBBackgroundManager.h" +#include "gui/UBFlowLayout.h" #include "gui/UBMainWindow.h" UBBackgroundPalette::UBBackgroundPalette(QWidget * parent) @@ -18,7 +19,6 @@ void UBBackgroundPalette::init() UBActionPalette::clearLayout(); delete layout(); - m_customCloseProcessing = false; mButtonSize = QSize(32, 32); @@ -28,10 +28,20 @@ void UBBackgroundPalette::init() mButtons.clear(); mVLayout = new QVBoxLayout(this); - mTopLayout = new QHBoxLayout(); + mTopLayout = new UBFlowLayout{0, 0, 0}; + mTopLayout->setSizeConstraint(QLayout::SetMaximumSize); mBottomLayout = new QHBoxLayout(); - mVLayout->addLayout(mTopLayout); + mButtonScrollArea = new QScrollArea{this}; + mButtonScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + mButtonScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + mButtonScrollArea->setWidgetResizable(true); + + QWidget* bgWidget = new QWidget{mButtonScrollArea}; + bgWidget->setLayout(mTopLayout); + mButtonScrollArea->setWidget(bgWidget); + + mVLayout->addWidget(mButtonScrollArea); mVLayout->addLayout(mBottomLayout); mSlider = new QSlider(Qt::Horizontal); @@ -69,7 +79,7 @@ void UBBackgroundPalette::init() mBottomLayout->addWidget(mLightDarkModeSwitch); mBottomLayout->addSpacing(16); - updateLayout(); + UBBackgroundPalette::updateLayout(); } void UBBackgroundPalette::createActions() @@ -89,12 +99,12 @@ void UBBackgroundPalette::createActions() delete action; } - // then add actions for the first 6 backgrounds from the background manager + // then add actions for the backgrounds from the background manager const QList backgrounds = UBApplication::boardController->backgroundManager()->backgrounds(); - const auto dark = false; //UBApplication::boardController->activeScene()->isDarkBackground(); + const auto dark = false; // starting value, updated later with updateActions() const auto bgManager = UBApplication::boardController->backgroundManager(); - for (int i = 0; i < backgrounds.size() && i < 6; ++i) + for (int i = 0; i < backgrounds.size(); ++i) { const auto background = backgrounds.at(i); auto action = bgManager->backgroundAction(*background, dark); @@ -143,6 +153,16 @@ void UBBackgroundPalette::addAction(QAction* action) mTopLayout->addWidget(button); mActions << action; + + const auto size = action->icon().availableSizes().at(0); + + if (mButtonScrollArea->height() < size.height()) + { + // make part of the second row visible + mButtonScrollArea->setFixedHeight(size.height() * 3 / 2); + // account for the width of the scrollbar + mButtonScrollArea->setFixedWidth(6 * size.width() + 40); + } } void UBBackgroundPalette::setActions(QList actions) diff --git a/src/gui/UBBackgroundPalette.h b/src/gui/UBBackgroundPalette.h index 41d219202..7a56851b5 100644 --- a/src/gui/UBBackgroundPalette.h +++ b/src/gui/UBBackgroundPalette.h @@ -8,6 +8,7 @@ // forward class UBBackgroundManager; +class UBFlowLayout; class UBBackgroundPalette : public UBActionPalette { @@ -40,8 +41,9 @@ class UBBackgroundPalette : public UBActionPalette private: QVBoxLayout* mVLayout; - QHBoxLayout* mTopLayout; + UBFlowLayout* mTopLayout; QHBoxLayout* mBottomLayout; + QScrollArea* mButtonScrollArea; QSlider* mSlider; QLabel* mSliderLabel; diff --git a/src/gui/UBPreferredBackgroundWidget.cpp b/src/gui/UBPreferredBackgroundWidget.cpp index 8e29e714d..f8fb82b6a 100644 --- a/src/gui/UBPreferredBackgroundWidget.cpp +++ b/src/gui/UBPreferredBackgroundWidget.cpp @@ -61,7 +61,6 @@ UBPreferredBackgroundWidget::UBPreferredBackgroundWidget(QWidget* parent) mTrash->setVisible(false); updateBackgroundButtons(); - updateStyle(); connect(UBApplication::boardController->backgroundManager(), &UBBackgroundManager::backgroundListChanged, this, &UBPreferredBackgroundWidget::updateBackgroundButtons); @@ -116,7 +115,7 @@ void UBPreferredBackgroundWidget::dragMoveEvent(QDragMoveEvent* event) { auto plItem = mLayout->takeAt(pl); mLayout->insertItem(ix, plItem); - updateStyle(); + mLayout->update(); } } @@ -174,7 +173,6 @@ void UBPreferredBackgroundWidget::dropEvent(QDropEvent* event) mLayout->removeWidget(mPlaceholder); mPlaceholder->setVisible(false); mTrash->setVisible(false); - updateStyle(); event->acceptProposedAction(); } @@ -244,20 +242,6 @@ void UBPreferredBackgroundWidget::mousePressEvent(QMouseEvent* event) } } -void UBPreferredBackgroundWidget::updateStyle() const -{ - for (int i = 0; i < mLayout->count(); ++i) - { - auto widget = mLayout->itemAt(i)->widget(); - auto icon = widget->findChild("backgroundIcon"); - - if (icon) - { - icon->setStyleSheet(i < 6 ? "background-color: #bbddff" : ""); - } - } -} - void UBPreferredBackgroundWidget::savePreferrdBackgrounds() const { QList uuidList; diff --git a/src/gui/UBPreferredBackgroundWidget.h b/src/gui/UBPreferredBackgroundWidget.h index e69f02608..69cb38561 100644 --- a/src/gui/UBPreferredBackgroundWidget.h +++ b/src/gui/UBPreferredBackgroundWidget.h @@ -44,7 +44,6 @@ class UBPreferredBackgroundWidget : public QWidget void mousePressEvent(QMouseEvent* event) override; private: - void updateStyle() const; void savePreferrdBackgrounds() const; private slots: From c7c5e15d9b5882d1882107ece076195e3c38e1ce Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Sun, 25 Aug 2024 15:34:04 +0200 Subject: [PATCH 099/133] feat: add preferences dialog for shortcut configuration - recording of key sequences amd mouse/stylus buttons - collect actions, filtering, collision detection - persist shortcut settings --- resources/forms/preferences.ui | 169 ++++++++++++++++++ src/core/UBApplication.cpp | 28 +++ src/core/UBPreferencesController.cpp | 252 ++++++++++++++++++++++++++- src/core/UBPreferencesController.h | 12 ++ 4 files changed, 459 insertions(+), 2 deletions(-) diff --git a/resources/forms/preferences.ui b/resources/forms/preferences.ui index 45a2fc180..9b73f8d65 100644 --- a/resources/forms/preferences.ui +++ b/resources/forms/preferences.ui @@ -1095,6 +1095,175 @@
+ + + Shortcut + + + + + + Filter + + + + + + + true + + + + + 0 + 0 + 789 + 447 + + + + + + + QAbstractItemView::NoEditTriggers + + + false + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + false + + + true + + + false + + + 25 + + + 25 + + + + + + + + + + + + + Active keyboard shortcuts without pressing Ctrl key + + + + + + + + + false + + + Shortcuts + + + Qt::AlignCenter + + + + + + color: red; + + + Qt::PlainText + + + + + + + true + + + + + + + Abort + + + + + + + Record + + + true + + + + + + + Stylus Button + + + + + + + Mouse Button + + + + + + + true + + + + + + + true + + + + + + + Reset + + + + + + + Key Sequence + + + + + + + + true diff --git a/src/core/UBApplication.cpp b/src/core/UBApplication.cpp index 640fad511..7b1d8d7b0 100644 --- a/src/core/UBApplication.cpp +++ b/src/core/UBApplication.cpp @@ -713,6 +713,34 @@ bool UBApplication::eventFilter(QObject *obj, QEvent *event) || result; } + else if (event->type() == QEvent::MouseButtonPress) + { + // intercept special mouse buttons for shortcut handler + QMouseEvent *mouseEvent = static_cast(event); + Qt::MouseButton button = mouseEvent->button(); + + if (button != Qt::LeftButton && button != Qt::RightButton) + { + return mPreferencesController->handleMouseEvent(mouseEvent) + || UBShortcutManager::shortcutManager()->handleMouseEvent(mouseEvent) + || result; + } + } + + else if (event->type() == QEvent::TabletPress) + { + // intercept special tablet buttons for shortcut handler + QTabletEvent *tabletEvent = static_cast(event); + Qt::MouseButton button = tabletEvent->button(); + + if (button != Qt::LeftButton) + { + return mPreferencesController->handleTabletEvent(tabletEvent) + || UBShortcutManager::shortcutManager()->handleTabletEvent(tabletEvent) + || result; + } + } + return result; } diff --git a/src/core/UBPreferencesController.cpp b/src/core/UBPreferencesController.cpp index ed0e393d8..145323385 100644 --- a/src/core/UBPreferencesController.cpp +++ b/src/core/UBPreferencesController.cpp @@ -37,6 +37,7 @@ #include "core/UBSetting.h" #include "core/UBApplicationController.h" #include "core/UBDisplayManager.h" +#include "core/UBShortcutManager.h" #include "frameworks/UBStringUtils.h" @@ -72,7 +73,6 @@ void UBPreferencesDialog::closeEvent(QCloseEvent* e) } - UBPreferencesController::UBPreferencesController(QWidget *parent) : QObject(parent) , mPreferencesWindow(0) @@ -88,6 +88,8 @@ UBPreferencesController::UBPreferencesController(QWidget *parent) adjustScreensPreferences(); connect(UBApplication::displayManager, &UBDisplayManager::availableScreenCountChanged, this, &UBPreferencesController::adjustScreensPreferences); + mPreferencesUI->shortcutTab->installEventFilter(this); + wire(); } @@ -103,6 +105,90 @@ UBPreferencesController::~UBPreferencesController() delete mMarkerProperties; } +bool UBPreferencesController::handleKeyEvent(QKeyEvent *event) +{ + if (!mPreferencesUI->recordButton->isChecked() + || mPreferencesUI->mainTabWidget->currentWidget() != mPreferencesUI->shortcutTab) + { + return false; + } + + int key = event->key(); + Qt::KeyboardModifiers mods = event->modifiers(); + QString text = event->text(); + + int keys = mods; + + if (key < Qt::Key_Shift || key > Qt::Key_ScrollLock) + { + keys += key; + } + + // compose key sequence from active modifiers and key + QKeySequence keySequence(keys); + QString keyString = keySequence.toString(); + mPreferencesUI->keySequence->setText(keyString); + + if (currentIndex.isValid()) + { + bool ok = UBShortcutManager::shortcutManager()->checkData(currentIndex.siblingAtColumn(2), keyString); + applyShortcutFilter(ok ? mPreferencesUI->filter->text() : keyString, ok ? -1 : 2); + mPreferencesUI->recordButton->setEnabled(ok); + mPreferencesUI->report->setText(ok ? "" : tr("Key sequence already in use")); + mPreferencesUI->noCtrl->setEnabled(!UBShortcutManager::shortcutManager()->hasCtrlConflicts(keySequence)); + } + + return true; +} + +bool UBPreferencesController::handleMouseEvent(QMouseEvent *event) +{ + if (!mPreferencesUI->recordButton->isChecked() + || mPreferencesUI->mainTabWidget->currentWidget() != mPreferencesUI->shortcutTab) + { + return false; + } + + Qt::MouseButton button = event->button(); + + if (currentIndex.isValid()) + { + QString buttonName = UBShortcutManager::buttonName(button); + mPreferencesUI->mouseButton->setText(buttonName); + bool ok = UBShortcutManager::shortcutManager()->checkData(currentIndex.siblingAtColumn(3), buttonName); + applyShortcutFilter(ok ? mPreferencesUI->filter->text() : buttonName, ok ? -1 : 3); + mPreferencesUI->recordButton->setEnabled(ok); + mPreferencesUI->report->setText(ok ? "" : tr("Mouse button already in use")); + return true; + } + + return false; +} + +bool UBPreferencesController::handleTabletEvent(QTabletEvent *event) +{ + if (!mPreferencesUI->recordButton->isChecked() + || mPreferencesUI->mainTabWidget->currentWidget() != mPreferencesUI->shortcutTab) + { + return false; + } + + Qt::MouseButton button = event->button(); + + if (currentIndex.isValid()) + { + QString buttonName = UBShortcutManager::buttonName(button); + mPreferencesUI->stylusButton->setText(buttonName); + bool ok = UBShortcutManager::shortcutManager()->checkData(currentIndex.siblingAtColumn(4), buttonName); + applyShortcutFilter(ok ? mPreferencesUI->filter->text() : buttonName, ok ? -1 : 4); + mPreferencesUI->recordButton->setEnabled(ok); + mPreferencesUI->report->setText(ok ? "" : tr("Stylus button already in use")); + return true; + } + + return false; +} + void UBPreferencesController::adjustScreensPreferences() { bool enabled = UBApplication::displayManager->numScreens() > 1; @@ -139,6 +225,50 @@ void UBPreferencesController::adjustScreensPreferences() } } +void UBPreferencesController::applyShortcutFilter(const QString &filter, int filterCol) +{ + // go throug rows in reverse direction + QAbstractItemModel* model = mPreferencesUI->shortcutTableView->model(); + QModelIndex index = model->index(0, 0); + bool groupVisible = false; + int minCol = filterCol < 0 ? 0 : filterCol; + int maxCol = filterCol < 0 ? model->columnCount() : filterCol + 1; + + for (int row = model->rowCount() - 1; row >= 0; --row) + { + QModelIndex rowIndex = index.siblingAtRow(row); + bool match = false; + bool header = model->data(rowIndex, UBShortcutManager::GroupHeaderRole).toBool(); + + if (header) + { + match = groupVisible; + groupVisible = false; + } + else if (currentIndex.isValid() && currentIndex.row() == row) + { + match = true; + groupVisible = true; + } + else + { + for (int col = minCol; col < maxCol; ++col) + { + QModelIndex colIndex = rowIndex.siblingAtColumn(col); + + if (model->data(colIndex).toString().contains(filter, Qt::CaseInsensitive)) + { + match = true; + groupVisible = true; + break; + } + } + } + + mPreferencesUI->shortcutTableView->setRowHidden(row, !match); + } +} + void UBPreferencesController::show() { init(); @@ -293,6 +423,21 @@ void UBPreferencesController::wire() // about tab connect(mPreferencesUI->checkSoftwareUpdateAtLaunchCheckBox, SIGNAL(clicked(bool)), settings->appEnableAutomaticSoftwareUpdates, SLOT(setBool(bool))); + + // shortcut tab + connect(mPreferencesUI->shortcutTableView, SIGNAL(activated(const QModelIndex&)), this, SLOT(actionSelected(const QModelIndex&))); + connect(mPreferencesUI->filter, SIGNAL(textChanged(const QString&)), this, SLOT(applyShortcutFilter(const QString&))); + connect(mPreferencesUI->recordButton, SIGNAL(clicked(bool)), this, SLOT(recordingClicked(bool))); + connect(mPreferencesUI->abortButton, SIGNAL(clicked()), this, SLOT(abortClicked())); + connect(mPreferencesUI->resetButton, SIGNAL(clicked()), this, SLOT(resetClicked())); + connect(mPreferencesUI->noCtrl, &QCheckBox::toggled, UBShortcutManager::shortcutManager(), &UBShortcutManager::ignoreCtrl); + connect(mPreferencesUI->mainTabWidget, &QTabWidget::currentChanged, [this](int tab){ + auto shortcutTab = mPreferencesUI->mainTabWidget->indexOf(mPreferencesUI->shortcutTab); + + if (tab != shortcutTab) { + abortClicked(); + } + }); } void UBPreferencesController::init() @@ -351,6 +496,27 @@ void UBPreferencesController::init() mMarkerProperties->opacitySlider->setValue(settings->boardMarkerAlpha->get().toDouble() * 100); + // shortcut tab + mPreferencesUI->shortcutTableView->setModel(UBShortcutManager::shortcutManager()); + mPreferencesUI->shortcutTableView->horizontalHeader()->setModel(UBShortcutManager::shortcutManager()); + mPreferencesUI->shortcutTableView->horizontalHeader()->resizeSection(0, 150); + mPreferencesUI->shortcutTableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); + mPreferencesUI->noCtrl->setChecked(settings->value("Shortcut/IgnoreCtrl").toBool()); + mPreferencesUI->noCtrl->setEnabled(!UBShortcutManager::shortcutManager()->hasCtrlConflicts()); +} + +bool UBPreferencesController::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::KeyPress) + { + QKeyEvent *keyEvent = static_cast(event); + return handleKeyEvent(keyEvent); + } + else + { + // standard event processing + return QObject::eventFilter(obj, event); + } } void UBPreferencesController::close() @@ -445,7 +611,8 @@ void UBPreferencesController::defaultSettings() mPreferencesUI->checkSoftwareUpdateAtLaunchCheckBox->setChecked(defaultValue); } - else if(mPreferencesUI->mainTabWidget->currentWidget() == mPreferencesUI->networkTab){ + else if(mPreferencesUI->mainTabWidget->currentWidget() == mPreferencesUI->networkTab) + { bool defaultValue = settings->webUseExternalBrowser->reset().toBool(); mPreferencesUI->useExternalBrowserCheckBox->setChecked(defaultValue); defaultValue = settings->webShowPageImmediatelyOnMirroredScreen->reset().toBool(); @@ -480,6 +647,23 @@ void UBPreferencesController::defaultSettings() lightBackgroundCrossOpacityValueChanged(lightBackgroundOpacity); } + else if(mPreferencesUI->mainTabWidget->currentWidget() == mPreferencesUI->shortcutTab) + { + if (mPreferencesUI->recordButton->isChecked()) + { + abortClicked(); + } + + UBShortcutManager* sm = UBShortcutManager::shortcutManager(); + + for (int row = 0; row < sm->rowCount(); ++row) + { + QModelIndex rowIndex = sm->index(row, 0); + sm->resetData(rowIndex); + } + + resetClicked(); + } } void UBPreferencesController::darkBackgroundCrossOpacityValueChanged(int value) @@ -690,6 +874,70 @@ void UBPreferencesController::systemOSKCheckBoxToggled(bool checked) mPreferencesUI->keyboardPaletteKeyButtonSize_Label->setVisible(!checked); } +void UBPreferencesController::actionSelected(const QModelIndex &index) +{ + currentIndex = index; + UBShortcutManager* sm = UBShortcutManager::shortcutManager(); + mPreferencesUI->keySequence->setText(sm->data(index.siblingAtColumn(2), UBShortcutManager::PrimaryShortcutRole).toString()); + mPreferencesUI->mouseButton->setText(sm->data(index.siblingAtColumn(3)).toString()); + mPreferencesUI->stylusButton->setText(sm->data(index.siblingAtColumn(4)).toString()); + + bool isAction = sm->data(index, UBShortcutManager::ActionRole).toBool(); + mPreferencesUI->recordButton->setEnabled(true); + mPreferencesUI->shortcutsGroupBox->setEnabled(isAction); +} + +void UBPreferencesController::recordingClicked(bool checked) +{ + if (!checked && currentIndex.isValid()) + { + UBShortcutManager* sm = UBShortcutManager::shortcutManager(); + sm->setData(currentIndex.siblingAtColumn(2), mPreferencesUI->keySequence->text()); + sm->setData(currentIndex.siblingAtColumn(3), sm->buttonIndex(mPreferencesUI->mouseButton->text())); + sm->setData(currentIndex.siblingAtColumn(4), sm->buttonIndex(mPreferencesUI->stylusButton->text())); + } + + mPreferencesUI->shortcutTableView->setSelectionMode(checked ? QTableView::NoSelection : QTableView::SingleSelection); + mPreferencesUI->recordButton->setText(checked ? tr("Accept", "preferencesDialog") : tr("Record", "preferencesDialog")); +} + +void UBPreferencesController::abortClicked() +{ + applyShortcutFilter(mPreferencesUI->filter->text()); + + mPreferencesUI->recordButton->setEnabled(true); + mPreferencesUI->recordButton->setChecked(false); + mPreferencesUI->recordButton->setText(tr("Record", "preferencesDialog")); + mPreferencesUI->shortcutTableView->setSelectionMode(QTableView::SingleSelection); + mPreferencesUI->shortcutTableView->clearSelection(); + mPreferencesUI->report->setText(""); + mPreferencesUI->noCtrl->setEnabled(!UBShortcutManager::shortcutManager()->hasCtrlConflicts()); + actionSelected(mPreferencesUI->shortcutTableView->model()->index(0, 0)); +} + +void UBPreferencesController::resetClicked() +{ + if (mPreferencesUI->recordButton->isChecked()) + { + abortClicked(); + } + + if (currentIndex.isValid()) + { + UBShortcutManager* sm = UBShortcutManager::shortcutManager(); + + sm->resetData(currentIndex); + applyShortcutFilter(mPreferencesUI->filter->text()); + + mPreferencesUI->keySequence->setText(sm->data(currentIndex.siblingAtColumn(2)).toString()); + mPreferencesUI->mouseButton->setText(sm->data(currentIndex.siblingAtColumn(3)).toString()); + mPreferencesUI->stylusButton->setText(sm->data(currentIndex.siblingAtColumn(4)).toString()); + } + + mPreferencesUI->report->setText(""); + mPreferencesUI->noCtrl->setEnabled(!UBShortcutManager::shortcutManager()->hasCtrlConflicts()); +} + UBBrushPropertiesFrame::UBBrushPropertiesFrame(QFrame* owner, const QList& lightBackgroundColors, const QList& darkBackgroundColors, const QList& lightBackgroundSelectedColors, const QList& darkBackgroundSelectedColors, UBPreferencesController* controller) diff --git a/src/core/UBPreferencesController.h b/src/core/UBPreferencesController.h index d89b4c181..25413762c 100644 --- a/src/core/UBPreferencesController.h +++ b/src/core/UBPreferencesController.h @@ -70,6 +70,9 @@ class UBPreferencesController : public QObject UBPreferencesController(QWidget *parent); virtual ~UBPreferencesController(); + bool handleKeyEvent(QKeyEvent *event); + bool handleMouseEvent(QMouseEvent *event); + bool handleTabletEvent(QTabletEvent *event); public slots: @@ -80,6 +83,8 @@ class UBPreferencesController : public QObject void wire(); void init(); + virtual bool eventFilter(QObject* obj, QEvent* event) Q_DECL_OVERRIDE; + UBPreferencesDialog* mPreferencesWindow; Ui::preferencesDialog* mPreferencesUI; UBBrushPropertiesFrame* mPenProperties; @@ -104,14 +109,21 @@ class UBPreferencesController : public QObject void toolbarOrientationVertical(bool checked); void toolbarOrientationHorizontal(bool checked); void systemOSKCheckBoxToggled(bool checked); + void actionSelected(const QModelIndex& index); + void recordingClicked(bool checked); + void abortClicked(); + void resetClicked(); private slots: void adjustScreensPreferences(); + void applyShortcutFilter(const QString& filter, int filterCol = -1); + private: static qreal sSliderRatio; static qreal sMinPenWidth; static qreal sMaxPenWidth; + QModelIndex currentIndex; }; class UBBrushPropertiesFrame : public Ui::brushProperties From 4cb8f13b4135c16c2ff9c4966863827d601cd08a Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 30 Sep 2024 16:21:21 +0200 Subject: [PATCH 100/133] i18n: update German translation - change ownership of a translation string in UBShortcutManager - add new translation strings - update a few translations --- resources/i18n/OpenBoard_de.ts | 70 ++++++++++++++++++++++++++++++++-- src/core/UBShortcutManager.cpp | 2 +- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/resources/i18n/OpenBoard_de.ts b/resources/i18n/OpenBoard_de.ts index 2eb616221..e6f43f5e5 100644 --- a/resources/i18n/OpenBoard_de.ts +++ b/resources/i18n/OpenBoard_de.ts @@ -3007,6 +3007,28 @@ Möchten Sie diese Fehler für diesen Computer ignorieren? Use all available displays Alle verfügbaren Bildschirme nutzen + + Key sequence already in use + Tastenkombination wird bereits benutzt + + + Mouse button already in use + Maustaste wird bereits benutzt + + + Stylus button already in use + Stifttaste wird bereits benutzt + + + Accept + preferencesDialog + Übernehmen + + + Record + preferencesDialog + Aufnehmen + UBSettings @@ -3078,7 +3100,7 @@ Möchten Sie diese Fehler für diesen Computer ignorieren? Reset zoom factor - Zoom zurücksetzen + Zoom-Faktor zurücksetzen @@ -3128,7 +3150,7 @@ Möchten Sie diese Fehler für diesen Computer ignorieren? Command - Kommando + Befehl @@ -3143,12 +3165,12 @@ Möchten Sie diese Fehler für diesen Computer ignorieren? Mouse Button - Mausknopf + Maustaste Tablet Button - Tablet Stiftknopf + Stifttaste @@ -4074,6 +4096,46 @@ p, li { white-space: pre-wrap; } List of screens used for Control, Display and Previous pages Liste der Bildschirme, die für die Hauptansicht, Erweiterte Ansicht und Vorherige Seiten verwendet werden + + Shortcut + Kurzbefehl + + + Filter + Filter + + + Active keyboard shortcuts without pressing Ctrl key + Aktiviere Kurzbefehle auch ohne Strg Taste + + + Shortcuts + Kurzbefehle + + + Abort + Abbrechen + + + Record + Aufnehmen + + + Stylus Button + Stifttaste + + + Mouse Button + Maustaste + + + Reset + Zurücksetzen + + + Key Sequence + Tasten + trapFlashDialog diff --git a/src/core/UBShortcutManager.cpp b/src/core/UBShortcutManager.cpp index dfe8c8239..56a66a870 100644 --- a/src/core/UBShortcutManager.cpp +++ b/src/core/UBShortcutManager.cpp @@ -43,7 +43,7 @@ UBShortcutManager* UBShortcutManager::sShortcutManager = nullptr; UBShortcutManager::UBShortcutManager() : mIgnoreCtrl(false) { - actionsOfGroup(QObject::tr("Common")); + actionsOfGroup(tr("Common")); } UBShortcutManager *UBShortcutManager::shortcutManager() From fd2ef1560716d19177c6810cad0f51928593e695 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Thu, 6 Nov 2025 09:04:50 +0100 Subject: [PATCH 101/133] feat: improve shortcut configuration - use QKeySequenceEdit for keyboard shortcuts - filter for exact match to detect conflicts - start recording by double-click in table - start recording by focussing key sequence input field - don't allow to edit cut, copy and paste shortcuts --- resources/forms/preferences.ui | 5 +- src/core/UBPreferencesController.cpp | 130 ++++++++++++++------------- src/core/UBPreferencesController.h | 3 - src/core/UBShortcutManager.cpp | 9 +- 4 files changed, 76 insertions(+), 71 deletions(-) diff --git a/resources/forms/preferences.ui b/resources/forms/preferences.ui index 9b73f8d65..fd2106ee5 100644 --- a/resources/forms/preferences.ui +++ b/resources/forms/preferences.ui @@ -1239,10 +1239,7 @@ - - - true - + diff --git a/src/core/UBPreferencesController.cpp b/src/core/UBPreferencesController.cpp index 145323385..df03678aa 100644 --- a/src/core/UBPreferencesController.cpp +++ b/src/core/UBPreferencesController.cpp @@ -88,7 +88,10 @@ UBPreferencesController::UBPreferencesController(QWidget *parent) adjustScreensPreferences(); connect(UBApplication::displayManager, &UBDisplayManager::availableScreenCountChanged, this, &UBPreferencesController::adjustScreensPreferences); - mPreferencesUI->shortcutTab->installEventFilter(this); + +#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) + mPreferencesUI->keySequence->setMaximumSequenceLength(1); +#endif wire(); } @@ -105,42 +108,6 @@ UBPreferencesController::~UBPreferencesController() delete mMarkerProperties; } -bool UBPreferencesController::handleKeyEvent(QKeyEvent *event) -{ - if (!mPreferencesUI->recordButton->isChecked() - || mPreferencesUI->mainTabWidget->currentWidget() != mPreferencesUI->shortcutTab) - { - return false; - } - - int key = event->key(); - Qt::KeyboardModifiers mods = event->modifiers(); - QString text = event->text(); - - int keys = mods; - - if (key < Qt::Key_Shift || key > Qt::Key_ScrollLock) - { - keys += key; - } - - // compose key sequence from active modifiers and key - QKeySequence keySequence(keys); - QString keyString = keySequence.toString(); - mPreferencesUI->keySequence->setText(keyString); - - if (currentIndex.isValid()) - { - bool ok = UBShortcutManager::shortcutManager()->checkData(currentIndex.siblingAtColumn(2), keyString); - applyShortcutFilter(ok ? mPreferencesUI->filter->text() : keyString, ok ? -1 : 2); - mPreferencesUI->recordButton->setEnabled(ok); - mPreferencesUI->report->setText(ok ? "" : tr("Key sequence already in use")); - mPreferencesUI->noCtrl->setEnabled(!UBShortcutManager::shortcutManager()->hasCtrlConflicts(keySequence)); - } - - return true; -} - bool UBPreferencesController::handleMouseEvent(QMouseEvent *event) { if (!mPreferencesUI->recordButton->isChecked() @@ -159,6 +126,7 @@ bool UBPreferencesController::handleMouseEvent(QMouseEvent *event) applyShortcutFilter(ok ? mPreferencesUI->filter->text() : buttonName, ok ? -1 : 3); mPreferencesUI->recordButton->setEnabled(ok); mPreferencesUI->report->setText(ok ? "" : tr("Mouse button already in use")); + event->accept(); return true; } @@ -183,6 +151,7 @@ bool UBPreferencesController::handleTabletEvent(QTabletEvent *event) applyShortcutFilter(ok ? mPreferencesUI->filter->text() : buttonName, ok ? -1 : 4); mPreferencesUI->recordButton->setEnabled(ok); mPreferencesUI->report->setText(ok ? "" : tr("Stylus button already in use")); + event->accept(); return true; } @@ -255,8 +224,22 @@ void UBPreferencesController::applyShortcutFilter(const QString &filter, int fil for (int col = minCol; col < maxCol; ++col) { QModelIndex colIndex = rowIndex.siblingAtColumn(col); + const auto colData{model->data(colIndex).toString()}; + const auto exactMatch{filterCol >= 0}; + + bool hasMatch{false}; + + if (exactMatch) + { + const auto tokens = colData.split(", "); + hasMatch = tokens.contains(filter); + } + else + { + hasMatch = colData.contains(filter, Qt::CaseInsensitive); + } - if (model->data(colIndex).toString().contains(filter, Qt::CaseInsensitive)) + if (hasMatch) { match = true; groupVisible = true; @@ -425,11 +408,14 @@ void UBPreferencesController::wire() connect(mPreferencesUI->checkSoftwareUpdateAtLaunchCheckBox, SIGNAL(clicked(bool)), settings->appEnableAutomaticSoftwareUpdates, SLOT(setBool(bool))); // shortcut tab - connect(mPreferencesUI->shortcutTableView, SIGNAL(activated(const QModelIndex&)), this, SLOT(actionSelected(const QModelIndex&))); - connect(mPreferencesUI->filter, SIGNAL(textChanged(const QString&)), this, SLOT(applyShortcutFilter(const QString&))); - connect(mPreferencesUI->recordButton, SIGNAL(clicked(bool)), this, SLOT(recordingClicked(bool))); - connect(mPreferencesUI->abortButton, SIGNAL(clicked()), this, SLOT(abortClicked())); - connect(mPreferencesUI->resetButton, SIGNAL(clicked()), this, SLOT(resetClicked())); + connect(mPreferencesUI->shortcutTableView, &QTableView::clicked, this, &UBPreferencesController::actionSelected); + connect(mPreferencesUI->shortcutTableView, &QTableView::doubleClicked, this, [this](){ + mPreferencesUI->keySequence->setFocus(); + }); + connect(mPreferencesUI->filter, &QLineEdit::textChanged, this, [this](const QString& text){applyShortcutFilter(text);}); + connect(mPreferencesUI->recordButton, &QPushButton::clicked, this, &UBPreferencesController::recordingClicked); + connect(mPreferencesUI->abortButton, &QPushButton::clicked, this, &UBPreferencesController::abortClicked); + connect(mPreferencesUI->resetButton, &QPushButton::clicked, this, &UBPreferencesController::resetClicked); connect(mPreferencesUI->noCtrl, &QCheckBox::toggled, UBShortcutManager::shortcutManager(), &UBShortcutManager::ignoreCtrl); connect(mPreferencesUI->mainTabWidget, &QTabWidget::currentChanged, [this](int tab){ auto shortcutTab = mPreferencesUI->mainTabWidget->indexOf(mPreferencesUI->shortcutTab); @@ -438,6 +424,28 @@ void UBPreferencesController::wire() abortClicked(); } }); + connect(mPreferencesUI->keySequence, &QKeySequenceEdit::keySequenceChanged, this, [this](const QKeySequence& keySequence){ + // check validity of shortcut + if (currentIndex.isValid()) + { + const QString keyString{keySequence.toString()}; + bool ok = UBShortcutManager::shortcutManager()->checkData(currentIndex.siblingAtColumn(2), keyString); + applyShortcutFilter(ok ? mPreferencesUI->filter->text() : keyString, ok ? -1 : 2); + mPreferencesUI->recordButton->setEnabled(ok); + mPreferencesUI->report->setText(ok ? "" : tr("Key sequence already in use")); + mPreferencesUI->noCtrl->setEnabled(!UBShortcutManager::shortcutManager()->hasCtrlConflicts(keySequence)); + } + }); + connect(UBApplication::app(), &QApplication::focusChanged, this, [this](QWidget*, QWidget* now){ + // activate recording when input field gets focus + if (now == mPreferencesUI->keySequence || now == mPreferencesUI->mouseButton || now == mPreferencesUI->stylusButton) + { + if (mPreferencesUI->recordButton->isEnabled() && !mPreferencesUI->recordButton->isChecked()) + { + mPreferencesUI->recordButton->click(); + } + } + }); } void UBPreferencesController::init() @@ -505,20 +513,6 @@ void UBPreferencesController::init() mPreferencesUI->noCtrl->setEnabled(!UBShortcutManager::shortcutManager()->hasCtrlConflicts()); } -bool UBPreferencesController::eventFilter(QObject *obj, QEvent *event) -{ - if (event->type() == QEvent::KeyPress) - { - QKeyEvent *keyEvent = static_cast(event); - return handleKeyEvent(keyEvent); - } - else - { - // standard event processing - return QObject::eventFilter(obj, event); - } -} - void UBPreferencesController::close() { //web @@ -874,11 +868,17 @@ void UBPreferencesController::systemOSKCheckBoxToggled(bool checked) mPreferencesUI->keyboardPaletteKeyButtonSize_Label->setVisible(!checked); } -void UBPreferencesController::actionSelected(const QModelIndex &index) +void UBPreferencesController::actionSelected(const QModelIndex& index) { + if (mPreferencesUI->recordButton->isChecked()) + { + return; + } + currentIndex = index; UBShortcutManager* sm = UBShortcutManager::shortcutManager(); - mPreferencesUI->keySequence->setText(sm->data(index.siblingAtColumn(2), UBShortcutManager::PrimaryShortcutRole).toString()); + const QKeySequence keySequence{sm->data(index.siblingAtColumn(2), UBShortcutManager::PrimaryShortcutRole).toString()}; + mPreferencesUI->keySequence->setKeySequence(keySequence); mPreferencesUI->mouseButton->setText(sm->data(index.siblingAtColumn(3)).toString()); mPreferencesUI->stylusButton->setText(sm->data(index.siblingAtColumn(4)).toString()); @@ -891,11 +891,16 @@ void UBPreferencesController::recordingClicked(bool checked) { if (!checked && currentIndex.isValid()) { + // recording finished UBShortcutManager* sm = UBShortcutManager::shortcutManager(); - sm->setData(currentIndex.siblingAtColumn(2), mPreferencesUI->keySequence->text()); + sm->setData(currentIndex.siblingAtColumn(2), mPreferencesUI->keySequence->keySequence().toString()); sm->setData(currentIndex.siblingAtColumn(3), sm->buttonIndex(mPreferencesUI->mouseButton->text())); sm->setData(currentIndex.siblingAtColumn(4), sm->buttonIndex(mPreferencesUI->stylusButton->text())); } + else if (checked) + { + mPreferencesUI->keySequence->setFocus(); + } mPreferencesUI->shortcutTableView->setSelectionMode(checked ? QTableView::NoSelection : QTableView::SingleSelection); mPreferencesUI->recordButton->setText(checked ? tr("Accept", "preferencesDialog") : tr("Record", "preferencesDialog")); @@ -909,10 +914,8 @@ void UBPreferencesController::abortClicked() mPreferencesUI->recordButton->setChecked(false); mPreferencesUI->recordButton->setText(tr("Record", "preferencesDialog")); mPreferencesUI->shortcutTableView->setSelectionMode(QTableView::SingleSelection); - mPreferencesUI->shortcutTableView->clearSelection(); mPreferencesUI->report->setText(""); mPreferencesUI->noCtrl->setEnabled(!UBShortcutManager::shortcutManager()->hasCtrlConflicts()); - actionSelected(mPreferencesUI->shortcutTableView->model()->index(0, 0)); } void UBPreferencesController::resetClicked() @@ -929,7 +932,8 @@ void UBPreferencesController::resetClicked() sm->resetData(currentIndex); applyShortcutFilter(mPreferencesUI->filter->text()); - mPreferencesUI->keySequence->setText(sm->data(currentIndex.siblingAtColumn(2)).toString()); + const QKeySequence keySequence{sm->data(currentIndex.siblingAtColumn(2)).toString()}; + mPreferencesUI->keySequence->setKeySequence(keySequence); mPreferencesUI->mouseButton->setText(sm->data(currentIndex.siblingAtColumn(3)).toString()); mPreferencesUI->stylusButton->setText(sm->data(currentIndex.siblingAtColumn(4)).toString()); } diff --git a/src/core/UBPreferencesController.h b/src/core/UBPreferencesController.h index 25413762c..e51f0c347 100644 --- a/src/core/UBPreferencesController.h +++ b/src/core/UBPreferencesController.h @@ -70,7 +70,6 @@ class UBPreferencesController : public QObject UBPreferencesController(QWidget *parent); virtual ~UBPreferencesController(); - bool handleKeyEvent(QKeyEvent *event); bool handleMouseEvent(QMouseEvent *event); bool handleTabletEvent(QTabletEvent *event); @@ -83,8 +82,6 @@ class UBPreferencesController : public QObject void wire(); void init(); - virtual bool eventFilter(QObject* obj, QEvent* event) Q_DECL_OVERRIDE; - UBPreferencesDialog* mPreferencesWindow; Ui::preferencesDialog* mPreferencesUI; UBBrushPropertiesFrame* mPenProperties; diff --git a/src/core/UBShortcutManager.cpp b/src/core/UBShortcutManager.cpp index 56a66a870..6653e5af3 100644 --- a/src/core/UBShortcutManager.cpp +++ b/src/core/UBShortcutManager.cpp @@ -133,6 +133,11 @@ void UBShortcutManager::addMainActions(UBMainWindow *mainWindow) mainWindow->actionQuit }, mainWindow); + // Don't allow to modify these shortcuts + mainWindow->actionCut->setProperty("builtIn", true); + mainWindow->actionCopy->setProperty("builtIn", true); + mainWindow->actionPaste->setProperty("builtIn", true); + addActions(tr("Board"), { mainWindow->actionUndo, mainWindow->actionRedo, @@ -574,7 +579,9 @@ bool UBShortcutManager::checkData(const QModelIndex &index, const QVariant &valu for (int row = 0; row < rowCount(); ++row) { - if (data(index.siblingAtRow(row)).toString().split(", ").contains(value.toString())) + if (row != index.row() && + !value.toString().isEmpty() && + data(index.siblingAtRow(row)).toString().split(", ").contains(value.toString())) { // duplicate value return false; From e7a9d844da1af4a40848e5ef35a380c921515acf Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Wed, 3 Dec 2025 14:11:11 +0100 Subject: [PATCH 102/133] refactor: rearrange shortcut configuration UI - move buttons below input fields - right aligned: Reset, Abort, Record - red background to Record button while pressed - red border around disabled shortcut table during recording - double-click table entry to start recording Signed-off-by: letsfindaway --- resources/forms/preferences.ui | 165 ++++++++++++++++----------- src/core/UBPreferencesController.cpp | 6 +- 2 files changed, 103 insertions(+), 68 deletions(-) diff --git a/resources/forms/preferences.ui b/resources/forms/preferences.ui index fd2106ee5..eef21bf6a 100644 --- a/resources/forms/preferences.ui +++ b/resources/forms/preferences.ui @@ -1112,13 +1112,16 @@ true + + QScrollArea:disabled {border: 1px solid red;} + 0 0 - 789 - 447 + 1032 + 173 @@ -1182,8 +1185,57 @@ Qt::AlignCenter - - + + + + + + + Key Sequence + + + + + + + true + + + 1 + + + + + + + Mouse Button + + + + + + + true + + + + + + + Stylus Button + + + + + + + true + + + + + + color: red; @@ -1193,68 +1245,49 @@ - - - - true - - - - - - - Abort - - - - - - - Record - - - true - - - - - - - Stylus Button - - - - - - - Mouse Button - - - - - - - true - - - - - - - - - - - Reset - - - - - - - Key Sequence - - + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Reset + + + + + + + Abort + + + + + + + QPushButton:checked {background-color: red} + + + Record + + + true + + + + diff --git a/src/core/UBPreferencesController.cpp b/src/core/UBPreferencesController.cpp index df03678aa..ca8e6f547 100644 --- a/src/core/UBPreferencesController.cpp +++ b/src/core/UBPreferencesController.cpp @@ -410,10 +410,12 @@ void UBPreferencesController::wire() // shortcut tab connect(mPreferencesUI->shortcutTableView, &QTableView::clicked, this, &UBPreferencesController::actionSelected); connect(mPreferencesUI->shortcutTableView, &QTableView::doubleClicked, this, [this](){ + mPreferencesUI->recordButton->setChecked(true); mPreferencesUI->keySequence->setFocus(); }); connect(mPreferencesUI->filter, &QLineEdit::textChanged, this, [this](const QString& text){applyShortcutFilter(text);}); connect(mPreferencesUI->recordButton, &QPushButton::clicked, this, &UBPreferencesController::recordingClicked); + connect(mPreferencesUI->recordButton, &QPushButton::toggled, mPreferencesUI->shortcutScrollArea, &QScrollArea::setDisabled); connect(mPreferencesUI->abortButton, &QPushButton::clicked, this, &UBPreferencesController::abortClicked); connect(mPreferencesUI->resetButton, &QPushButton::clicked, this, &UBPreferencesController::resetClicked); connect(mPreferencesUI->noCtrl, &QCheckBox::toggled, UBShortcutManager::shortcutManager(), &UBShortcutManager::ignoreCtrl); @@ -903,7 +905,7 @@ void UBPreferencesController::recordingClicked(bool checked) } mPreferencesUI->shortcutTableView->setSelectionMode(checked ? QTableView::NoSelection : QTableView::SingleSelection); - mPreferencesUI->recordButton->setText(checked ? tr("Accept", "preferencesDialog") : tr("Record", "preferencesDialog")); +// mPreferencesUI->recordButton->setText(checked ? tr("Accept", "preferencesDialog") : tr("Record", "preferencesDialog")); } void UBPreferencesController::abortClicked() @@ -912,7 +914,7 @@ void UBPreferencesController::abortClicked() mPreferencesUI->recordButton->setEnabled(true); mPreferencesUI->recordButton->setChecked(false); - mPreferencesUI->recordButton->setText(tr("Record", "preferencesDialog")); +// mPreferencesUI->recordButton->setText(tr("Record", "preferencesDialog")); mPreferencesUI->shortcutTableView->setSelectionMode(QTableView::SingleSelection); mPreferencesUI->report->setText(""); mPreferencesUI->noCtrl->setEnabled(!UBShortcutManager::shortcutManager()->hasCtrlConflicts()); From 8d7ad12261dab76b04c10b44a2c1eace33861cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Wed, 14 Jan 2026 17:21:15 +0100 Subject: [PATCH 103/133] fixed immediate crash on gnome+wayland by not setting Qt::ToolTip window flag on the status bar --- src/core/UBDisplayManager.h | 1 + src/frameworks/UBDesktopPortal.h | 1 + src/frameworks/UBPipewireSink.h | 1 + src/web/simplebrowser/browserwindow.cpp | 9 ++++++++- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/core/UBDisplayManager.h b/src/core/UBDisplayManager.h index 082da734d..ad9ac2d59 100644 --- a/src/core/UBDisplayManager.h +++ b/src/core/UBDisplayManager.h @@ -33,6 +33,7 @@ #include #include #include +#include class UBBlackoutWidget; class UBBoardView; diff --git a/src/frameworks/UBDesktopPortal.h b/src/frameworks/UBDesktopPortal.h index 57d4e620d..157a45b86 100644 --- a/src/frameworks/UBDesktopPortal.h +++ b/src/frameworks/UBDesktopPortal.h @@ -25,6 +25,7 @@ #include #include #include +#include // forward class QDBusInterface; diff --git a/src/frameworks/UBPipewireSink.h b/src/frameworks/UBPipewireSink.h index 44ccb657f..f2539b6af 100644 --- a/src/frameworks/UBPipewireSink.h +++ b/src/frameworks/UBPipewireSink.h @@ -23,6 +23,7 @@ #pragma once #include +#include #include #include diff --git a/src/web/simplebrowser/browserwindow.cpp b/src/web/simplebrowser/browserwindow.cpp index c9cb01d1e..4e6022c56 100644 --- a/src/web/simplebrowser/browserwindow.cpp +++ b/src/web/simplebrowser/browserwindow.cpp @@ -67,6 +67,8 @@ #include #include +#include "frameworks/UBPlatformUtils.h" + #include "core/UBApplication.h" #include "core/UBApplicationController.h" #include "core/UBDisplayManager.h" @@ -106,7 +108,12 @@ BrowserWindow::BrowserWindow(QWidget *parent, QWebEngineProfile *profile, bool f void BrowserWindow::init() { m_statusBar = new QStatusBar(this); - m_statusBar->setWindowFlag(Qt::ToolTip); + + // On Wayland, popup-like tooltips without an input-grabbed parent can trigger a protocol error. + if (UBPlatformUtils::sessionType() != UBPlatformUtils::WAYLAND) + { + m_statusBar->setWindowFlag(Qt::ToolTip); + } m_statusBar->setVisible(true); connect(m_tabWidget, &TabWidget::titleChanged, this, &BrowserWindow::handleWebViewTitleChanged); From 2ad6bfcac26c4849cce89ae7c8600e535d33e6d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Fri, 30 Jan 2026 14:24:02 +0100 Subject: [PATCH 104/133] fix gnome+wayland screen and video capture issues using xdg-desktop-portal --- src/core/UBApplication.cpp | 3 - src/desktop/UBDesktopAnnotationController.cpp | 66 ++++- src/desktop/UBDesktopAnnotationController.h | 1 + src/frameworks/UBDesktopPortal.cpp | 244 ++++++++++++++++-- src/frameworks/UBDesktopPortal.h | 6 + 5 files changed, 282 insertions(+), 38 deletions(-) diff --git a/src/core/UBApplication.cpp b/src/core/UBApplication.cpp index b71ccbdb8..5daab97b3 100644 --- a/src/core/UBApplication.cpp +++ b/src/core/UBApplication.cpp @@ -107,11 +107,8 @@ UBApplication::UBApplication(const QString &id, int &argc, char **argv) : Single setOrganizationDomain("oe-f.org"); setApplicationName("OpenBoard"); setDesktopFileName("ch.openboard.OpenBoard"); - -#ifdef Q_OS_OSX // With Qt 6.9 on macOS 15 (at least), icons aren't shown in menus. This forces their display. QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, false); -#endif QString version = UBVERSION; if(version.endsWith(".")) diff --git a/src/desktop/UBDesktopAnnotationController.cpp b/src/desktop/UBDesktopAnnotationController.cpp index 7fec53a14..788ba7013 100644 --- a/src/desktop/UBDesktopAnnotationController.cpp +++ b/src/desktop/UBDesktopAnnotationController.cpp @@ -29,6 +29,9 @@ #include "UBDesktopAnnotationController.h" +#include +#include + #include "frameworks/UBPlatformUtils.h" #include "core/UBApplication.h" @@ -187,6 +190,26 @@ UBDesktopAnnotationController::~UBDesktopAnnotationController() delete mTransparentDrawingView; } +QPixmap UBDesktopAnnotationController::clipboardScreenshot() +{ + QClipboard* clipboard = QGuiApplication::clipboard(); + + if (!clipboard) + { + return {}; + } + + const QImage image = clipboard->image(); + + if (!image.isNull()) + { + return QPixmap::fromImage(image); + } + + const QPixmap pixmap = clipboard->pixmap(); + return pixmap.isNull() ? QPixmap{} : pixmap; +} + void UBDesktopAnnotationController::updateColors(){ if(UBApplication::boardController->activeScene()->isDarkBackground()){ mTransparentDrawingScene->setSceneBackground(true, nullptr); @@ -449,19 +472,32 @@ void UBDesktopAnnotationController::customCapture() mDesktopPalette->disappearForCapture(); getScreenPixmap([this](QPixmap pixmap){ + auto finishCapture = [this](){ + mDesktopPalette->appear(); + mCustomCaptureClicked = false; + mIsFullyTransparent = false; + updateBackground(); + }; + + QPixmap screenshot = pixmap.isNull() ? clipboardScreenshot() : pixmap; + + // On Wayland with xdg-desktop-portal, the user already chose the area. + if (UBPlatformUtils::sessionType() == UBPlatformUtils::WAYLAND && !screenshot.isNull()) + { + emit imageCaptured(screenshot, false); + finishCapture(); + return; + } + UBCustomCaptureWindow customCaptureWindow(mDesktopPalette); - if (customCaptureWindow.execute(pixmap) == QDialog::Accepted) + if (customCaptureWindow.execute(screenshot) == QDialog::Accepted) { QPixmap selectedPixmap = customCaptureWindow.getSelectedPixmap(); emit imageCaptured(selectedPixmap, false); } - mDesktopPalette->appear(); - - mCustomCaptureClicked = false; - mIsFullyTransparent = false; - updateBackground(); + finishCapture(); }); } } @@ -476,13 +512,23 @@ void UBDesktopAnnotationController::screenCapture() mDesktopPalette->disappearForCapture(); getScreenPixmap([this](QPixmap pixmap){ - mDesktopPalette->appear(); + auto finishCapture = [this](){ + mDesktopPalette->appear(); + mIsFullyTransparent = false; + updateBackground(); + }; - emit imageCaptured(pixmap, false); + QPixmap screenshot = pixmap.isNull() ? clipboardScreenshot() : pixmap; - mIsFullyTransparent = false; + if (UBPlatformUtils::sessionType() == UBPlatformUtils::WAYLAND && !screenshot.isNull()) + { + emit imageCaptured(screenshot, false); + finishCapture(); + return; + } - updateBackground(); + emit imageCaptured(screenshot, false); + finishCapture(); }); } diff --git a/src/desktop/UBDesktopAnnotationController.h b/src/desktop/UBDesktopAnnotationController.h index c549cb934..b217a663a 100644 --- a/src/desktop/UBDesktopAnnotationController.h +++ b/src/desktop/UBDesktopAnnotationController.h @@ -132,6 +132,7 @@ class UBDesktopAnnotationController : public QObject void setAssociatedPalettePosition(UBActionPalette* palette, const QString& actionName); void togglePropertyPalette(UBActionPalette* palette); void updateMask(bool bTransparent); + static QPixmap clipboardScreenshot(); UBDesktopPalette *mDesktopPalette; //UBKeyboardPalette *mKeyboardPalette; diff --git a/src/frameworks/UBDesktopPortal.cpp b/src/frameworks/UBDesktopPortal.cpp index 99015abe1..468630065 100644 --- a/src/frameworks/UBDesktopPortal.cpp +++ b/src/frameworks/UBDesktopPortal.cpp @@ -22,9 +22,17 @@ #include "UBDesktopPortal.h" +#include #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include "board/UBBoardView.h" @@ -42,6 +50,77 @@ enum : uint { TRANSIENT = 0, APPLICATION = 1, PERSISTENT = 2 } PersistMode; Q_DECLARE_METATYPE(UBDesktopPortal::Stream) Q_DECLARE_METATYPE(UBDesktopPortal::Streams) +QPixmap UBDesktopPortal::loadScreenshotFromUri(const QUrl& uri) const +{ + if (uri.isEmpty()) + { + return {}; + } + + QFile file(uri.toLocalFile()); + + if (!file.exists()) + { + qDebug() << "Screenshot image file does not exist" << uri; + return {}; + } + + QPixmap pixmap{file.fileName()}; + file.remove(); + qDebug() << "DesktopPortal: loaded screenshot file" << uri; + return pixmap; +} + +QPixmap UBDesktopPortal::readClipboardScreenshot() const +{ + auto clipboard = QGuiApplication::clipboard(); + + if (!clipboard) + { + qDebug() << "DesktopPortal: no clipboard available"; + return {}; + } + + QImage cbImage = clipboard->image(); + + if (!cbImage.isNull()) + { + QPixmap fromImage = QPixmap::fromImage(cbImage); + qDebug() << "DesktopPortal: clipboard image found" << "size" << fromImage.size(); + return fromImage; + } + + QPixmap cbPixmap = clipboard->pixmap(); + + if (!cbPixmap.isNull()) + { + qDebug() << "DesktopPortal: clipboard pixmap found" << "size" << cbPixmap.size(); + return cbPixmap; + } + + qDebug() << "DesktopPortal: clipboard empty"; + return {}; +} + + +QDBusArgument &operator << (QDBusArgument &arg, const UBDesktopPortal::Stream &stream) +{ + arg.beginStructure(); + arg << stream.node_id; + + arg.beginMap(qMetaTypeId(), qMetaTypeId()); + for (auto it = stream.map.cbegin(); it != stream.map.cend(); ++it) + { + arg.beginMapEntry(); + arg << it.key() << QDBusVariant(it.value()); + arg.endMapEntry(); + } + arg.endMap(); + + arg.endStructure(); + return arg; +} + const QDBusArgument &operator >> (const QDBusArgument &arg, UBDesktopPortal::Stream &stream) { arg.beginStructure(); @@ -52,11 +131,11 @@ const QDBusArgument &operator >> (const QDBusArgument &arg, UBDesktopPortal::Str while (!arg.atEnd()) { QString key; - QVariant value; + QDBusVariant value; arg.beginMapEntry(); arg >> key >> value; arg.endMapEntry(); - stream.map.insert(key, value); + stream.map.insert(key, value.variant()); } arg.endMap(); @@ -65,9 +144,37 @@ const QDBusArgument &operator >> (const QDBusArgument &arg, UBDesktopPortal::Str return arg; } +QDBusArgument &operator << (QDBusArgument &arg, const UBDesktopPortal::Streams &streams) +{ + arg.beginArray(qMetaTypeId()); + for (const auto &stream : streams) + { + arg << stream; + } + arg.endArray(); + return arg; +} + + +const QDBusArgument &operator >> (const QDBusArgument &arg, UBDesktopPortal::Streams &streams) +{ + streams.clear(); + arg.beginArray(); + while (!arg.atEnd()) + { + UBDesktopPortal::Stream stream; + arg >> stream; + streams.append(stream); + } + arg.endArray(); + return arg; +} + UBDesktopPortal::UBDesktopPortal(QObject* parent) : QObject{parent} { + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); } UBDesktopPortal::~UBDesktopPortal() @@ -81,22 +188,39 @@ UBDesktopPortal::~UBDesktopPortal() void UBDesktopPortal::grabScreen(QScreen* screen, const QRect& rect) { mScreenRect = screen->geometry(); + mInteractiveScreenshot = false; if (!rect.isNull()) { mScreenRect = rect.translated(mScreenRect.topLeft()); } + qDebug() << "DesktopPortal: grabScreen" + << "screen" << (screen ? screen->name() : QStringLiteral("")) + << "geom" << mScreenRect + << "rect" << rect; + QDBusInterface screenshotPortal("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop", "org.freedesktop.portal.Screenshot"); if (screenshotPortal.isValid()) { QMap options; options["handle_token"] = createRequestToken(); + options["interactive"] = true; // required by some portals (e.g. GNOME) + mInteractiveScreenshot = true; QDBusReply reply = screenshotPortal.call("Screenshot", "", options); QDBusObjectPath objectPath = reply.value(); QString path = objectPath.path(); - QDBusConnection::sessionBus().connect( + qDebug() << "DesktopPortal: Screenshot reply valid" << reply.isValid() << "path" << path << "options" << options; + + if (!reply.isValid()) + { + qWarning() << "DesktopPortal: Screenshot call failed" << reply.error(); + emit screenGrabbed(QPixmap{}); + return; + } + + const bool connected = QDBusConnection::sessionBus().connect( "", path, "org.freedesktop.portal.Request", @@ -104,6 +228,11 @@ void UBDesktopPortal::grabScreen(QScreen* screen, const QRect& rect) "ua{sv}", this, SLOT(handleScreenshotResponse(uint,QMap))); + + if (!connected) + { + qWarning() << "DesktopPortal: failed to connect to screenshot response signal"; + } } else { @@ -168,23 +297,62 @@ void UBDesktopPortal::stopScreenCast() void UBDesktopPortal::handleScreenshotResponse(uint code, const QMap& results) { - QUrl uri(results["uri"].toUrl()); - QFile file(uri.toLocalFile()); + qDebug() << "DesktopPortal: handleScreenshotResponse code" << code << "results" << results; - if (!file.exists()) + QPixmap pixmap; + auto finalizeScreenshot = [this](const QPixmap& pixmap){ + if (pixmap.isNull()) + { + qDebug() << "DesktopPortal: screenshot pixmap still null, aborting"; + emit screenGrabbed(QPixmap{}); + return; + } + + QPixmap screenshot; + + if (mInteractiveScreenshot) + { + // portal already applied the selection + screenshot = pixmap; + } + else + { + QRect targetRect = mScreenRect; + targetRect.moveTo(0, 0); // portal images are local to the grab + targetRect &= pixmap.rect(); + screenshot = pixmap.copy(targetRect); + qDebug() << "DesktopPortal: cropping screenshot" << "targetRect" << targetRect; + } + + qDebug() << "DesktopPortal: emitting screenshot" + << "interactive" << mInteractiveScreenshot + << "source size" << pixmap.size() + << "final size" << screenshot.size(); + emit screenGrabbed(screenshot); + }; + + const QUrl uri(results.value("uri").toUrl()); + qDebug() << "DesktopPortal: screenshot URI" << uri; + + pixmap = loadScreenshotFromUri(uri); + + // GNOME may only place the shot on the clipboard when capturing a full screen + if (pixmap.isNull()) { - qDebug() << "Screenshot image file does not exist"; - emit screenGrabbed(QPixmap{}); - return; + pixmap = readClipboardScreenshot(); } - QPixmap pixmap{file.fileName()}; - file.remove(); - - // cut requested screen - QPixmap screenshot = pixmap.copy(mScreenRect); + if (pixmap.isNull()) + { + // Clipboard might not be populated yet on some portals (e.g. GNOME fullscreen); retry shortly. + QTimer::singleShot(500, this, [this, finalizeScreenshot](){ + QPixmap delayed = readClipboardScreenshot(); + finalizeScreenshot(delayed); + }); + return; + } - emit screenGrabbed(screenshot); + finalizeScreenshot(pixmap); } void UBDesktopPortal::handleCreateSessionResponse(uint response, const QVariantMap& results) @@ -192,6 +360,7 @@ void UBDesktopPortal::handleCreateSessionResponse(uint response, const QVariantM if (response != 0) { qWarning() << "Failed to create session: " << response << results; + mSession.clear(); emit screenCastAborted(); return; } @@ -212,13 +381,17 @@ void UBDesktopPortal::handleCreateSessionResponse(uint response, const QVariantM options["types"] = MONITOR; options["cursor_mode"] = mWithCursor ? EMBEDDED : HIDDEN; options["handle_token"] = requestToken; - options["persist_mode"] = PERSISTENT; // restore token valid across application restart - auto restoreToken = UBSettings::settings()->value("App/ScreenCastRestoreToken"); - - if (restoreToken.isValid()) + if (mSupportsPersistentScreencast) { - options["restore_token"] = restoreToken; + options["persist_mode"] = PERSISTENT; // restore token valid across application restart + + auto restoreToken = UBSettings::settings()->value("App/ScreenCastRestoreToken"); + + if (restoreToken.isValid()) + { + options["restore_token"] = restoreToken; + } } // connect before call @@ -243,6 +416,7 @@ void UBDesktopPortal::handleSelectSourcesResponse(uint response, const QVariantM if (response != 0) { qWarning() << "Failed to select sources: " << response; + mSession.clear(); emit screenCastAborted(); return; } @@ -278,8 +452,6 @@ void UBDesktopPortal::handleSelectSourcesResponse(uint response, const QVariantM void UBDesktopPortal::handleStartResponse(uint response, const QVariantMap& results) { - Q_UNUSED(results); - // Show annotation drawing view in desktop mode after portal dialog was closed showGlassPane(true); @@ -287,12 +459,25 @@ void UBDesktopPortal::handleStartResponse(uint response, const QVariantMap& resu { // The system Desktop dialog was canceled qDebug() << "Failed to start or cancel dialog: " << response; + mSession.clear(); emit screenCastAborted(); return; } // save restore token - UBSettings::settings()->setValue("App/ScreenCastRestoreToken", results.value("restore_token")); + const QVariant restoreTokenVariant = results.value("restore_token"); + QString restoreToken; + + if (restoreTokenVariant.canConvert()) + { + restoreToken = restoreTokenVariant.value().variant().toString(); + } + else + { + restoreToken = restoreTokenVariant.toString(); + } + + UBSettings::settings()->setValue("App/ScreenCastRestoreToken", restoreToken); // invalidate token when screen configuration changes static bool connected{false}; @@ -341,8 +526,17 @@ QDBusInterface* UBDesktopPortal::screencastPortal() "org.freedesktop.portal.ScreenCast"); mScreencastPortal->setParent(this); - mRequestPath = "/org/freedesktop/portal/desktop/request/" + mScreencastPortal->connection().baseService().remove(0, 1).replace('.', '_') + "/"; - qDebug() << "request path" << mRequestPath; + QString baseService = QDBusConnection::sessionBus().baseService(); + baseService.remove(0, 1); + baseService.replace('.', '_'); + mRequestPath = "/org/freedesktop/portal/desktop/request/" + baseService + "/"; + + const QVariant version = mScreencastPortal->property("version"); + mScreencastPortalVersion = version.isValid() ? version.toUInt() : 0; + mSupportsPersistentScreencast = mScreencastPortalVersion >= 4; + + qDebug() << "request path" << mRequestPath << "portal version" << mScreencastPortalVersion + << "persistent support" << mSupportsPersistentScreencast; } if (mScreencastPortal->isValid()) diff --git a/src/frameworks/UBDesktopPortal.h b/src/frameworks/UBDesktopPortal.h index 157a45b86..1be0c6bef 100644 --- a/src/frameworks/UBDesktopPortal.h +++ b/src/frameworks/UBDesktopPortal.h @@ -26,6 +26,7 @@ #include #include #include +#include // forward class QDBusInterface; @@ -68,11 +69,16 @@ private slots: QString createSessionToken() const; QString createRequestToken() const; void showGlassPane(bool show) const; + QPixmap loadScreenshotFromUri(const QUrl& uri) const; + QPixmap readClipboardScreenshot() const; private: QRect mScreenRect; bool mWithCursor{false}; + bool mInteractiveScreenshot{false}; QString mSession; QString mRequestPath; + uint mScreencastPortalVersion{0}; + bool mSupportsPersistentScreencast{false}; QDBusInterface* mScreencastPortal{nullptr}; }; From 6e3179f0ba41514cff196e800b0447be0e22b36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Thu, 22 Jan 2026 14:59:51 +0100 Subject: [PATCH 105/133] mPortal linux only + fixed capture size on grab for windows --- src/core/UBDisplayManager.cpp | 5 +++++ src/podcast/UBPodcastController.cpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/core/UBDisplayManager.cpp b/src/core/UBDisplayManager.cpp index f8c47dd37..e33f159a8 100644 --- a/src/core/UBDisplayManager.cpp +++ b/src/core/UBDisplayManager.cpp @@ -711,6 +711,11 @@ void UBDisplayManager::grab(ScreenRole role, std::function callb if (scr) { + if (!rect.isValid()) + { + rect = QRect(QPoint(0, 0), scr->geometry().size()); + } + UBPlatformUtils::grabScreen(scr, callback, rect); } else diff --git a/src/podcast/UBPodcastController.cpp b/src/podcast/UBPodcastController.cpp index ac9b72a02..b15caa706 100644 --- a/src/podcast/UBPodcastController.cpp +++ b/src/podcast/UBPodcastController.cpp @@ -457,6 +457,7 @@ void UBPodcastController::stop() if (mRecordingProgressTimerEventID != 0) killTimer(mRecordingProgressTimerEventID); +#ifdef Q_OS_LINUX if (mPortal) { delete mPortal; @@ -465,6 +466,7 @@ void UBPodcastController::stop() mPortal = nullptr; mPipewireSink = nullptr; } +#endif sendLatestPixmapToEncoder(); From 3d2d77c57b15046e3ec631f6ed3db9a80547d328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Fri, 30 Jan 2026 14:49:23 +0100 Subject: [PATCH 106/133] Merging feat-screen-labals-in-preferences-display-tab remaining code --- src/core/UBDisplayManager.cpp | 43 ++---------- src/core/UBPreferencesController.cpp | 98 +++++++++++++++++++++++++++- src/core/UBPreferencesController.h | 19 ++++++ src/frameworks/UBPipewireSink.h | 1 + 4 files changed, 121 insertions(+), 40 deletions(-) diff --git a/src/core/UBDisplayManager.cpp b/src/core/UBDisplayManager.cpp index e33f159a8..58d425c19 100644 --- a/src/core/UBDisplayManager.cpp +++ b/src/core/UBDisplayManager.cpp @@ -120,7 +120,6 @@ void UBDisplayManager::createScreenLabels() const static QSize labelSize{300, 150}; const auto screens = availableScreens(); - QStringList availableScreenIndexes; int screenIndex = 1; QFont font; font.setPointSize(48); @@ -128,7 +127,6 @@ void UBDisplayManager::createScreenLabels() for (QScreen* screen : screens) { QString index = QString::number(screenIndex); - availableScreenIndexes << index; QPushButton* button = new QPushButton{mLabelParent}; button->setWindowFlag(Qt::FramelessWindowHint, true); @@ -137,6 +135,7 @@ void UBDisplayManager::createScreenLabels() button->setWindowFlag(Qt::Window, true); button->setWindowFlag(Qt::WindowDoesNotAcceptFocus, true); button->setAttribute(Qt::WA_ShowWithoutActivating, true); + button->setProperty("screenIndex", index); #ifdef QT_DEBUG button->setText(index + "(" + screen->name() + ")"); @@ -584,49 +583,17 @@ void UBDisplayManager::showScreenLabels(bool show) if (show) { - if (UBPlatformUtils::sessionType() == UBPlatformUtils::WAYLAND) - { - constexpr int positioningDelay{300}; - - // workaround: wayland window positioning only works for fullscreen - for (auto label : mScreenLabels) - { - if (label) - { - label->showFullScreen(); - } - - // we can however go back to normal later, when OS window positioning is finished - QTimer::singleShot(positioningDelay, this, [label](){ - if (label) - { - label->showNormal(); - } - }); - } - - auto parent = mScreenLabels.first()->parentWidget(); - - // make sure focus is on label's parent (screen list line edit) after labels are displayed - QTimer::singleShot(positioningDelay + 100, this, [parent](){ - parent->activateWindow(); - }); - } - else + for (auto label : mScreenLabels) { - for (auto label : mScreenLabels) + if (label) { - if (label) - { - label->showNormal(); - } + label->showNormal(); } } } else { - // workaround for wayland not supporting WindowDoesNotAcceptFocus - for (const auto label : mScreenLabels) + for (const auto &label : mScreenLabels) { if (label && label->rect().contains(QCursor::pos())) { diff --git a/src/core/UBPreferencesController.cpp b/src/core/UBPreferencesController.cpp index c2d77c268..2bfb5aa11 100644 --- a/src/core/UBPreferencesController.cpp +++ b/src/core/UBPreferencesController.cpp @@ -31,6 +31,8 @@ #include "UBSettings.h" #include "UBApplication.h" +#include +#include #include "gui/UBCircleFrame.h" @@ -38,6 +40,7 @@ #include "core/UBApplicationController.h" #include "core/UBDisplayManager.h" #include "core/UBShortcutManager.h" +#include "frameworks/UBPlatformUtils.h" #include "frameworks/UBStringUtils.h" @@ -191,6 +194,11 @@ void UBPreferencesController::adjustScreensPreferences() UBSettings::settings()->appScreenList->set(value); mPreferencesUI->screenList->loadScreenList(value.toStringList()); } + + if (mPreferencesUI->screenLayoutPreview) + { + mPreferencesUI->screenLayoutPreview->refreshScreens(); + } } void UBPreferencesController::applyShortcutFilter(const QString &filter, int filterCol) @@ -1048,7 +1056,10 @@ void UBScreenListLineEdit::loadScreenList(const QStringList &screenList) void UBScreenListLineEdit::focusInEvent(QFocusEvent *focusEvent) { QLineEdit::focusInEvent(focusEvent); - UBApplication::displayManager->showScreenLabels(true); + if (UBPlatformUtils::sessionType() != UBPlatformUtils::WAYLAND) + { + UBApplication::displayManager->showScreenLabels(true); + } if (!mValidator) { @@ -1064,7 +1075,8 @@ void UBScreenListLineEdit::focusOutEvent(QFocusEvent *focusEvent) { QLineEdit::focusOutEvent(focusEvent); - if (focusEvent->reason() != Qt::ActiveWindowFocusReason) + if (focusEvent->reason() != Qt::ActiveWindowFocusReason && + UBPlatformUtils::sessionType() != UBPlatformUtils::WAYLAND) { UBApplication::displayManager->showScreenLabels(false); } @@ -1155,3 +1167,85 @@ void UBStringListValidator::setValidationStringList(const QStringList &list) { mList = list; } + +UBScreenLayoutPreview::UBScreenLayoutPreview(QWidget* parent) + : QWidget(parent) +{ + setMinimumSize(QSize(480, 260)); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + if (UBApplication::displayManager) + { + connect(UBApplication::displayManager, &UBDisplayManager::availableScreenCountChanged, + this, &UBScreenLayoutPreview::refreshScreens); + connect(UBApplication::displayManager, &UBDisplayManager::screenLayoutChanged, + this, &UBScreenLayoutPreview::refreshScreens); + } + + refreshScreens(); +} + +void UBScreenLayoutPreview::refreshScreens() +{ + mScreens = UBApplication::displayManager ? UBApplication::displayManager->availableScreens() : QList(); + update(); +} + +void UBScreenLayoutPreview::paintEvent(QPaintEvent* event) +{ + Q_UNUSED(event); + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + + if (mScreens.isEmpty()) + { + painter.drawText(rect(), Qt::AlignCenter, tr("No displays detected")); + return; + } + + const int margin = 10; + QRectF availableRect = QRectF(rect()).adjusted(margin, margin, -margin, -margin); + + QRectF bounding; + for (QScreen* screen : mScreens) + { + bounding = bounding.isNull() ? QRectF(screen->geometry()) : bounding.united(QRectF(screen->geometry())); + } + + if (bounding.width() <= 0 || bounding.height() <= 0) + { + painter.drawText(rect(), Qt::AlignCenter, tr("Invalid display layout")); + return; + } + + const qreal scale = std::min(availableRect.width() / bounding.width(), + availableRect.height() / bounding.height()); + + const QPointF offset = availableRect.topLeft() - bounding.topLeft() * scale; + + const QColor screenColor = palette().alternateBase().color(); + const QColor primaryColor = palette().mid().color(); + const QColor borderColor = palette().mid().color().darker(120); + const QFont font = painter.font(); + + int index = 1; + for (QScreen* screen : mScreens) + { + QRectF g(screen->geometry()); + QRectF mapped(g.topLeft() * scale + offset, g.size() * scale); + + QColor fill = (screen == QGuiApplication::primaryScreen()) ? primaryColor : screenColor; + painter.setBrush(fill); + painter.setPen(QPen(borderColor, 1.0)); + painter.drawRoundedRect(mapped, 6, 6); + + painter.setPen(palette().windowText().color()); + QFont f = font; + f.setBold(true); + painter.setFont(f); + painter.drawText(mapped, Qt::AlignCenter, QString::number(index)); + + ++index; + } +} diff --git a/src/core/UBPreferencesController.h b/src/core/UBPreferencesController.h index 2245bb684..e46762996 100644 --- a/src/core/UBPreferencesController.h +++ b/src/core/UBPreferencesController.h @@ -139,6 +139,7 @@ class UBBrushPropertiesFrame : public Ui::brushProperties // forward class UBStringListValidator; +class UBScreenLayoutPreview; class UBScreenListLineEdit : public QLineEdit { @@ -183,4 +184,22 @@ class UBStringListValidator : public QValidator QStringList mList; }; +class UBScreenLayoutPreview : public QWidget +{ + Q_OBJECT; + +public: + explicit UBScreenLayoutPreview(QWidget* parent = nullptr); + ~UBScreenLayoutPreview() override = default; + +public slots: + void refreshScreens(); + +protected: + void paintEvent(QPaintEvent* event) override; + +private: + QList mScreens; +}; + #endif /* UBPREFERENCESCONTROLLER_H_ */ diff --git a/src/frameworks/UBPipewireSink.h b/src/frameworks/UBPipewireSink.h index f2539b6af..7b0fb1dde 100644 --- a/src/frameworks/UBPipewireSink.h +++ b/src/frameworks/UBPipewireSink.h @@ -27,6 +27,7 @@ #include #include +#include class UBPipewireSink : public QObject From 377ce8252d09f960c64cb9f925da047274342079 Mon Sep 17 00:00:00 2001 From: "sebastian.vallet" Date: Fri, 30 Jan 2026 22:44:13 +0100 Subject: [PATCH 107/133] Declare the missing #include in UBSvgSubsetAdaptor.h --- src/adaptors/UBSvgSubsetAdaptor.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/adaptors/UBSvgSubsetAdaptor.h b/src/adaptors/UBSvgSubsetAdaptor.h index f56049782..66913ab13 100644 --- a/src/adaptors/UBSvgSubsetAdaptor.h +++ b/src/adaptors/UBSvgSubsetAdaptor.h @@ -34,6 +34,8 @@ #include #include +#include + #include "frameworks/UBGeometryUtils.h" class UBGraphicsSvgItem; From 7f354619c24d8a073148a711e51b26fd002b6190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Mon, 2 Feb 2026 09:45:51 +0100 Subject: [PATCH 108/133] fixed preferences.ui error from previous merge --- resources/forms/preferences.ui | 338 +++++++++++++++++++-------------- 1 file changed, 198 insertions(+), 140 deletions(-) diff --git a/resources/forms/preferences.ui b/resources/forms/preferences.ui index 9ef7d9110..dd8d9ad59 100644 --- a/resources/forms/preferences.ui +++ b/resources/forms/preferences.ui @@ -82,7 +82,7 @@ - 7 + 0 @@ -98,22 +98,22 @@ 0 - -285 - 1013 - 765 + 0 + 1018 + 1200 783 - 765 + 1200 0 - 416 + 920 1011 111 @@ -181,7 +181,7 @@ 0 - 320 + 710 1011 101 @@ -252,7 +252,7 @@ 0 - 620 + 1040 1011 101 @@ -336,7 +336,7 @@ 0 - 218 + 600 1011 101 @@ -414,7 +414,7 @@ 0 - 102 + 480 1011 104 @@ -522,7 +522,7 @@ 0 - 540 + 840 1011 71 @@ -604,62 +604,115 @@ 0 0 1011 - 90 + 450 + + + 0 + 0 + + + + + 0 + 450 + + Multi display - - - - - true - - - - - - - List of screens used for Control, Display and Previous pages - - - - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - + + + + - 40 - 20 + 0 + 400 - - - - - - Show internal web page content on secondary screen or projector + + QFrame::NoFrame + + + QFrame::Plain + + + + + Qt::Vertical + + + + 20 + 10 + + + + + + + + + 0 + 0 + + + + + 600 + 300 + + + + + 900 + 800 + + + + + + + + Qt::Vertical + + + + 20 + 10 + + + + + - - - - Qt::Horizontal - - - - 40 - 20 - - - + + + + + + Show internal web page content on secondary screen or projector + + + + + + + List of screens used for Control, Display and Previous pages + + + + + + + true + + + + @@ -3320,87 +3373,87 @@ Public License instead of this License. But first, please read <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } -</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:12pt; font-weight:600;">Translations</span><span style=" font-family:'Cantarell'; font-size:10pt;"><br /></span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">A special thanks to:<br /></span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Alexander Angelov and Iva Ninova for Bulgarian</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Francesc Busquets and Toni Hortal for Catalan</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Milo Ivir for Croatian</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Jaroslav Krejčí, Janek Wagner for Czech</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Geert Kraeye and Derk Klomp for Dutch</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Christian Oïhénart for French</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Félix Díaz López for Galician </span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Hans-Peter Zahno, Klaus Tenner and Yves Kaiser for German</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Yannis Kiolalis for Greek</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Imre Fekete for Hungarian</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Antonello Comi, Marco Menardi, Marco Gregori and Salvatore Cristaldi for Italian</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Didier Clerc for Japanese</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Faraniaina Domoina Rabarijaona for Malagasy</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Patricia Fisch and César Marques for Portuguese</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Ilia Ryabokon for Russian</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Jaroslav Ryník for Slovak</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Dorian Fuentes, Juan José Gutiérrez Aparicio and Félix Díaz López for Spanish</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Anki Chen for Traditional Chinese</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Ferhat Ozkasgarli and Sabri Ünal for Turkish</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">• Alex Compit and Joonel for Ukrainian</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;"><br /></span><span style=" font-family:'Cantarell'; font-size:12pt; font-weight:600;">Resources added in OpenBoard</span></p> +</style></head><body style=" font-family:'Noto Sans',''; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:12pt; font-weight:600;">Translations</span><span style=" font-family:'Cantarell';"><br /></span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">A special thanks to:<br /></span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Alexander Angelov and Iva Ninova for Bulgarian</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Francesc Busquets and Toni Hortal for Catalan</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Milo Ivir for Croatian</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Jaroslav Krejčí, Janek Wagner for Czech</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Geert Kraeye and Derk Klomp for Dutch</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Christian Oïhénart for French</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Félix Díaz López for Galician </span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Hans-Peter Zahno, Klaus Tenner and Yves Kaiser for German</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Yannis Kiolalis for Greek</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Imre Fekete for Hungarian</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Antonello Comi, Marco Menardi, Marco Gregori and Salvatore Cristaldi for Italian</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Didier Clerc for Japanese</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Faraniaina Domoina Rabarijaona for Malagasy</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Patricia Fisch and César Marques for Portuguese</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Ilia Ryabokon for Russian</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Jaroslav Ryník for Slovak</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Dorian Fuentes, Juan José Gutiérrez Aparicio and Félix Díaz López for Spanish</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Anki Chen for Traditional Chinese</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Ferhat Ozkasgarli and Sabri Ünal for Turkish</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">• Alex Compit and Joonel for Ukrainian</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';"><br /></span><span style=" font-family:'Cantarell'; font-size:12pt; font-weight:600;">Resources added in OpenBoard</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;"><br /></span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">AndBasR.ttf </span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Sil Open Font License</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://scripts.sil.org/OFL"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">http://scripts.sil.org/OFL</span></a></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">(c) 2004-2008, SIL International (</span><a href="http://scripts.sil.org"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">http://scripts.sil.org</span></a><span style=" font-family:'Cantarell'; font-size:10pt;">), </span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">with Reserved Font Names 'Andika' and 'SIL'.</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;"><br /></span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">ec_cour.ttf </span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Open Font License</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://scripts.sil.org/OFL"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">http://scripts.sil.org/OFL</span></a></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">© Jean-Marie Douteau (</span><a href="mailto:douteau.ecolier@sfr.fr"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">douteau.ecolier@sfr.fr</span></a><span style=" font-family:'Cantarell'; font-size:10pt;">)</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Source : </span><a href="http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm</span></a></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;"><br /></span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">ecl_cour.ttf</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Open Font License</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://scripts.sil.org/OFL"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">http://scripts.sil.org/OFL</span></a></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">© Jean-Marie Douteau (</span><a href="mailto:douteau.ecolier@sfr.fr"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">douteau.ecolier@sfr.fr</span></a><span style=" font-family:'Cantarell'; font-size:10pt;">)</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Source : </span><a href="http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">AndBasR.ttf </span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Sil Open Font License</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://scripts.sil.org/OFL"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">http://scripts.sil.org/OFL</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">(c) 2004-2008, SIL International (</span><a href="http://scripts.sil.org"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">http://scripts.sil.org</span></a><span style=" font-family:'Cantarell';">), </span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">with Reserved Font Names 'Andika' and 'SIL'.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';"><br /></span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">ec_cour.ttf </span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Open Font License</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://scripts.sil.org/OFL"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">http://scripts.sil.org/OFL</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">© Jean-Marie Douteau (</span><a href="mailto:douteau.ecolier@sfr.fr"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">douteau.ecolier@sfr.fr</span></a><span style=" font-family:'Cantarell';">)</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Source : </span><a href="http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';"><br /></span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">ecl_cour.ttf</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Open Font License</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://scripts.sil.org/OFL"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">http://scripts.sil.org/OFL</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">© Jean-Marie Douteau (</span><a href="mailto:douteau.ecolier@sfr.fr"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">douteau.ecolier@sfr.fr</span></a><span style=" font-family:'Cantarell';">)</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Source : </span><a href="http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm</span></a></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;"><br /></span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#000000;">EcritureA and EcritureB</span></a></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://creativecommons.org/licenses/by/3.0/"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">Creative Commons BY-ND</span></a></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#000000;">DGESCO (</span></a><a href="mailto:degre.numerique@education.gouv.fr"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">degre.numerique@education.gouv.fr</span></a><a href="http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#000000;">)</span></a></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#000000;">Source: </span></a><a href="http://eduscol.education.fr/cid72979/polices-de-caracteres-cursives-pour-l-enseignement-de-l-ecriture.html"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">http://eduscol.education.fr/cid72979/polices-de-caracteres-cursives-pour-l-enseignement-de-l-ecriture.html</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#000000;">EcritureA and EcritureB</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://creativecommons.org/licenses/by/3.0/"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">Creative Commons BY-ND</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#000000;">DGESCO (</span></a><a href="mailto:degre.numerique@education.gouv.fr"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">degre.numerique@education.gouv.fr</span></a><a href="http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#000000;">)</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://douteau.ecolier.perso.sfr.fr/page_ecolier.htm"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#000000;">Source: </span></a><a href="http://eduscol.education.fr/cid72979/polices-de-caracteres-cursives-pour-l-enseignement-de-l-ecriture.html"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">http://eduscol.education.fr/cid72979/polices-de-caracteres-cursives-pour-l-enseignement-de-l-ecriture.html</span></a></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;"><br /></span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">GeTypo Libre</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Creative Commons BY-NC-ND</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.ge.ch/sem/cc/by-nc-nd/"><span style=" font-family:'Lucida Grande'; font-size:10pt; text-decoration: underline; color:#0000ff;">http://www.ge.ch/sem/cc/by-nc-nd/</span></a></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">© 2005-2015, Vista Multimedia SA, Droit de diffusion Etat de Genève - DIP</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://edu.ge.ch/sem/node/1294"><span style=" font-family:'Lucida Grande'; font-size:10pt; text-decoration: underline; color:#0000ff;">http://edu.ge.ch/sem/node/1294</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">GeTypo Libre</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Creative Commons BY-NC-ND</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.ge.ch/sem/cc/by-nc-nd/"><span style=" font-family:'Lucida Grande'; text-decoration: underline; color:#0000ff;">http://www.ge.ch/sem/cc/by-nc-nd/</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">© 2005-2015, Vista Multimedia SA, Droit de diffusion Etat de Genève - DIP</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://edu.ge.ch/sem/node/1294"><span style=" font-family:'Lucida Grande'; text-decoration: underline; color:#0000ff;">http://edu.ge.ch/sem/node/1294</span></a></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;"><br /></span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">GraphMe Widget 2.1</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">Yannick Vessaz</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">GraphMe Widget 2.1</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">Yannick Vessaz</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;"><br /></span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Papier.wgt 2.5.4</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Developed by F. Le Cléac’h </span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Papier.wgt 2.5.4</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Developed by F. Le Cléac’h </span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://creativecommons.org/licenses/by-nc-sa/3.0/"><span style=" font-family:'Ubuntu'; font-size:11pt; text-decoration: underline; color:#0000ff;">Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)</span></a></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://www.openedu.fr"><span style=" font-family:'Ubuntu'; font-size:11pt; text-decoration: underline; color:#0000ff;">https://www.openedu.fr</span></a></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;"><br /></span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;"><br /></span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">QR-Code Widget</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">Basilstotz</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">Licence: CCO</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">QR-Code Widget</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">Basilstotz</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">Licence: CCO</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;"><br /></span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt; color:#000000;">Sonata para piano (.mp3)</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt; color:#000000;">Óscar G. Villegas</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://creativecommons.org/licenses/by-nc-sa/3.0/es"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">Creative Commons Attribution-NonCommercial-Share Alike 3.0 Unported</span></a></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://recursostic.educacion.es/bancoimagenes/web/"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">http://recursostic.educacion.es/bancoimagenes/web/</span></a><span style=" font-family:'Cantarell'; font-size:10pt;"><br /></span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; color:#000000;">Sonata para piano (.mp3)</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; color:#000000;">Óscar G. Villegas</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://creativecommons.org/licenses/by-nc-sa/3.0/es"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">Creative Commons Attribution-NonCommercial-Share Alike 3.0 Unported</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://recursostic.educacion.es/bancoimagenes/web/"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">http://recursostic.educacion.es/bancoimagenes/web/</span></a><span style=" font-family:'Cantarell';"><br /></span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;"><br /></span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">wannaworktogether (.mp4)</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Creative Commons</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://creativecommons.org/licenses/by/2.5/"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">Creative Commons Attribution</span></a></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://creativecommons.org/videos/wanna-work-together"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">http://creativecommons.org/videos/wanna-work-together</span></a></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;"><br /></span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Worldmap_wdb_combined (.svg)</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">David Eccles (gringer)</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://creativecommons.org/licenses/by-sa/3.0/deed.en"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">Creative Commons Attribution-Share Alike 3.0 Unported</span></a></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://commons.wikimedia.org/wiki/File:Worldmap_wdb_combined.svg"><span style=" font-family:'Cantarell'; font-size:10pt; text-decoration: underline; color:#0000ff;">http://commons.wikimedia.org/wiki/File:Worldmap_wdb_combined.svg</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">wannaworktogether (.mp4)</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Creative Commons</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://creativecommons.org/licenses/by/2.5/"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">Creative Commons Attribution</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://creativecommons.org/videos/wanna-work-together"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">http://creativecommons.org/videos/wanna-work-together</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';"><br /></span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Worldmap_wdb_combined (.svg)</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">David Eccles (gringer)</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://creativecommons.org/licenses/by-sa/3.0/deed.en"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">Creative Commons Attribution-Share Alike 3.0 Unported</span></a></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://commons.wikimedia.org/wiki/File:Worldmap_wdb_combined.svg"><span style=" font-family:'Cantarell'; text-decoration: underline; color:#0000ff;">http://commons.wikimedia.org/wiki/File:Worldmap_wdb_combined.svg</span></a></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:11pt;"><br /></span></p></body></html> @@ -3425,23 +3478,23 @@ hr { height: 1px; border-width: 0; } <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } -</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'Noto Sans',''; font-size:10pt; font-weight:400; font-style:normal;"> <table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> <tr> <td style="border: none;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">OpenBoard is copyright © 2022. All rights reserved.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Cantarell'; font-size:10pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">OpenBoard is derived from Open-Sankoré. Open-Sankoré is copyright © 2010-2015 Groupement d'Intérêt Public pour l'Education Numérique en Afrique (GIP ENA). All right reserved.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Cantarell'; font-size:10pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">OpenBoard is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License, with a specific linking exception for the OpenSSL project's &quot;OpenSSL&quot; library (or with modified versions of it that use the same license as the &quot;OpenSSL&quot; library). You can find the source code of this software at </span><a href="https://github.com/DIP-SEM/OpenBoard"><span style=" font-family:'.Helvetica Neue DeskInterface'; font-size:10pt; text-decoration: underline; color:#0000ff;">github.com/OpenBoard-org</span></a><span style=" font-family:'Cantarell'; font-size:10pt;">. </span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">OpenBoard is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License below for more details.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Cantarell'; font-size:10pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Contact :</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Service écoles-médias</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Rue des Gazomètres 5</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Case Postale 241</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">1211 Genève 8</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:10pt;">Switzerland</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">OpenBoard is copyright © 2022. All rights reserved.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Cantarell';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">OpenBoard is derived from Open-Sankoré. Open-Sankoré is copyright © 2010-2015 Groupement d'Intérêt Public pour l'Education Numérique en Afrique (GIP ENA). All right reserved.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Cantarell';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">OpenBoard is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License, with a specific linking exception for the OpenSSL project's &quot;OpenSSL&quot; library (or with modified versions of it that use the same license as the &quot;OpenSSL&quot; library). You can find the source code of this software at </span><a href="https://github.com/DIP-SEM/OpenBoard"><span style=" font-family:'.Helvetica Neue DeskInterface'; text-decoration: underline; color:#0000ff;">github.com/OpenBoard-org</span></a><span style=" font-family:'Cantarell';">. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">OpenBoard is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License below for more details.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Cantarell';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Contact :</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Service écoles-médias</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Rue des Gazomètres 5</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Case Postale 241</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">1211 Genève 8</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';">Switzerland</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.openboard.ch"><span style=" font-family:'.Helvetica Neue DeskInterface'; font-size:11pt; text-decoration: underline; color:#0000ff;">openboard.ch</span></a></p></td></tr></table></body></html> @@ -3509,6 +3562,11 @@ hr { height: 1px; border-width: 0; } UBPreferredBackgroundWidget QWidget
gui/UBPreferredBackgroundWidget.h
+ + + UBScreenLayoutPreview + QWidget +
core/UBPreferencesController.h
1
From ac361d45d144cbc5175490b05cbc0b4c6847aa0d Mon Sep 17 00:00:00 2001 From: Vekhir Date: Tue, 3 Feb 2026 09:07:01 +0100 Subject: [PATCH 109/133] refactor(preferences.ui): Widget names should be unique --- resources/forms/preferences.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/forms/preferences.ui b/resources/forms/preferences.ui index dd8d9ad59..d470f3b16 100644 --- a/resources/forms/preferences.ui +++ b/resources/forms/preferences.ui @@ -1175,7 +1175,7 @@ QScrollArea:disabled {border: 1px solid red;} - + 0 From 64c9e3572616c05ac300a0e30480c89f5206e27e Mon Sep 17 00:00:00 2001 From: Vekhir Date: Tue, 3 Feb 2026 09:21:53 +0100 Subject: [PATCH 110/133] refactor: use different setContent overload The old version of setContent had separate overloads to specify whether to use namespace processing or not. This, among other options, can now be specified via ParseOptions which were introduced in Qt 6.5. --- src/gui/UBBackgroundManager.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/gui/UBBackgroundManager.cpp b/src/gui/UBBackgroundManager.cpp index 7e32abeb4..0b7839f16 100644 --- a/src/gui/UBBackgroundManager.cpp +++ b/src/gui/UBBackgroundManager.cpp @@ -300,8 +300,12 @@ QPixmap UBBackgroundManager::createButtonPixmap(const QDomDocument& bgDoc, bool } QDomDocument doc; - - if (!doc.setContent(&templateFile, true)) +#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) + auto result = doc.setContent(&templateFile, QDomDocument::ParseOption::UseNamespaceProcessing); +#else + auto result = doc.setContent(&templateFile, true) +#endif + if (!result) { qWarning() << "Cannot load template file" << templateFile.fileName(); return {}; From 73df558e843ebdc945bacd2ee11d6c45b7e26092 Mon Sep 17 00:00:00 2001 From: sebojolais Date: Tue, 3 Feb 2026 17:58:13 +0100 Subject: [PATCH 111/133] Fix missing ; in UBBackgroundManager.cpp --- src/gui/UBBackgroundManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/UBBackgroundManager.cpp b/src/gui/UBBackgroundManager.cpp index 0b7839f16..bf3fb01d6 100644 --- a/src/gui/UBBackgroundManager.cpp +++ b/src/gui/UBBackgroundManager.cpp @@ -303,7 +303,7 @@ QPixmap UBBackgroundManager::createButtonPixmap(const QDomDocument& bgDoc, bool #if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) auto result = doc.setContent(&templateFile, QDomDocument::ParseOption::UseNamespaceProcessing); #else - auto result = doc.setContent(&templateFile, true) + auto result = doc.setContent(&templateFile, true); #endif if (!result) { From c8208882c4f61357f71601332917f78c3db450c7 Mon Sep 17 00:00:00 2001 From: Giovanni Fasano <46658414+Gvf63@users.noreply.github.com> Date: Sat, 7 Feb 2026 12:41:21 +0100 Subject: [PATCH 112/133] Update OpenBoard_it.ts fixed some translations --- resources/i18n/OpenBoard_it.ts | 74 +++++++++++++++++----------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/resources/i18n/OpenBoard_it.ts b/resources/i18n/OpenBoard_it.ts index 62dd8ac8f..04c1ff796 100644 --- a/resources/i18n/OpenBoard_it.ts +++ b/resources/i18n/OpenBoard_it.ts @@ -44,9 +44,9 @@ If you wish so, you may continue with an unverified certificate. Accepting an unverified certificate mean you may not be connected with the host you tried to connect to. Do you wish to override the security check and continue ? - Se vuoi, puoi prosseguire con un certificato non attestato. Accettare un certificato non attestato implica che potresti non essere connesso all'host al quale cerchi di accedere. + Se vuoi, puoi proseguire con un certificato non verificato. Accettare un certificato non verificato implica che potresti non essere connesso all'host al quale cerchi di accedere. - Vuoi comunque prosseguire ? + Vuoi comunque proseguire ? @@ -64,7 +64,7 @@ Do you wish to override the security check and continue ? Save as - Salvaguardare sotto + Salva come @@ -84,22 +84,22 @@ Do you wish to override the security check and continue ? %L1 B - %L1 o + %L1 B %L1 KiB - %L1 ko + %L1 KiB %L1 MiB - %L1 Mo + %L1 MiB %L1 GiB - %L1 Go + %L1 GiB @@ -119,7 +119,7 @@ Do you wish to override the security check and continue ? cancelled - %1 downloaded - %2/s - Anullato - %1 downloaded - %2/s + Annullato - %1 downloaded - %2/s @@ -134,7 +134,7 @@ Do you wish to override the security check and continue ? Remove from list - Ritirare dalla lista + Rimuovere dalla lista @@ -1790,12 +1790,12 @@ Do you wish to override the security check and continue ? Complete deletion of %1 documents/folders - Cancellazione definitiva des %1 documenti/folders + Cancellazione definitiva dei %1 documenti/folders You are about to permanantly delete %1 documents and/or folders. Are you sure ? - Stai per cancellare definitivamente %1 documenti et/o folders. Sei sicuro ? + Stai per cancellare definitivamente %1 documenti e/o folders. Sei sicuro ? @@ -2120,7 +2120,7 @@ Dando un nuovo nome si creerà un nuovo documento. Warnings during export was appeared - È apparso un avviso durante l'esportazione + Sono apparsi avvisi durante l'esportazione @@ -2504,12 +2504,12 @@ Dando un nuovo nome si creerà un nuovo documento. Layer up - stratificare + Strato verso l'alto Layer down - strato verso il basso + Strato verso il basso @@ -3034,7 +3034,7 @@ Vuoi ignorare gli errori per questo host? Background - Fondi + Sfondi @@ -3099,17 +3099,17 @@ Vuoi ignorare gli errori per questo host? Scroll page up - Scorri verso l'alto + Scorri la pagina verso l'alto Scroll down - Scorrere verso il basso + Scorri verso il basso Scroll page down - Scorrere verso il basso + Scorri la pagina verso il basso @@ -3129,7 +3129,7 @@ Vuoi ignorare gli errori per questo host? Key Sequence - Sequenza di tastiera + Sequenza di tasti @@ -3175,7 +3175,7 @@ Vuoi ignorare gli errori per questo host? Task MouseButton - Macchia + Compito @@ -3224,7 +3224,7 @@ Vuoi ignorare gli errori per questo host? Generating preview thumbnails ... - Generazione della miniatura di anteprima in corso... + Generazione delle miniature di anteprima in corso... @@ -3366,7 +3366,7 @@ Si prega di riavviare l'applicazione per accedere ai documenti aggiornati.< Open Web Inspector - Aprier l’ispettore Web + Aprire l’ispettore Web @@ -3470,7 +3470,7 @@ Si prega di riavviare l'applicazione per accedere ai documenti aggiornati.< Bottom layer limit reached - Limite del livello inferiore raggiunto + Raggiunto il limite inferiore degli strati @@ -3520,48 +3520,48 @@ Si prega di riavviare l'applicazione per accedere ai documenti aggiornati.< Enter username and password for "%1" at %2 - Entra l’utente e la password per «%1» a %2 + Inserisci l’utente e la password per «%1» a %2 Allow %1 to access your location information? - Autorizzare %1 ad accedere alla tua posizione ? + Autorizza %1 ad accedere alla tua posizione ? Allow %1 to access your microphone? - Autorizzare %1 ad accedere al tuo microfono ? + Autorizza %1 ad accedere al tuo microfono ? Allow %1 to access your webcam? - Autorizzare %1 ad accedere alla tua webcam ? + Autorizza %1 ad accedere alla tua webcam ? Allow %1 to access your microphone and webcam? - Autorizzare %1 ad accedere al tuo microfono ed alla tua webcam ? + Autorizza %1 ad accedere al tuo microfono ed alla tua webcam ? Allow %1 to lock your mouse cursor? - Autorizzare %1 a bloccare il cursore della tua mouse ? + Autorizza %1 a bloccare il cursore del tuo mouse ? Allow %1 to capture video of your desktop? - Autorizzare %1 a fare una cattura video del tuo desktop ? + Autorizza %1 a catturare un video del tuo desktop ? Allow %1 to capture audio and video of your desktop? - Autorizzare %1 a fare una cattura audio e video del tuo desktop ? + Autorizza %1 a catturare audio e video del tuo desktop ? Permission Request - Chiedere l’autorizzazione + Richiesta di autorizzazione @@ -3579,22 +3579,22 @@ Si prega di riavviare l'applicazione per accedere ai documenti aggiornati.< Render process normal exit - Uscita normale del procedimento resa + Uscita normale del procedimento di rendering Render process abnormal exit - Uscita anomala del procedimento di resa + Uscita anomala del procedimento di rendering Render process crashed - Il procedimento di resa ha subito un crash + Il procedimento di rendering ha subito un crash Render process killed - Il procedimento di resa si è fermato + Procedimento di rendering interrotto @@ -4062,7 +4062,7 @@ p, li { white-space: pre-wrap; } List of screens used for Control, Display and Previous pages - Lista degli schermi utilizzati per le visualizzazioni Principale, Esteso ePpagine precedenti + Lista degli schermi utilizzati per le visualizzazioni Principale, Esteso e Pagine precedenti From 54dbd7fefa034640cd4608db54bd7ebb9dcc9dab Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 8 Dec 2025 07:39:29 +0100 Subject: [PATCH 113/133] fix: index checks for UBDocument - return boolean success indicator for page operations - add parameter to suppress confirmation dialog when deleting pages - create TOC assets entry when creating a page - create thumbnail when creating a page - add common function to UBDocumentToc to check index bounds Signed-off-by: letsfindaway --- src/document/UBDocument.cpp | 167 ++++++++++++++++++++------------- src/document/UBDocument.h | 10 +- src/document/UBDocumentToc.cpp | 49 +++++----- src/document/UBDocumentToc.h | 1 + 4 files changed, 133 insertions(+), 94 deletions(-) diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index 299898149..7bd4fd5a1 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -73,43 +73,60 @@ std::shared_ptr UBDocument::proxy() const return mProxy; } -void UBDocument::deletePages(QList indexes) +bool UBDocument::deletePages(QList indexes, bool approve) { if (indexes.isEmpty()) { - return; + return true; } - bool accepted{false}; - - if (indexes.size() > 1) - { - accepted = UBApplication::mainWindow->yesNoQuestion( - UBDocumentController::tr("Moving %1 pages of the document \"%2\" to trash") - .arg(QString::number(indexes.size()), mProxy->name()), - UBDocumentController::tr("You are about to move %1 pages of the document \"%2\" to trash. Are you sure ?") - .arg(QString::number(indexes.size()), mProxy->name()), - QPixmap(":/images/trash-document-page.png")); - } - else + if (approve) { - accepted = UBApplication::mainWindow->yesNoQuestion( - UBDocumentController::tr("Remove page %1").arg(indexes.at(0) + 1), - UBDocumentController::tr("You are about to remove page %1 of the document \"%2\". Are you sure ?") - .arg(indexes.at(0) + 1) - .arg(mProxy->name()), - QPixmap(":/images/trash-document-page.png")); - } + bool accepted{false}; - if (!accepted) - { - return; + if (indexes.size() > 1) + { + accepted = UBApplication::mainWindow->yesNoQuestion( + UBDocumentController::tr("Moving %1 pages of the document \"%2\" to trash") + .arg(QString::number(indexes.size()), mProxy->name()), + UBDocumentController::tr("You are about to move %1 pages of the document \"%2\" to trash. Are you sure ?") + .arg(QString::number(indexes.size()), mProxy->name()), + QPixmap(":/images/trash-document-page.png")); + } + else + { + accepted = UBApplication::mainWindow->yesNoQuestion( + UBDocumentController::tr("Remove page %1").arg(indexes.at(0) + 1), + UBDocumentController::tr("You are about to remove page %1 of the document \"%2\". Are you sure ?") + .arg(indexes.at(0) + 1) + .arg(mProxy->name()), + QPixmap(":/images/trash-document-page.png")); + } + + if (!accepted) + { + return false; + } } // sort list, remove duplicates std::sort(indexes.begin(), indexes.end()); indexes.erase(std::unique(indexes.begin(), indexes.end()), indexes.end()); + // check bounds + if (indexes.first() < 0 || indexes.last() >= pageCount()) + { + return false; + } + + // decline attempt to remove all pages + if (indexes.count() == pageCount()) + { + // deleting all pages is blocked in the UI. Just log if it happens anyway + qWarning() << "UBDocument::deletePages: declined attempt to remove all pages of a document"; + return false; + } + // copy to-be-deleted pages to trash document QString sourceName = mProxy->metaData(UBSettings::documentName).toString(); auto trashDocProxy = UBPersistenceManager::persistenceManager()->createDocument(UBSettings::trashedDocumentGroupNamePrefix, sourceName, false); @@ -124,53 +141,59 @@ void UBDocument::deletePages(QList indexes) } // delete the scenes - if (pageIds.count() == pageCount()) - { - // deleting all pages is blocked in the UI. Just log if it happens anyway - qWarning() << "UBDocument::deletePages: declined attempt to remove all pages of a document"; - return; - } - UBPersistenceManager::persistenceManager()->deleteDocumentScenes(mProxy, pageIds); assureHeaderLoaderFinished(); for (int i = indexes.size() - 1; i >= 0; --i) { - mToc->remove(indexes.at(i)); - thumbnailScene()->deleteThumbnail(indexes.at(i), false); - emit UBPersistenceManager::persistenceManager()->documentSceneDeleted(this, indexes.at(i)); + const auto index{indexes.at(i)}; + mToc->remove(index); + thumbnailScene()->deleteThumbnail(index, false); + emit UBPersistenceManager::persistenceManager()->documentSceneDeleted(this, index); } thumbnailScene()->renumberThumbnails(indexes.first()); thumbnailScene()->arrangeThumbnails(indexes.first()); mToc->save(); + return true; } -void UBDocument::duplicatePage(int index) +bool UBDocument::duplicatePage(int index) { - copyPage(index, this, index + 1); - emit UBPersistenceManager::persistenceManager()->documentSceneDuplicated(this, index + 1); + if (copyPage(index, this, index + 1)) + { + emit UBPersistenceManager::persistenceManager()->documentSceneDuplicated(this, index + 1); + return true; + } + + return false; } -void UBDocument::movePage(int fromIndex, int toIndex) +bool UBDocument::movePage(int fromIndex, int toIndex) { - auto scene = getScene(fromIndex); - - if (scene && scene->isModified()) + if (mToc->isValidIndex(fromIndex) && mToc->isValidIndex(toIndex)) { - persistPage(scene, fromIndex); + auto scene = getScene(fromIndex); + + if (scene && scene->isModified()) + { + persistPage(scene, fromIndex); + } + + assureHeaderLoaderFinished(); + thumbnailScene()->moveThumbnail(fromIndex, toIndex); + mToc->move(fromIndex, toIndex); + mToc->save(); + emit UBPersistenceManager::persistenceManager()->documentSceneMoved(this, fromIndex, toIndex); + return true; } - assureHeaderLoaderFinished(); - thumbnailScene()->moveThumbnail(fromIndex, toIndex); - mToc->move(fromIndex, toIndex); - mToc->save(); - emit UBPersistenceManager::persistenceManager()->documentSceneMoved(this, fromIndex, toIndex); + return false; } -void UBDocument::copyPage(int fromIndex, std::shared_ptr to, int toIndex) +bool UBDocument::copyPage(int fromIndex, std::shared_ptr to, int toIndex) { - copyPage(fromIndex, to.get(), toIndex); + return copyPage(fromIndex, to.get(), toIndex); } std::shared_ptr UBDocument::createPage(int index, bool saveToc, bool cached, bool useUndoRedoStack) @@ -178,8 +201,15 @@ std::shared_ptr UBDocument::createPage(int index, bool saveToc, // create a new TOC entry for the page assureHeaderLoaderFinished(); auto pageId = mToc->insert(index); + + if (pageId < 0) + { + return nullptr; + } + auto scene = UBPersistenceManager::persistenceManager()->createDocumentSceneAt(mProxy, pageId, cached, useUndoRedoStack); mToc->setUuid(index, scene->uuid()); + mToc->setAssets(index, {}); if (saveToc) { @@ -187,6 +217,7 @@ std::shared_ptr UBDocument::createPage(int index, bool saveToc, } thumbnailScene()->insertThumbnail(index, false); + mThumbnailScene->ensureThumbnail(index, scene.get()); return scene; } @@ -303,7 +334,7 @@ UBDocumentToc* UBDocument::toc() } // scan assets if missing - for (int index = 0; index < mToc->pageCount(); ++index) + for (int index = 0; index < pageCount(); ++index) { if (!mToc->hasAssetsEntry(index)) { @@ -428,7 +459,7 @@ void UBDocument::scanAssets() const auto persistenceManager = UBPersistenceManager::persistenceManager(); persistenceManager->waitForAllSaved(); - for (int index = 0; index < mToc->pageCount(); ++index) + for (int index = 0; index < pageCount(); ++index) { if (!mToc->hasAssetsEntry(index)) { @@ -444,7 +475,7 @@ void UBDocument::scanAssets() mSceneAssetLoader = new UBBackgroundLoader{UBBackgroundLoader::ByteArray}; QObject::connect(mSceneAssetLoader, &UBBackgroundLoader::resultAvailable, mSceneAssetLoader, [this](int pageId, const QVariant& data){ - UBApplication::showMessage(UBDocumentController::tr("Scanning page %1 of %2").arg(pageId).arg(mToc->pageCount()), true); + UBApplication::showMessage(UBDocumentController::tr("Scanning page %1 of %2").arg(pageId).arg(pageCount()), true); if (pageId >= 0 && !data.isNull()) { @@ -656,22 +687,28 @@ void UBDocument::scan(bool tocPresent) QApplication::restoreOverrideCursor(); } -void UBDocument::copyPage(int fromIndex, UBDocument* to, int toIndex) +bool UBDocument::copyPage(int fromIndex, UBDocument* to, int toIndex) { - const auto dependencies = pageRelativeDependencies(fromIndex); + if (mToc->isValidIndex(fromIndex) && to->mToc->isValidIndex(toIndex)) + { + const auto dependencies = pageRelativeDependencies(fromIndex); - // copy scene - to->assureHeaderLoaderFinished(); - const auto pageId = to->mToc->insert(toIndex); - const auto uuid = UBPersistenceManager::persistenceManager()->copyDocumentScene(mProxy, mToc->pageId(fromIndex), to->proxy(), pageId, dependencies); + // copy scene + to->assureHeaderLoaderFinished(); + const auto pageId = to->mToc->insert(toIndex); + const auto uuid = UBPersistenceManager::persistenceManager()->copyDocumentScene(mProxy, mToc->pageId(fromIndex), to->proxy(), pageId, dependencies); - // add thumbnail - to->thumbnailScene()->insertThumbnail(toIndex); + // update target TOC + to->mToc->setUuid(toIndex, uuid); + to->mToc->setAssets(toIndex, dependencies); + to->mToc->save(); + + // add thumbnail + to->thumbnailScene()->insertThumbnail(toIndex); + return true; + } - // update target TOC - to->mToc->setUuid(toIndex, uuid); - to->mToc->setAssets(toIndex, dependencies); - to->mToc->save(); + return false; } void UBDocument::deleteUnreferencedAssets() @@ -679,7 +716,7 @@ void UBDocument::deleteUnreferencedAssets() // Go through the TOC and create a set of all referenced media assets. QSet referencedMediaAssets; - for (int index = 0; index < mToc->pageCount(); ++index) + for (int index = 0; index < pageCount(); ++index) { if (!mToc->hasAssetsEntry(index)) { diff --git a/src/document/UBDocument.h b/src/document/UBDocument.h index 2956d7d73..c055ba7cd 100644 --- a/src/document/UBDocument.h +++ b/src/document/UBDocument.h @@ -59,10 +59,10 @@ class UBDocument : public std::enable_shared_from_this std::shared_ptr proxy() const; - void deletePages(QList indexes); - void duplicatePage(int index); - void movePage(int fromIndex, int toIndex); - void copyPage(int fromIndex, std::shared_ptr to, int toIndex); + bool deletePages(QList indexes, bool approve = true); + bool duplicatePage(int index); + bool movePage(int fromIndex, int toIndex); + bool copyPage(int fromIndex, std::shared_ptr to, int toIndex); std::shared_ptr createPage(int index, bool saveToc = true, bool cached = true, bool useUndoRedoStack = true); void persistPage(std::shared_ptr scene, int index, bool isAutomaticBackup = false, @@ -85,7 +85,7 @@ class UBDocument : public std::enable_shared_from_this private: void scan(bool tocPresent); - void copyPage(int fromIndex, UBDocument* to, int toIndex); + bool copyPage(int fromIndex, UBDocument* to, int toIndex); void deleteUnreferencedAssets(); void assureHeaderLoaderFinished(bool visualFeedback = true); diff --git a/src/document/UBDocumentToc.cpp b/src/document/UBDocumentToc.cpp index 76b02ca32..5db2e147a 100644 --- a/src/document/UBDocumentToc.cpp +++ b/src/document/UBDocumentToc.cpp @@ -67,20 +67,18 @@ int UBDocumentToc::insert(int index) void UBDocumentToc::move(int fromIndex, int toIndex) { - if (fromIndex < 0 || fromIndex >= mToc.count() || toIndex < 0 || toIndex >= mToc.count()) + if (isValidIndex(fromIndex) && isValidIndex(toIndex)) { - return; + auto entry = mToc.at(fromIndex); + mToc.removeAt(fromIndex); + mToc.insert(toIndex, entry); + mModified = true; } - - auto entry = mToc.at(fromIndex); - mToc.removeAt(fromIndex); - mToc.insert(toIndex, entry); - mModified = true; } void UBDocumentToc::remove(int index) { - if (index >= 0 && index < mToc.count()) + if (isValidIndex(index)) { mToc.remove(index); mModified = true; @@ -89,12 +87,12 @@ void UBDocumentToc::remove(int index) QUuid UBDocumentToc::uuid(int index) const { - if (index < 0 || index >= mToc.count()) + if (isValidIndex(index)) { - return {}; + return mToc.at(index).value(UUID).toUuid(); } - return mToc.at(index).value(UUID).toUuid(); + return {}; } void UBDocumentToc::setUuid(int index, const QUuid& uuid) @@ -124,12 +122,12 @@ int UBDocumentToc::findUuid(const QUuid& sceneUuid) const int UBDocumentToc::pageId(int index) const { - if (index < 0 || index >= mToc.count()) + if (isValidIndex(index)) { - return -1; + return mToc.at(index).value(PAGE_ID).toInt(); } - return mToc.at(index).value(PAGE_ID).toInt(); + return -1; } void UBDocumentToc::setPageId(int index, int pageId) @@ -146,12 +144,12 @@ void UBDocumentToc::setPageId(int index, int pageId) QStringList UBDocumentToc::assets(int index) const { - if (index < 0 || index >= mToc.count()) + if (isValidIndex(index)) { - return {}; + return mToc.at(index).value(ASSETS).toStringList(); } - return mToc.at(index).value(ASSETS).toStringList(); + return {}; } void UBDocumentToc::setAssets(int index, const QStringList& assets) @@ -168,17 +166,15 @@ void UBDocumentToc::setAssets(int index, const QStringList& assets) void UBDocumentToc::unsetAssets(int index) { - mToc[index].remove(ASSETS); + if (isValidIndex(index)) + { + mToc[index].remove(ASSETS); + } } bool UBDocumentToc::hasAssetsEntry(int index) const { - if (index < 0 || index >= mToc.count()) - { - return false; - } - - return mToc.at(index).contains(ASSETS); + return isValidIndex(index) && mToc.at(index).contains(ASSETS); } bool UBDocumentToc::load() @@ -210,6 +206,11 @@ int UBDocumentToc::nextAvailablePageId() return mNextAvailablePageId++; } +bool UBDocumentToc::isValidIndex(int index) const +{ + return index >= 0 && index < mToc.count(); +} + void UBDocumentToc::assureSize(int index) { if (index >= mToc.count()) diff --git a/src/document/UBDocumentToc.h b/src/document/UBDocumentToc.h index 49b2beded..e5ce1f9f4 100644 --- a/src/document/UBDocumentToc.h +++ b/src/document/UBDocumentToc.h @@ -65,6 +65,7 @@ class UBDocumentToc // next available pageId int nextAvailablePageId(); + bool isValidIndex(int index) const; private: void assureSize(int index); From e0211bb90a626a18f15c8f8b30c7aa8c43979438 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 8 Dec 2025 08:43:04 +0100 Subject: [PATCH 114/133] fix: crash when deleting current page - do not attempt to save current page when it was deleted - set mDeletingSceneIndex while switching to other scene - remove `UBBoardController::deleteScene()` as it is no longer used - remove `UBBoardController::setActiveSceneIndex` as it is not used and would break internal consistency of the board controller Signed-off-by: letsfindaway --- src/board/UBBoardController.cpp | 33 ++------------------------------- src/board/UBBoardController.h | 2 -- 2 files changed, 2 insertions(+), 33 deletions(-) diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index 353d0b9ca..bab59bddf 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -566,7 +566,9 @@ void UBBoardController::documentSceneDeleted(UBDocument* document, int index) if (UBApplication::applicationController->displayMode() == UBApplicationController::Board) { // directly change scene + mDeletingSceneIndex = index; setActiveDocumentScene(nextSceneIndex); + mDeletingSceneIndex = -1; } else { @@ -796,32 +798,6 @@ UBGraphicsItem *UBBoardController::duplicateItem(UBItem *item) return retItem; } -void UBBoardController::deleteScene(int nIndex) -{ - auto document = UBDocument::getDocument(selectedDocument()); - - if (document->pageCount() >= 2) - { - mDeletingSceneIndex = nIndex; - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - persistCurrentScene(); - UBApplication::showMessage(tr("Deleting page %1").arg(nIndex+1), true); - - document->deletePages({nIndex}); - - QDateTime now = QDateTime::currentDateTime(); - selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(now)); - UBMetadataDcSubsetAdaptor::persist(selectedDocument()); - - if (nIndex >= document->pageCount()) - nIndex = document->pageCount()-1; - setActiveDocumentScene(nIndex); - UBApplication::showMessage(tr("Page %1 deleted").arg(nIndex+1)); - QApplication::restoreOverrideCursor(); - mDeletingSceneIndex = -1; - } -} - void UBBoardController::clearScene() { @@ -1804,11 +1780,6 @@ int UBBoardController::activeSceneIndex() const return mActiveSceneIndex; } -void UBBoardController::setActiveSceneIndex(int i) -{ - mActiveSceneIndex = i; -} - void UBBoardController::documentSceneChanged(std::shared_ptr pDocumentProxy, int pIndex) { Q_UNUSED(pIndex); diff --git a/src/board/UBBoardController.h b/src/board/UBBoardController.h index 7b1a22568..b427fd726 100644 --- a/src/board/UBBoardController.h +++ b/src/board/UBBoardController.h @@ -84,7 +84,6 @@ class UBBoardController : public UBDocumentContainer std::shared_ptr activeScene() const; int activeSceneIndex() const; - void setActiveSceneIndex(int i); void closing(); int currentPage() const; @@ -188,7 +187,6 @@ class UBBoardController : public UBDocumentContainer void duplicateScene(int index); UBGraphicsItem *duplicateItem(UBItem *item); - void deleteScene(int index); bool cacheIsVisible() const {return mCacheWidgetIsEnabled;} From e66c414b3003a179e12519d37b0d41c87b7b4360 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 23 Feb 2026 18:03:00 +0100 Subject: [PATCH 115/133] fix: add to document thumbnails - thumbnails are not created after adding objects using add to document in document mode or import from board mode - remove asset entries from TOC and force scanning new pages - same as during import --- src/core/UBDocumentManager.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/core/UBDocumentManager.cpp b/src/core/UBDocumentManager.cpp index 963de8065..7a3ec4cd6 100644 --- a/src/core/UBDocumentManager.cpp +++ b/src/core/UBDocumentManager.cpp @@ -320,7 +320,15 @@ int UBDocumentManager::addFilesToDocument(std::shared_ptr docum } UBPersistenceManager::persistenceManager()->persistDocumentMetadata(document); + + // remove all asset entries from new pages to force scanning + for (int index = currentNumberOfPages; index < doc->pageCount(); ++index) + { + doc->toc()->unsetAssets(index); + } + doc->toc()->save(); + doc->scanAssets(); UBApplication::showMessage(tr("Import of file %1 successful.").arg(file.fileName())); nImportedDocuments++; break; From c41a6d5c753b4e4f328ec86450a4c5b9fe3070f7 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 23 Feb 2026 18:06:06 +0100 Subject: [PATCH 116/133] fix: size of imported image - when using add to document in document mode to add an image or a set of images, the resulting images may be scaled wrongly and just appear as small dot - UBGraphicsScene::scaleToFitDocumentSize may use an uninitialized mNominalSize - Use nominalSize() instead to guarantee an initialized value Signed-off-by: letsfindaway --- src/domain/UBGraphicsScene.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/domain/UBGraphicsScene.cpp b/src/domain/UBGraphicsScene.cpp index 523c7f0af..47d26c643 100644 --- a/src/domain/UBGraphicsScene.cpp +++ b/src/domain/UBGraphicsScene.cpp @@ -2183,8 +2183,8 @@ const UBBackgroundRuling* UBGraphicsScene::background() const QGraphicsItem* UBGraphicsScene::scaleToFitDocumentSize(QGraphicsItem* item, bool center, int margin, bool expand) { - int maxWidth = mNominalSize.width() - (margin * 2); - int maxHeight = mNominalSize.height() - (margin * 2); + int maxWidth = nominalSize().width() - (margin * 2); + int maxHeight = nominalSize().height() - (margin * 2); QRectF size = item->sceneBoundingRect(); From 5ef6795fc2396aabaa0557ac689774ad03e4fb09 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Tue, 24 Feb 2026 12:21:07 +0100 Subject: [PATCH 117/133] refactor: extract common code in UBDocumentManager - extract common code from importFile and addFilesToDocument to new function importPages - remove a 14 years old workaround for an unspecified MacOS problem, which was only present in one of the code paths Signed-off-by: letsfindaway --- src/core/UBDocumentManager.cpp | 129 ++++++++++++--------------------- src/core/UBDocumentManager.h | 3 + 2 files changed, 51 insertions(+), 81 deletions(-) diff --git a/src/core/UBDocumentManager.cpp b/src/core/UBDocumentManager.cpp index 7a3ec4cd6..37d738334 100644 --- a/src/core/UBDocumentManager.cpp +++ b/src/core/UBDocumentManager.cpp @@ -197,49 +197,12 @@ std::shared_ptr UBDocumentManager::importFile(const QFile& pFile, co if (document) { doc = UBDocument::getDocument(document); - QString filepath = pFile.fileName(); - QUuid uuid; - if (importAdaptor->folderToCopy() != "") - { - uuid = UBPersistenceManager::persistenceManager()->addFileToDocument(document, pFile.fileName(), importAdaptor->folderToCopy(), filepath); - if (uuid.isNull()) - { - UBApplication::setDisabled(false); - return NULL; - } - } - - // NOTE when folderToCopy returns empty string, uuid parameter is not used for import - QList pages = importAdaptor->import(uuid, filepath); - int pageIndex = 0; - - UBApplication::showMessage(tr("Creating %1 pages. Please wait...").arg(pages.size()), true); // create the thumbnail scene before any pages are created doc->thumbnailScene(false); - foreach(UBGraphicsItem* page, pages) - { - #ifdef Q_WS_MACX - //Workaround for issue 912 - QApplication::processEvents(); - #endif - std::shared_ptr scene = doc->createPage(pageIndex, false, false); - importAdaptor->placeImportedItemToScene(scene, page); - doc->persistPage(scene, pageIndex, false, false, false, false); - pageIndex++; - } - - UBPersistenceManager::persistenceManager()->persistDocumentMetadata(document); - - // remove all asset entries to force scanning - for (int index = 0; index < doc->pageCount(); ++index) - { - doc->toc()->unsetAssets(index); - } + importPages(pFile, doc, importAdaptor); - doc->toc()->save(); - doc->scanAssets(); UBApplication::showMessage(tr("Import successful.")); } } @@ -257,7 +220,6 @@ int UBDocumentManager::addFilesToDocument(std::shared_ptr docum { int nImportedDocuments = 0; auto doc = UBDocument::getDocument(document); - const auto currentNumberOfPages = doc->pageCount(); foreach(const QString& fileName, fileNames) { @@ -287,48 +249,8 @@ int UBDocumentManager::addFilesToDocument(std::shared_ptr docum else { UBPageBasedImportAdaptor* importAdaptor = (UBPageBasedImportAdaptor*)adaptor; + importPages(file, doc, importAdaptor); - QByteArray data; - - if (file.open(QFile::ReadOnly)) - { - data = file.readAll(); - file.close(); - } - - QString filepath = file.fileName(); - QUuid uuid; - if (importAdaptor->folderToCopy() != "") - { - uuid = UBPersistenceManager::persistenceManager()->addFileToDocument(document, file.fileName(), importAdaptor->folderToCopy(), filepath); - if (uuid.isNull()) - { - continue; - } - } - - // NOTE when folderToCopy returns empty string, uuid parameter is not used for import - QList pages = importAdaptor->import(uuid, filepath); - int nPage = 0; - foreach(UBGraphicsItem* page, pages) - { - UBApplication::showMessage(tr("Inserting page %1 of %2").arg(++nPage).arg(pages.size()), true); - int pageIndex = doc->pageCount(); - std::shared_ptr scene = doc->createPage(pageIndex); - importAdaptor->placeImportedItemToScene(scene, page); - doc->persistPage(scene, pageIndex, false, false, false, false); - } - - UBPersistenceManager::persistenceManager()->persistDocumentMetadata(document); - - // remove all asset entries from new pages to force scanning - for (int index = currentNumberOfPages; index < doc->pageCount(); ++index) - { - doc->toc()->unsetAssets(index); - } - - doc->toc()->save(); - doc->scanAssets(); UBApplication::showMessage(tr("Import of file %1 successful.").arg(file.fileName())); nImportedDocuments++; break; @@ -336,9 +258,9 @@ int UBDocumentManager::addFilesToDocument(std::shared_ptr docum } } - doc->thumbnailScene()->createThumbnails(currentNumberOfPages); UBApplication::setDisabled(false); } + return nImportedDocuments; } @@ -390,3 +312,48 @@ QList UBDocumentManager::supportedExportAdaptors() { return mExportAdaptors; } + +int UBDocumentManager::importPages(const QFile& file, std::shared_ptr doc, UBPageBasedImportAdaptor* importAdaptor) +{ + std::shared_ptr document = doc->proxy(); + QString filepath = file.fileName(); + QUuid uuid; + + if (importAdaptor->folderToCopy() != "") + { + uuid = UBPersistenceManager::persistenceManager()->addFileToDocument(document, file.fileName(), importAdaptor->folderToCopy(), filepath); + + if (uuid.isNull()) + { + return 0; + } + } + + // NOTE when folderToCopy returns empty string, uuid parameter is not used for import + QList pages = importAdaptor->import(uuid, filepath); + const int startIndex = doc->pageCount(); + int pageIndex = startIndex; + + UBApplication::showMessage(tr("Creating %1 pages. Please wait...").arg(pages.size()), true); + + for (UBGraphicsItem* page : pages) + { + std::shared_ptr scene = doc->createPage(pageIndex, false, false); + importAdaptor->placeImportedItemToScene(scene, page); + doc->persistPage(scene, pageIndex, false, false, false, false); + pageIndex++; + } + + UBPersistenceManager::persistenceManager()->persistDocumentMetadata(document); + + // remove all asset entries to force scanning + for (int index = startIndex; index < pageIndex; ++index) + { + doc->toc()->unsetAssets(index); + } + + doc->toc()->save(); + doc->scanAssets(); + + return pageIndex - startIndex; +} diff --git a/src/core/UBDocumentManager.h b/src/core/UBDocumentManager.h index 8939392a8..453597531 100644 --- a/src/core/UBDocumentManager.h +++ b/src/core/UBDocumentManager.h @@ -36,6 +36,7 @@ class UBExportAdaptor; class UBImportAdaptor; class UBDocument; class UBDocumentProxy; +class UBPageBasedImportAdaptor; class UBDocumentManager : public QObject @@ -64,6 +65,8 @@ class UBDocumentManager : public QObject private: UBDocumentManager(QObject *parent = 0); + int importPages(const QFile& file, std::shared_ptr doc, UBPageBasedImportAdaptor* importAdaptor); + QList mExportAdaptors; QList mImportAdaptors; From 660a6ffc4d1981b921c1c3eac8c3e187734fb0ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Wed, 11 Mar 2026 15:42:32 +0100 Subject: [PATCH 118/133] Refreshed app theming and cleaned up UI style handling - modernized the light and dark themes across the application - restyled toolbars, button groups, tabs, dialogs and floating palettes - refreshed the Preferences dialog, startup hints and message popups - aligned board and desktop palette appearance and removed visual inconsistencies - moved widget-specific styling toward QSS and object-name based selectors - reduced ad hoc C++ styling code where QSS was sufficient - finalized dark mode polish for selections, scrollbars, spin boxes and inline editors - updated document and board thumbnail views to react correctly to theme changes - unified close button handling for floating palettes with a shared asset-based icon - cleaned up obsolete styling helpers and unused palette-related code - introduced a debug widget inspector to help debugging style issues --- resources/OpenBoard.qrc | 9 +- resources/darkTheme.qss | 188 ++++- resources/etc/OpenBoard.css | 49 -- resources/images/close-no-bg.png | Bin 0 -> 3178 bytes resources/images/down_arrow.png | Bin 258 -> 1137 bytes resources/images/left_arrow.png | Bin 258 -> 1179 bytes resources/images/right_arrow.png | Bin 256 -> 1125 bytes resources/images/up_arrow.png | Bin 238 -> 1156 bytes resources/lightTheme.qss | 704 +++++++++++++++++- resources/startupHints/css/basic.css | 16 +- .../startupHints/locales/de/css/light.css | 6 +- .../startupHints/locales/en/css/light.css | 6 +- .../startupHints/locales/fr/css/light.css | 6 +- .../startupHints/locales/hr/css/light.css | 6 +- .../startupHints/locales/it/css/light.css | 6 +- resources/style.qss | 119 +-- src/board/UBBoardPaletteManager.cpp | 2 +- src/board/UBFeaturesController.cpp | 2 +- src/core/CMakeLists.txt | 2 + src/core/UBApplication.cpp | 1 + src/core/UBSettings.cpp | 6 +- src/core/UBSettings.h | 4 +- src/core/UBThemeManager.cpp | 86 ++- src/core/UBThemeManager.h | 42 +- src/core/UBWidgetInspector.cpp | 335 +++++++++ src/core/UBWidgetInspector.h | 60 ++ src/core/core.pri | 2 + src/core/main.cpp | 8 +- src/desktop/UBDesktopAnnotationController.cpp | 9 +- src/desktop/UBDesktopPropertyPalette.cpp | 17 +- src/desktop/UBDesktopPropertyPalette.h | 1 - src/document/UBDocumentController.cpp | 4 +- src/domain/UBGraphicsItemDelegate.cpp | 2 +- src/gui/UBActionPalette.cpp | 23 +- src/gui/UBActionPalette.h | 2 +- src/gui/UBBackgroundPalette.cpp | 39 +- src/gui/UBCachePropertiesWidget.cpp | 3 +- src/gui/UBDockDownloadWidget.cpp | 5 +- src/gui/UBDockPalette.cpp | 50 +- src/gui/UBDockPaletteWidget.cpp | 10 - src/gui/UBDockPaletteWidget.h | 6 +- src/gui/UBDocumentThumbnailsView.cpp | 10 +- src/gui/UBDocumentThumbnailsView.h | 2 - src/gui/UBDownloadWidget.cpp | 3 +- src/gui/UBFeaturesWidget.cpp | 3 +- src/gui/UBFloatingPalette.cpp | 75 +- src/gui/UBFloatingPalette.h | 10 +- src/gui/UBMessageWindow.cpp | 9 +- src/gui/UBPageNavigationWidget.cpp | 8 +- src/gui/UBSpinningWheel.cpp | 1 + src/gui/UBStartupHintsPalette.cpp | 27 +- src/gui/UBStartupHintsPalette.h | 2 - src/gui/UBThumbnail.cpp | 5 +- src/podcast/UBPodcastRecordingPalette.cpp | 2 +- 54 files changed, 1555 insertions(+), 438 deletions(-) create mode 100644 resources/images/close-no-bg.png create mode 100644 src/core/UBWidgetInspector.cpp create mode 100644 src/core/UBWidgetInspector.h diff --git a/resources/OpenBoard.qrc b/resources/OpenBoard.qrc index a0dd1e7b9..73cd9f11d 100644 --- a/resources/OpenBoard.qrc +++ b/resources/OpenBoard.qrc @@ -2,7 +2,6 @@ images/OpenBoard.png images/bigOpenBoard.png - images/close.svg images/increase.svg images/decrease.svg images/resize.svg @@ -34,6 +33,8 @@ images/resizeRuler.svg images/resizeCompass.svg images/closeTool.svg + images/close.svg + images/close-no-bg.png images/hflipTool.svg images/vflipTool.svg images/resetTool.svg @@ -319,10 +320,6 @@ images/libpalette/FlashCategory.svg images/libpalette/FlashIcon.svg images/toolbar/stylusTab.png - images/library_close.png - images/library_open.png - images/pages_close.png - images/pages_open.png images/cache_close.png images/cache_open.png images/cache_circle.png @@ -339,8 +336,6 @@ images/moveUpDisabled.svg style.qss images/libpalette/WebSearchCategory.svg - images/download_close.png - images/download_open.png images/tab_mask.png images/duplicateDisabled.svg images/roundeRrectangle.svg diff --git a/resources/darkTheme.qss b/resources/darkTheme.qss index 830b5ecf3..c0fa40ace 100644 --- a/resources/darkTheme.qss +++ b/resources/darkTheme.qss @@ -31,6 +31,7 @@ QLineEdit, QTextEdit, QPlainTextEdit { QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus { border: 1px solid #2a82da; + background-color: #2a2a2a; } QLineEdit:disabled, QTextEdit:disabled, QPlainTextEdit:disabled { @@ -160,6 +161,10 @@ QComboBox QAbstractItemView::item:hover { background-color: #404040; } +#UBPageNavigationWidget { + background-color: #353535; +} + /* Spin boxes */ QSpinBox, QDoubleSpinBox { background-color: #2a2a2a; @@ -176,12 +181,14 @@ QSpinBox:focus, QDoubleSpinBox:focus { QSpinBox::up-button, QDoubleSpinBox::up-button { background-color: #404040; border-left: 1px solid #555555; + width: 10px; border-top-right-radius: 3px; } QSpinBox::down-button, QDoubleSpinBox::down-button { background-color: #404040; border-left: 1px solid #555555; + width: 10px; border-bottom-right-radius: 3px; } @@ -190,6 +197,18 @@ QSpinBox::down-button:hover, QDoubleSpinBox::down-button:hover { background-color: #505050; } +QSpinBox::up-arrow, QDoubleSpinBox::up-arrow { + image: url(:/images/up_arrow.png); + width: 10px; + height: 10px; +} + +QSpinBox::down-arrow, QDoubleSpinBox::down-arrow { + image: url(:/images/down_arrow.png); + width: 10px; + height: 10px; +} + /* Sliders */ QSlider::groove:horizontal { background-color: #404040; @@ -233,72 +252,68 @@ QScrollBar:vertical { } QScrollBar::handle:vertical { - background: #555555; + background: white; min-height: 30px; border-radius: 6px; - border: 1px solid #404040; + border: 1px solid #1e5fa0; } QScrollBar::handle:vertical:hover { - background: #6a6a6a; + background: #3d8fd1; } -QScrollBar::add-line:vertical { - background: #404040; - height: 16px; - subcontrol-position: bottom; - subcontrol-origin: margin; - border-radius: 6px; - margin: 1px 1px 2px 1px; +QScrollBar::handle:vertical:pressed { + background: #1e5fa0; } -QScrollBar::sub-line:vertical { - background: #404040; - height: 16px; - subcontrol-position: top; - subcontrol-origin: margin; - border-radius: 6px; - margin: 2px 1px 1px 1px; +QScrollBar::add-line:vertical { + background: transparent; + border: none; + height: 0px; } -QScrollBar::add-line:vertical:hover, -QScrollBar::sub-line:vertical:hover { - background: #505050; +QScrollBar::sub-line:vertical { + background: transparent; + border: none; + height: 0px; } QScrollBar:horizontal { - background: #2b2b2b; + background: #2a82da; height: 14px; margin: 1px 18px 1px 18px; } QScrollBar::handle:horizontal { - background: #555555; + background: #2a82da; min-width: 30px; border-radius: 6px; - border: 1px solid #404040; + border: 1px solid white; +} + +QScrollBar::handle:horizontal:!hover { + background: #2a82da; + border: 1px solid #1e5fa0; } QScrollBar::handle:horizontal:hover { - background: #6a6a6a; + background: #3d8fd1; +} + +QScrollBar::handle:horizontal:pressed { + background: #1e5fa0; } QScrollBar::add-line:horizontal { - background: #404040; - width: 16px; - subcontrol-position: right; - subcontrol-origin: margin; - border-radius: 6px; - margin: 1px 2px 1px 1px; + background: transparent; + border: none; + width: 0px; } QScrollBar::sub-line:horizontal { - background: #404040; - width: 16px; - subcontrol-position: left; - subcontrol-origin: margin; - border-radius: 6px; - margin: 1px 1px 1px 2px; + background: transparent; + border: none; + width: 0px; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical, @@ -379,6 +394,33 @@ QTreeView::item:selected, QListView::item:selected, QTableView::item:selected { color: #ffffff; } +QTreeView::item:selected:active, +QListView::item:selected:active, +QTableView::item:selected:active, +QTreeView::branch:selected { + background: #2a82da; + color: #ffffff; + border: none; +} + +QTreeView QLineEdit, +QListView QLineEdit, +QTableView QLineEdit { + background-color: #2a2a2a; + color: #ffffff; + border: 1px solid #555555; + padding: 1px 6px; + selection-background-color: #2a82da; + selection-color: #ffffff; +} + +QTreeView QLineEdit:focus, +QListView QLineEdit:focus, +QTableView QLineEdit:focus { + background-color: #2a2a2a; + border: 1px solid #2a82da; +} + QTreeView::branch { background-color: #2a2a2a; } @@ -572,6 +614,80 @@ QScrollArea { border: none; } +#BackgroundPaletteScrollArea { + background-color: #3f3f3f; + border: none; +} +#BackgroundPaletteScrollArea QWidget{ + background-color: transparent; +} + +#BackgroundPalette { + background-color: #3f3f3f; +} +#AddItemPalette { + background-color: #3f3f3f; +} + +#DesktopPropertyPalette { + background-color: #3f3f3f; +} + +#UBMessageWindow { + color: #ffffff; +} + +#UBMessageWindow QLabel#UBMessageWindowLabel { + background: transparent; + border: none; + color: #f8fafc; + font-size: 15px; + font-weight: 600; + padding: 0px 2px 0px 0px; +} + +#UBMessageWindow UBSpinningWheel#UBMessageWindowSpinner { + background: transparent; + color: #5aa5e0; +} + +#BackgroundPalette QLabel { + color: palette(window-text); +} +#BackgroundPalette QToolButton#closeButton, +#AddItemPalette QToolButton#closeButton, +#UBStartupHintsPalette QToolButton#closeButton { + background: transparent; + border: none; + border-radius: 5px; + padding: 0px; + color: #ffffff; + font-size: 20px; + font-weight: bold; + min-width: 16px; + max-width: 16px; + min-height: 16px; + max-height: 16px; +} + +#UBStartupHintsPalette QCheckBox { + background: transparent; + color: #ffffff; +} +#BackgroundPalette QToolButton#closeButton:hover, +#AddItemPalette QToolButton#closeButton:hover, +#UBStartupHintsPalette QToolButton#closeButton:hover { + background: rgba(255, 255, 255, 0.10); +} +#BackgroundPalette QToolButton#closeButton:pressed, +#AddItemPalette QToolButton#closeButton:pressed, +#UBStartupHintsPalette QToolButton#closeButton:pressed { + background: rgba(255, 255, 255, 0.18); +} +#BackgroundPaletteLabel { + color: palette(window-text); +} + /* Calendar widget */ QCalendarWidget { background-color: #2a2a2a; diff --git a/resources/etc/OpenBoard.css b/resources/etc/OpenBoard.css index db7f4208c..5f76525d0 100644 --- a/resources/etc/OpenBoard.css +++ b/resources/etc/OpenBoard.css @@ -86,29 +86,6 @@ QToolBar::separator border: 1px dotted palette(dark); border-left: none; margin-left: 5px; margin-right: 5px; width: 1px; } -QToolBar QToolButton -{ - - margin: 4px; - margin-left: 0px; - margin-right: 0px; - padding: 0px; - border: none; - height: 58px; -} - -QToolBar QToolButton:pressed -{ - margin: 4px; - margin-left: 0px; - margin-right: 0px; - padding: 0px; - border: none; - height: 58px; - - background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop: 0 #d3d3d3, stop: 1 #b3b3b3); -} - QDialog QToolButton:pressed { background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop: 0 #ffffff, stop: 1 #dddddd); @@ -143,13 +120,6 @@ QToolButton#desktop-ubButtonGroupRight } -QToolButton#ubButtonGroupLeft:checked, -QToolButton#ubButtonGroupCenter:checked, -QToolButton#ubButtonGroupRight:checked -{ - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 palette(light), stop: 1 palette(midlight)); -} - QToolButton#ubButtonGroupLeft:checked { padding-right: 4px; @@ -172,12 +142,6 @@ QToolButton#ubButtonMenu padding-right: 12px; } -QToolButton#ubButtonMenu:pressed, -QToolButton#ubButtonMenu:checked -{ - background-color: palette(midlight); -} - QToolButton#ubActionPaletteButton { margin: 0px; @@ -218,25 +182,12 @@ QTreeView background-color: palette(base); } -QTreeView::item:selected:active -{ - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #AAB7C4, stop: 1 #7e8eA0); - border: none; -} - QTreeView::item { padding-top: 1.5 px; padding-bottom: 1.5 px; } -QTreeView::item:selected, -QTreeView::branch:selected -{ - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #AAB7C4, stop: 1 #7e8eA0); - border: none; -} - QTreeView::branch:has-siblings:!adjoins-item, QTreeView::branch:!has-children:!has-siblings:adjoins-item, QTreeView::branch:has-siblings:adjoins-item diff --git a/resources/images/close-no-bg.png b/resources/images/close-no-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..949b5900c3b659a789c63b0ed9c4c7736d711534 GIT binary patch literal 3178 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 literal 0 HcmV?d00001 diff --git a/resources/images/down_arrow.png b/resources/images/down_arrow.png index a518176814401ba1f6478e81acd5e117c85eb362..934280f35a2963a943a2d93d9eb2cbb89926e234 100644 GIT binary patch literal 1137 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBQ!3HE-C+YhDDaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#S9F5he4R}c>anMprB-lYeY$Kep*R+Vo@qXKw@TIiJqTph=Qq} zp`M{(7l+t6prReA5uRzDo>~kXKn^Q|6eBAGBar0<#L`eU$T=E}%wTaQAls0Ui9rxZ zM*(qWI}2Dm2gnA21Rw_KhtcS^GB7YRFic=)U;(NzFfuk^TmUf_q=$6@#H?vRHV7~Q zO=1G846?KUvY@&Q4GciCY^GO=H}w};15K3mba4#HaDF<|HbcZwqD_CJ(3aqX^N%TX zY`xWSBC$!r+LPm;0;giHLWjZ(j|mM^w>hcYh>Y?O_~RJB=PMAn@dLjjOTDs$i%USr zmFIIMdE(0U-rYTO_wC#4_s*C*=auh!Z}jzmnuT-xwv7u1?NfTpo&W|%!FK^IsV%qPc$_Yr_2hVL&IPrIa}v7}4o^#x zlHK@_Y2xd-S}$t~m~#!8Z$4*yrL^8vy7o=masBcOXBJ#dQ`miG;oB#Red`1Ry$?LF zQwaZ&#I~vP**)p$dw!$~>m0xN*!$34jqGn4yQS5Bp57*Xww_x-OWuX0@SIsjnFKprsTZN{>9$}Z>Wc1C-Rtj31y=ql?d-%mP;|n!+ z+;`7>zUOV2+Sg;pj+$S%<8n5wf75Q+Gw*l4RZ~7IWUxc}%YyZ33oI|hR9#Zj4-$7M zSbW>$@Qdw|89K9?-}n`K`6`KbFr`@#ss z-0N`PQ11mj%`X=5zV3Rrvif?<^yAU{TBn*+Jy~--{*djK_TP0I?!Nl?t>%1+*`*g8 zdynz7JeIw6^6$KxdAUC#nApr0+I>08)8csj-RG%$K7=tGJd&2lmaEUv{7&xPij%C1 z4oJ#9=DE*Vd;78Br1?b~&G(2q1hhzYZJ2i9`pkzqC$FcJ7goeFrOG%wyIbA+LTXo- zK-0db52G)?{K&QHnp|r6-5B+cFZFaCxfN#oQJa;WF;~)~?_c@$?(_Cr?;5nkFtJTP zz~GhK|Lbn!g_GS6SOruTeP?&xHoZgf`^*O{g^e0>Y+ucOyGeOt&!j!&ySo?Xu?mPJ zZfgPthFffm_^VAUrzR|YDf0c)7o9Fsu`}-$X^Q+~cy#yPfscG!;z60l)78&qol`;+ E03t8M_y7O^ literal 258 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VV{wqX6T`Z5GB1G~wj^(N7l!{J zxM1({$v_d#0*}aI1_o|n5N2eUHAey{$X?><>&kwclb4;#V$RoHg+L+664!_l=ltB< z)VvY~=c3falGGH1^30M91$R&1fbd2>aiF4DPZ!4!i_^(}{{OdUHf0oMo_g?s`2^P3 z1BdUK%9Q-uWlI_#Ke#yr3XKrjk{MVUJaqP_UOl9MB>LPgg&ebxsLQ00%5tGynhq diff --git a/resources/images/left_arrow.png b/resources/images/left_arrow.png index 53e58f205b9e3c951aee9df35c5454e681db3bc6..48d6e45cb49bbd1dac0c82f06c7ebb2f2b088993 100644 GIT binary patch literal 1179 zcmeAS@N?(olHy`uVBq!ia0vp^nn3Kp!3HGTXUC-gDaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#S9F5he4R}c>W5I4#^VNh?3y^w370~qEv=}#LT=BJwMkF1yemk zJwwAT4zY7UMLSX>JkvZqwHP>n999M?Mpgz!Aj=DgrJ-z)b2J#4!QxCnwjm=EgCLNO z0^-be7O;2@kPQL}Kn&6kqtR_;U|?oon841!0#svQWNg5=0Aemk59Myben&|H7;uwEGzK{OCyY%<{{I~Dd9JjMoW?B%n_MDoG+wKcIUs&(DrT@75{*rG}67NI4S;?Jc z_ZIjre)YKMzyrS~Ewj5q&VjAf-m6vE_=V0boH(r`{lad~GrekaoZ59JGOSlKwCF70 zeY?TMY0u0f4{Q#_Zn-0*`5{TDc{L~h1t0GvDLdND%q8x4S9BRkinPu;^1$#AugOIr zNzIg9hUU{2^iQ|*esW}|Cy$?MjN@(HhYZVs2F_ognm1Eb=HVF?ws1kYMQ3=0+9w}7 z_(1MZ@sm3XPUH$Tze>mzs?rT)n7LfKII3BH!QW{b6MTRgdkaK!H@h5MV%B-EwPm)( zSE)HuL(~jc#D1|gIW08L^!)&C3?kW%N-)Oq}ZExbKY`gPY&4Plk|bZ z@%EY^s~ys|Gq@Ku?_TI7=WtL;#AxO1H47%5-1#+e$ClFa6(^ot|78%9@+qfQLeHp@ z^W_{FowcbOKPJ}g`WGCrW!>WJtx@$$gMJ<;;J&1&E%9$ZZ`*+<+=tk{ToYov@bN8k z@c+3h>(3N$MkSmS>a2Bbx@a$Pb*Ednx}W}nOG4E(9fy<`G~YP+%l}{J+7yvhzq(fK zOWz?{`Tmc~)Ep<*!~0|eX1q~f;~Zygf3d_p@m0OSSAU6DejZwLuBf>#{`@u0O<#}O z{@b!DHS2@Q3%sugYka@or5vofIN<8^kgv+lcT0LUE=ivA_j`!Ro9^1ilh;{t{q98` zQrx-Rnk)GKjB z?{s_#G7)YK+r%k)_G{3+ZqLTR+P#i$)1#DFTm8yKmi-eCuAjf~+V7CL@6Rqd@FHRH zXZ6KXr};E&fB8>*S^V>wx8K@d|6yD|wZ|#6^xXe51-4S@C(p&`t)1k%BI8E<3gM71 t(xO)#$-daEhaZky*`do`={f&M<`qdyjw1%Zko22WQ%mvv4FO#pb-&G`TT literal 258 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VV{wqX6T`Z5GB1G~wj^(N7l!{J zxM1({$v_d#0*}aI1_o|n5N2eUHAey{$X?><>&kwclb2UQ;EwY1KA@0fiEBiObAE1a zYF-J0b5UwyNotBhd1gt5g1e`0KzJjcI8afnr;B5V#p$_McV#r4ApZcln{=qkK*SY7w2>B<5zAxCW!mhy?35giXi<{w)o t;Ank7w>>OEHb*ySp9p8$|9$V6wQV{zB9u?LJ_lOF;OXk;vd$@?2>`@TQ=$L> diff --git a/resources/images/right_arrow.png b/resources/images/right_arrow.png index e9a64d2da468705fa50f96c747c356e4769ca9a0..a64d932be3efa2da8bc5ed678208f637d0e7692d 100644 GIT binary patch literal 1125 zcmeAS@N?(olHy`uVBq!ia0vp^nn3Kp!3HGTXUC-gDaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#S9F5he4R}c>W5I4#^VNh?3y^w370~qEv=}#LT=BJwMkF1yemk zJwwAT4zY7UMLSX>JkvZqwHP>n999M?Mpgz!Aj=DgrJ-z)b2J#4!QxCnwjm=EgCLNO z0^-be7O;2@kPQL}Kn&6kqtR_;U|?oon841!0#svQWNg5=0Aemk59MybenkeY$;uwfG-{;S} zzO-P@n^#UcXDfv;;fpr37wOcEV=OHzDvoft0^8) zL1$EAJI-yCk{6%kG`U{Ii zOZ9D0aW%cT^QFn^rIVK}nc@0Q(dv9w<`P{^HG#RVYd2b1M0#{3x~#rzxBB1`)4Psy z)MkHtvF+CUHQ!PcrB8&abg%nq=g}qlgl*B~wcn14doDb=zc*v*)wr5TBD>CAzggEC zde|H&nD6}Me(65`%d#$YpK9++Zq4{4T{B%|_i4wXB1?}d%e((S?~+mJ|Dm_i`GV(s z)$c_-_dRyiPWj_lGJoIERrSq_`Guw_+{nB7!SfSmWKY6$p!pN`_)Sy%aVIOjX2KPg z^)4SKU;US&d$T2`uBrN0LyGE3&UKFOHe5~EG@-^_OtIqNs|QPTS8~QRB&;~Eb$QAj zw`s~h4rRSuqPjA=ezoAA3{#nPs-=Io$nRtmdU<>&kwclb2UQO?YOJI8aEk#5JPCIX^cy zHLrxhxhOTUBsE2$JhLQ2!QIn0AiR+eq$t|c#WBR<^xG@mTnq{vEEjs-rMa)W?7Mn_ z?~jwNj>Qe_eF}^o6HjVd@Hb7BoGSTHxGJ$QReR050PflSN(YZd|LfXz@1;b{#KoND q6C|f7n67AbxxjVyLVf)AM&{sK>S3yt(}IE4FnGH9xvXanMprB-lYeY$Kep*R+Vo@qXKw@TIiJqTph=Qq} zp`M{(7l+t6prReA5uRzDo>~kXKn^Q|6eBAGBar0<#L`eU$T=E}%wTaQAls0Ui9rxZ zM*(qWI}2Dm2gnA21Rw_KhtcS^GB7YRFic=)U;(NzFfuk^TmUf_q=$6@#H?vRHV7~Q zO=1G846?KUvY@&Q4GciCY^GO=H}w};15GsWba4#HaDF=Tem8HT#PPMRBIb*9iWG0& z(TMzcv+Ua&x4>H}Pvjq*T6*;AmAH;6Ejf#}ZQYXPy;Hg5(4v?{TepUJ-pLEvCi=7H ze)+UM+uhdhXI7>^pYwU;`^tOIZPU~4J)gP#yX9xUyK|;+HZ71VmYM64eT9Agg~}^O zzwh_)_d3IyJ1fRH{DR8|r`)eEcZXcO>%sdjkKJun*V&yhd20eRcv|+A2YE9bls{Gy znICn_<52aa4|-qrPC6y!@ZszX_KbxuXUsI*(*Af})OGoL!VUt`2K*PZE(^{*pJ9HS zKk7PvoVX*~exA$CG0oyu%hYY!&G)D_G-lVnbn{)d*rp_>yh2a^#~enj%-=c2Vpi?j zKfO@hd}rfjiN6;;xuza3)H?k6f`88uVTTXx27#yMYOhsEGlsKotKX2 z{5YvoA@=Lsl(`H|_Dwsxg6@a>?6>ihP~yyYzTdft&Huw~!~Tm(mkodaaah~)dTHt6 z$8#9;Ht{V!eueGwMA?0d(vF$u+|97iZJHC~pH{1peUQ6%rM^sZiqd+aB`PFwM`@ED80pTIMz zCbyrSn<_TRz(?p_OP%L3-mVAb30r3FyipP&cYmT;czi^;QLtJ=^R=Wcj1!NF-e;Y9 zJoboj(%mF4y{11EoX_-DeRIHrMp%&`{EZ48slH6N;XPIk&wbfR!JppHAy&B?Du4ujWI>2>% zou|~4hW>4_lY2B6%X4gTe~DWM4fyY|go literal 238 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VV{wqX6T`Z5GB1G~wj^(N7l!{J zxM1({$v_d#0*}aI1_o|n5N2eUHAey{$X?><>&kwclb4-K+HTTmW}uK{iEBiObAE1a zYF-J0b5UwyNotBhd1gt5g1e`0KzJjcI8c$Nr;B5V#p&cf|Nq-Fn=%SBPd#`*;>E*v z|LR#PC7;D6?e&cpU$nbRBK*?%)*UgactionAddItemToLibrary; mAddItemPalette = new UBActionPalette(addItemActions, Qt::Horizontal, mContainer); + mAddItemPalette->setObjectName("AddItemPalette"); mAddItemPalette->setButtonIconSize(QSize(128, 128)); mAddItemPalette->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); mAddItemPalette->groupActions(); diff --git a/src/board/UBFeaturesController.cpp b/src/board/UBFeaturesController.cpp index c416adfbd..000968124 100644 --- a/src/board/UBFeaturesController.cpp +++ b/src/board/UBFeaturesController.cpp @@ -1302,7 +1302,7 @@ void UBFeaturesController::assignPathListView(UBFeaturesListView *pList) pList->setFixedHeight(60); pList->setSelectionMode(QAbstractItemView::NoSelection); pList->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - pList->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + pList->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); pList->setFlow(QListView::LeftToRight); pList->setWrapping(false); pList->setDragDropMode(QAbstractItemView::DropOnly); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7342c4828..31e9e45b2 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -35,4 +35,6 @@ target_sources(${PROJECT_NAME} PRIVATE UBTextTools.h UBThemeManager.cpp UBThemeManager.h + UBWidgetInspector.cpp + UBWidgetInspector.h ) diff --git a/src/core/UBApplication.cpp b/src/core/UBApplication.cpp index 08e853592..94d2bb472 100644 --- a/src/core/UBApplication.cpp +++ b/src/core/UBApplication.cpp @@ -624,6 +624,7 @@ void UBApplication::updateProtoActionsState() void UBApplication::insertSpaceToToolbarBeforeAction(QToolBar* toolbar, QAction* action, int width) { QWidget* spacer = new QWidget(); + spacer->setStyleSheet("background: transparent;"); if (width >= 0){ QHBoxLayout *layout = new QHBoxLayout(); diff --git a/src/core/UBSettings.cpp b/src/core/UBSettings.cpp index 4d5744324..f86d27054 100644 --- a/src/core/UBSettings.cpp +++ b/src/core/UBSettings.cpp @@ -97,9 +97,11 @@ QColor UBSettings::documentSizeMarkColorDarkBackground = QColor(44, 44, 44, 200) QColor UBSettings::documentSizeMarkColorLightBackground = QColor(241, 241, 241); QColor UBSettings::paletteColor = QColor(127, 127, 127, 127); -QColor UBSettings::opaquePaletteColor = QColor(66, 66, 66, 200); +QColor UBSettings::opaquePaletteColor = QColor(66, 66, 66, 255); -QColor UBSettings::documentViewLightColor = QColor(241, 241, 241); +QColor UBSettings::documentThumbnailsViewColor = QColor(214, 222, 235); +QColor UBSettings::boardThumbnailsViewColor = QColor(237, 242, 247); +QColor UBSettings::pageNavigationWidgetColor = QColor(Qt::white); QPointer UBSettings::sAppSettings = 0; diff --git a/src/core/UBSettings.h b/src/core/UBSettings.h index 3d6a7d9fb..ca68c291f 100644 --- a/src/core/UBSettings.h +++ b/src/core/UBSettings.h @@ -163,7 +163,9 @@ class UBSettings : public QObject static QColor paletteColor; static QColor opaquePaletteColor; - static QColor documentViewLightColor; + static QColor documentThumbnailsViewColor; + static QColor boardThumbnailsViewColor; + static QColor pageNavigationWidgetColor; static QBrush eraserBrushDarkBackground; static QBrush eraserBrushLightBackground; diff --git a/src/core/UBThemeManager.cpp b/src/core/UBThemeManager.cpp index 83b08f861..bdcad20e7 100644 --- a/src/core/UBThemeManager.cpp +++ b/src/core/UBThemeManager.cpp @@ -33,13 +33,16 @@ #include "board/UBBoardController.h" #include "board/UBBoardPaletteManager.h" #include "gui/UBMainWindow.h" +#include "gui/UBBoardThumbnailsView.h" #include "gui/UBFloatingPalette.h" +#include "gui/UBPageNavigationWidget.h" #include "gui/UBStartupHintsPalette.h" -#include "desktop/UBDesktopPropertyPalette.h" +#include "gui/UBDocumentThumbnailsView.h" #include "desktop/UBDesktopAnnotationController.h" #include "desktop/UBDesktopPalette.h" #include +#include #include #include #include @@ -175,6 +178,10 @@ void UBThemeManager::setupDarkPalette() // Update OpenBoard-specific palette colors UBSettings::paletteColor = UBTheme::Dark::PaletteColor; UBSettings::opaquePaletteColor = UBTheme::Dark::OpaquePaletteColor; + UBSettings::documentThumbnailsViewColor = darkPalette.color(QPalette::Window); + UBSettings::boardThumbnailsViewColor = darkPalette.color(QPalette::Window); + UBSettings::pageNavigationWidgetColor = darkPalette.color(QPalette::Base); + UBSettings::treeViewBackgroundColor = darkPalette.color(QPalette::Highlight); } void UBThemeManager::setupLightPalette() @@ -213,13 +220,24 @@ void UBThemeManager::setupLightPalette() // Update OpenBoard-specific palette colors UBSettings::paletteColor = UBTheme::Light::PaletteColor; UBSettings::opaquePaletteColor = UBTheme::Light::OpaquePaletteColor; + UBSettings::documentThumbnailsViewColor = QColor(214, 222, 235); + UBSettings::boardThumbnailsViewColor = UBTheme::Light::PaletteColor; + UBSettings::pageNavigationWidgetColor = UBTheme::Light::PaletteColor; + UBSettings::treeViewBackgroundColor = lightPalette.color(QPalette::Highlight); } void UBThemeManager::loadStylesheets() { QString fullStylesheet; - - // Layer 1: Theme-specific stylesheet (dark or light) + + // Layer 1: Embedded base stylesheet shared by light and dark themes + QString embeddedStyle = UBFileSystemUtils::readTextFile(":/style.qss"); + if (!embeddedStyle.isEmpty()) + { + fullStylesheet += embeddedStyle; + } + + // Layer 2: Theme-specific stylesheet (dark or light) if (mIsDarkMode) { QString darkThemeCss = UBFileSystemUtils::readTextFile(":/darkTheme.qss"); @@ -227,35 +245,36 @@ void UBThemeManager::loadStylesheets() // Fallback to file system if resource not found (allows user customization) darkThemeCss = UBFileSystemUtils::readTextFile( UBPlatformUtils::applicationResourcesDirectory() + "/darkTheme.qss"); - + if (darkThemeCss.isEmpty()) { qWarning() << "Failed to load dark theme stylesheet from resources and filesystem"; } } - fullStylesheet = darkThemeCss; + if (!darkThemeCss.isEmpty()) { + if (!fullStylesheet.isEmpty()) { + fullStylesheet += "\n"; + } + fullStylesheet += darkThemeCss; + } } else { QString lightThemeCss = UBFileSystemUtils::readTextFile(":/lightTheme.qss"); if (lightThemeCss.isEmpty()) { // Fallback to file system if resource not found (allows user customization) lightThemeCss = UBFileSystemUtils::readTextFile( UBPlatformUtils::applicationResourcesDirectory() + "/lightTheme.qss"); - + if (lightThemeCss.isEmpty()) { qWarning() << "Failed to load light theme stylesheet from resources and filesystem"; } } - fullStylesheet = lightThemeCss; - } - - // Layer 2: Embedded style.qss (palette-aware styling for OpenBoard widgets) - QString embeddedStyle = UBFileSystemUtils::readTextFile(":/style.qss"); - if (!embeddedStyle.isEmpty()) { - if (!fullStylesheet.isEmpty()) { - fullStylesheet += "\n"; + if (!lightThemeCss.isEmpty()) { + if (!fullStylesheet.isEmpty()) { + fullStylesheet += "\n"; + } + fullStylesheet += lightThemeCss; } - fullStylesheet += embeddedStyle; } - + // Layer 3: Standard CSS (user customizable, uses palette() references) QString css = UBFileSystemUtils::readTextFile( UBPlatformUtils::applicationEtcDirectory() + "/" + qApp->applicationName() + ".css"); @@ -313,12 +332,6 @@ void UBThemeManager::updateWidgets() desktopController->desktopPalette()->setBackgroundBrush(QBrush(UBSettings::opaquePaletteColor)); } - auto desktopPropertyPalettes = desktopController->findChildren(); - - for (auto desktopPropertyPalette : std::as_const(desktopPropertyPalettes)) - { - desktopPropertyPalette->setBackgroundBrush(QBrush(UBSettings::opaquePaletteColor)); - } } // Update startup hints palette background @@ -334,6 +347,35 @@ void UBThemeManager::updateWidgets() startupHint->update(); } + auto updateThumbnailSceneTextColor = [](QGraphicsScene* thumbnailScene) + { + if (!thumbnailScene) + { + return; + } + + for (auto item : thumbnailScene->items()) + { + if (auto textItem = dynamic_cast(item)) + { + textItem->setDefaultTextColor(QApplication::palette().color(QPalette::WindowText)); + } + } + }; + + auto documentThumbnailViews = UBApplication::mainWindow->findChildren(); + for (auto documentThumbnailView : std::as_const(documentThumbnailViews)) + { + documentThumbnailView->QGraphicsView::setBackgroundBrush(QBrush(UBSettings::documentThumbnailsViewColor)); + updateThumbnailSceneTextColor(documentThumbnailView->scene()); + } + + auto boardThumbnailViews = UBApplication::mainWindow->findChildren(); + for (auto boardThumbnailView : std::as_const(boardThumbnailViews)) + { + updateThumbnailSceneTextColor(boardThumbnailView->scene()); + } + // Force all widgets to update their appearance // This ensures that all widgets pick up the new palette and stylesheet QList allWidgets = UBApplication::mainWindow->findChildren(); diff --git a/src/core/UBThemeManager.h b/src/core/UBThemeManager.h index 6b4e12277..66b17257b 100644 --- a/src/core/UBThemeManager.h +++ b/src/core/UBThemeManager.h @@ -149,35 +149,35 @@ namespace UBTheme { // OpenBoard-specific palette colors const QColor PaletteColor(70, 70, 70, 220); - const QColor OpaquePaletteColor(50, 50, 50, 240); + const QColor OpaquePaletteColor(50, 50, 50, 255); } namespace Light { - const QColor Window(240, 240, 240); - const QColor WindowText(Qt::black); + const QColor Window(237, 242, 247); + const QColor WindowText(31, 41, 55); const QColor Base(Qt::white); - const QColor AlternateBase(245, 245, 245); - const QColor ToolTipBase(255, 255, 220); - const QColor ToolTipText(Qt::black); - const QColor Text(Qt::black); - const QColor Button(240, 240, 240); - const QColor ButtonText(Qt::black); + const QColor AlternateBase(247, 249, 252); + const QColor ToolTipBase(Qt::white); + const QColor ToolTipText(31, 41, 55); + const QColor Text(31, 41, 55); + const QColor Button(247, 249, 252); + const QColor ButtonText(31, 41, 55); const QColor BrightText(Qt::red); - const QColor Link(0, 0, 255); - const QColor Highlight(0, 120, 215); + const QColor Link(61, 143, 209); + const QColor Highlight(61, 143, 209); const QColor HighlightedText(Qt::white); - const QColor Light(245, 245, 245); - const QColor Midlight(242, 242, 242); - const QColor Dark(160, 160, 160); - const QColor Mid(160, 160, 160); - const QColor Shadow(105, 105, 105); - const QColor DisabledText(120, 120, 120); - const QColor DisabledBase(240, 240, 240); - const QColor DisabledButton(240, 240, 240); + const QColor Light(Qt::white); + const QColor Midlight(242, 246, 250); + const QColor Dark(179, 191, 205); + const QColor Mid(205, 214, 224); + const QColor Shadow(143, 154, 168); + const QColor DisabledText(148, 163, 184); + const QColor DisabledBase(242, 242, 242); + const QColor DisabledButton(239, 242, 247); // OpenBoard-specific palette colors - const QColor PaletteColor(180, 180, 180, 220); - const QColor OpaquePaletteColor(200, 200, 200, 240); + const QColor PaletteColor(236, 241, 247, 235); + const QColor OpaquePaletteColor(236, 241, 247, 255); } } diff --git a/src/core/UBWidgetInspector.cpp b/src/core/UBWidgetInspector.cpp new file mode 100644 index 000000000..0abc32a80 --- /dev/null +++ b/src/core/UBWidgetInspector.cpp @@ -0,0 +1,335 @@ +#include "UBWidgetInspector.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +UBWidgetInspector::UBWidgetInspector(QObject *parent) + : QObject(parent) + , mInspectorDialog(nullptr) + , mInspectorView(nullptr) +{ +} + +bool UBWidgetInspector::eventFilter(QObject *obj, QEvent *event) +{ + if (!event || QCoreApplication::closingDown()) + return QObject::eventFilter(obj, event); + + switch (event->type()) { + case QEvent::KeyPress: { + const auto *keyEvent = static_cast(event); + if (keyEvent->key() != Qt::Key_F12 || keyEvent->isAutoRepeat()) + return QObject::eventFilter(obj, event); + + inspectWidgetUnderCursor(); + return true; + } + default: + return QObject::eventFilter(obj, event); + } +} + +void UBWidgetInspector::inspectWidgetUnderCursor() +{ + QWidget *widget = QApplication::widgetAt(QCursor::pos()); + showInspector(buildInfo(widget)); +} + +QString UBWidgetInspector::buildInfo(const QWidget *widget) const +{ + if (!widget) { + return QStringLiteral("No widget under cursor."); + } + + const QString name = widget->objectName().isEmpty() + ? QStringLiteral("") + : widget->objectName(); + const QString styleName = + (widget->style() && widget->style()->metaObject()) + ? QString::fromUtf8(widget->style()->metaObject()->className()) + : QStringLiteral(""); + const QList hierarchy = buildWidgetHierarchy(widget); + const QStringList selectorTokens = buildSelectorTokens(hierarchy); + const QList sources = buildStyleSheetSources(hierarchy); + + QStringList reportSections; + reportSections << QStringLiteral("Target\n%1 obj=\"%2\"\nstyle=\"%3\"") + .arg(QString::fromUtf8(widget->metaObject()->className()), + name, + styleName); + reportSections << buildHierarchySection(hierarchy); + reportSections << QStringLiteral("Precedence\n1. widgetQss on the target widget\n2. parentQss from the nearest parent outward\n3. appQss from QApplication\nWithin one source, more specific selectors win; ties are resolved by later rules."); + reportSections << buildRelevantStylesSection(sources, selectorTokens); + + return reportSections.join(QStringLiteral("\n\n")); +} + +void UBWidgetInspector::showInspector(const QString &info) +{ + ensureInspectorDialog(); + + mInspectorView->setPlainText(info); + mInspectorView->moveCursor(QTextCursor::Start); + + if (!mInspectorDialog->isVisible()) + mInspectorDialog->show(); + + positionInspector(); + mInspectorDialog->raise(); + mInspectorDialog->activateWindow(); +} + +void UBWidgetInspector::ensureInspectorDialog() +{ + if (mInspectorDialog && mInspectorView) + return; + + auto *dialog = new QDialog(); + dialog->setWindowTitle(QStringLiteral("Widget Inspector")); + dialog->setWindowFlag(Qt::Tool, true); + dialog->resize(760, 520); + + auto *layout = new QVBoxLayout(dialog); + layout->setContentsMargins(8, 8, 8, 8); + + auto *view = new QPlainTextEdit(dialog); + view->setReadOnly(true); + view->setLineWrapMode(QPlainTextEdit::NoWrap); + layout->addWidget(view); + + mInspectorDialog = dialog; + mInspectorView = view; + + connect(dialog, &QObject::destroyed, this, [this]() { + mInspectorDialog.clear(); + mInspectorView.clear(); + }); +} + +void UBWidgetInspector::positionInspector() +{ + if (!mInspectorDialog) + return; + + QPoint position = QCursor::pos() + QPoint(24, 24); + if (QScreen *screen = QGuiApplication::screenAt(QCursor::pos())) { + const QRect availableGeometry = screen->availableGeometry(); + const QSize dialogSize = mInspectorDialog->size(); + + if (position.x() + dialogSize.width() > availableGeometry.right()) + position.rx() = qMax(availableGeometry.left(), availableGeometry.right() - dialogSize.width() + 1); + + if (position.y() + dialogSize.height() > availableGeometry.bottom()) + position.ry() = qMax(availableGeometry.top(), availableGeometry.bottom() - dialogSize.height() + 1); + } + + mInspectorDialog->move(position); +} + +QString UBWidgetInspector::describeWidget(const QWidget *widget) +{ + if (!widget) + return QStringLiteral(""); + + const QString objectName = widget->objectName().isEmpty() + ? QStringLiteral("") + : widget->objectName(); + return QStringLiteral("%1 obj=\"%2\"") + .arg(QString::fromUtf8(widget->metaObject()->className()), objectName); +} + +QList UBWidgetInspector::buildWidgetHierarchy(const QWidget *widget) +{ + QList hierarchy; + for (const QWidget *current = widget; current; current = current->parentWidget()) + hierarchy << current; + return hierarchy; +} + +QString UBWidgetInspector::buildHierarchySection(const QList &hierarchy) +{ + QStringList lines; + lines << QStringLiteral("Hierarchy"); + + for (int index = 0; index < hierarchy.size(); ++index) { + const QWidget *widget = hierarchy.at(index); + const QString prefix = (index == 0) ? QStringLiteral("0. target") : QStringLiteral("%1. parent").arg(index); + lines << QStringLiteral("%1 %2").arg(prefix, describeWidget(widget)); + } + + return lines.join(QStringLiteral("\n")); +} + +QStringList UBWidgetInspector::buildSelectorTokens(const QList &hierarchy) +{ + QStringList tokens; + + for (const QWidget *widget : hierarchy) { + if (!widget) + continue; + + if (!widget->objectName().isEmpty()) + tokens << QStringLiteral("#%1").arg(widget->objectName()); + + for (const QMetaObject *metaObject = widget->metaObject(); metaObject; metaObject = metaObject->superClass()) { + const QString className = QString::fromUtf8(metaObject->className()); + if (className.isEmpty()) + continue; + + tokens << className; + + if (className == QStringLiteral("QWidget")) + break; + } + } + + tokens.removeDuplicates(); + return tokens; +} + +QList UBWidgetInspector::buildStyleSheetSources(const QList &hierarchy) +{ + QList sources; + + if (!hierarchy.isEmpty()) { + sources << StyleSheetSource{QStringLiteral("widgetQss %1").arg(describeWidget(hierarchy.first())), + hierarchy.first()->styleSheet()}; + } + + for (int index = 1; index < hierarchy.size(); ++index) { + sources << StyleSheetSource{QStringLiteral("parentQss %1").arg(describeWidget(hierarchy.at(index))), + hierarchy.at(index)->styleSheet()}; + } + + sources << StyleSheetSource{QStringLiteral("appQss"), qApp ? qApp->styleSheet() : QString()}; + return sources; +} + +QString UBWidgetInspector::buildRelevantStylesSection(const QList &sources, const QStringList &selectorTokens) +{ + QStringList sections; + sections << QStringLiteral("Relevant Style Rules"); + + for (const StyleSheetSource &source : sources) { + const QStringList relevantRules = filterRelevantRules(source.styleSheet, selectorTokens); + if (relevantRules.isEmpty()) + continue; + + sections << QStringLiteral("%1\n%2").arg(source.label, relevantRules.join(QStringLiteral("\n\n"))); + } + + if (sections.size() == 1) + sections << QStringLiteral("No selector block referencing the target hierarchy was found."); + + return sections.join(QStringLiteral("\n\n")); +} + +QStringList UBWidgetInspector::filterRelevantRules(const QString &styleSheet, const QStringList &selectorTokens) +{ + QStringList relevantRules; + + for (const StyleRule &rule : parseStyleRules(styleSheet)) { + const QStringList matchedTokens = matchedTokensForSelectors(rule.selectors, selectorTokens); + if (matchedTokens.isEmpty()) + continue; + + relevantRules << QStringLiteral("[matches: %1]\n%2 {\n%3\n}") + .arg(matchedTokens.join(QStringLiteral(", ")), + rule.selectors.trimmed(), + indentMultiline(rule.body.trimmed(), QStringLiteral(" "))); + } + + return relevantRules; +} + +QList UBWidgetInspector::parseStyleRules(const QString &styleSheet) +{ + const QString source = stripComments(styleSheet); + QList rules; + int position = 0; + + while (position < source.size()) { + const int openBrace = source.indexOf(QChar('{'), position); + if (openBrace < 0) + break; + + int depth = 1; + int cursor = openBrace + 1; + while (cursor < source.size() && depth > 0) { + if (source.at(cursor) == QChar('{')) + ++depth; + else if (source.at(cursor) == QChar('}')) + --depth; + ++cursor; + } + + if (depth != 0) + break; + + const QString selectors = source.mid(position, openBrace - position).trimmed(); + const QString body = source.mid(openBrace + 1, cursor - openBrace - 2).trimmed(); + if (!selectors.isEmpty() && !body.isEmpty()) + rules << StyleRule{selectors, body}; + + position = cursor; + } + + return rules; +} + +QString UBWidgetInspector::stripComments(const QString &styleSheet) +{ + QString stripped = styleSheet; + static const QRegularExpression commentPattern(QStringLiteral("/\\*.*?\\*/"), + QRegularExpression::DotMatchesEverythingOption); + stripped.remove(commentPattern); + return stripped; +} + +QStringList UBWidgetInspector::matchedTokensForSelectors(const QString &selectors, const QStringList &selectorTokens) +{ + QStringList matchedTokens; + const QStringList selectorParts = selectors.split(QChar(','), Qt::SkipEmptyParts); + + for (const QString &selectorPart : selectorParts) { + const QString selector = selectorPart.trimmed(); + if (selector.isEmpty()) + continue; + + for (const QString &token : selectorTokens) { + if (selector.contains(token)) + matchedTokens << token; + } + } + + matchedTokens.removeDuplicates(); + return matchedTokens; +} + +QString UBWidgetInspector::indentMultiline(const QString &text, const QString &indent) +{ + QStringList lines = normalizeStyleSheet(text).split(QChar('\n')); + for (QString &line : lines) + line.prepend(indent); + return lines.join(QStringLiteral("\n")); +} + +QString UBWidgetInspector::normalizeStyleSheet(const QString &styleSheet) +{ + QString normalized = styleSheet.trimmed(); + normalized.replace(QStringLiteral("\r\n"), QStringLiteral("\n")); + normalized.replace(QChar('\r'), QChar('\n')); + return normalized; +} diff --git a/src/core/UBWidgetInspector.h b/src/core/UBWidgetInspector.h new file mode 100644 index 000000000..551938130 --- /dev/null +++ b/src/core/UBWidgetInspector.h @@ -0,0 +1,60 @@ +#ifndef UBWIDGETINSPECTOR_H_ +#define UBWIDGETINSPECTOR_H_ + +#include +#include +#include +#include + +class QDialog; +class QEvent; +class QPlainTextEdit; +class QWidget; + +class UBWidgetInspector : public QObject +{ + Q_OBJECT + +public: + explicit UBWidgetInspector(QObject *parent = nullptr); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; + +private: + struct StyleSheetSource + { + QString label; + QString styleSheet; + }; + + struct StyleRule + { + QString selectors; + QString body; + }; + + void inspectWidgetUnderCursor(); + QString buildInfo(const QWidget *widget) const; + void showInspector(const QString &info); + void ensureInspectorDialog(); + void positionInspector(); + + static QString describeWidget(const QWidget *widget); + static QList buildWidgetHierarchy(const QWidget *widget); + static QString buildHierarchySection(const QList &hierarchy); + static QStringList buildSelectorTokens(const QList &hierarchy); + static QList buildStyleSheetSources(const QList &hierarchy); + static QString buildRelevantStylesSection(const QList &sources, const QStringList &selectorTokens); + static QStringList filterRelevantRules(const QString &styleSheet, const QStringList &selectorTokens); + static QList parseStyleRules(const QString &styleSheet); + static QString stripComments(const QString &styleSheet); + static QStringList matchedTokensForSelectors(const QString &selectors, const QStringList &selectorTokens); + static QString indentMultiline(const QString &text, const QString &indent); + static QString normalizeStyleSheet(const QString &styleSheet); + + QPointer mInspectorDialog; + QPointer mInspectorView; +}; + +#endif /* UBWIDGETINSPECTOR_H_ */ diff --git a/src/core/core.pri b/src/core/core.pri index 3c10d3419..09ad83dee 100644 --- a/src/core/core.pri +++ b/src/core/core.pri @@ -16,6 +16,7 @@ HEADERS += src/core/UB.h \ src/core/UBDownloadManager.h \ src/core/UBDownloadThread.h \ src/core/UBTextTools.h \ + src/core/UBWidgetInspector.h \ src/core/UBPersistenceWorker.h SOURCES += src/core/main.cpp \ @@ -35,4 +36,5 @@ SOURCES += src/core/main.cpp \ src/core/UBDownloadManager.cpp \ src/core/UBDownloadThread.cpp \ src/core/UBTextTools.cpp \ + src/core/UBWidgetInspector.cpp \ src/core/UBPersistenceWorker.cpp diff --git a/src/core/main.cpp b/src/core/main.cpp index 03db78ed9..985ea0512 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -28,12 +28,14 @@ #include - #include "frameworks/UBPlatformUtils.h" #include "frameworks/UBFileSystemUtils.h" #include "UBApplication.h" #include "UBSettings.h" +#ifdef QT_DEBUG +#include "UBWidgetInspector.h" +#endif /* Uncomment this for memory leaks detection */ /* @@ -134,6 +136,10 @@ int main(int argc, char *argv[]) UBApplication app("OpenBoard", argc, argv); +#ifdef QT_DEBUG + app.installEventFilter(new UBWidgetInspector(&app)); +#endif + QStringList args = app.arguments(); QString dumpPath = UBSettings::userDataDirectory() + "/log"; diff --git a/src/desktop/UBDesktopAnnotationController.cpp b/src/desktop/UBDesktopAnnotationController.cpp index 788ba7013..14948b3a7 100644 --- a/src/desktop/UBDesktopAnnotationController.cpp +++ b/src/desktop/UBDesktopAnnotationController.cpp @@ -99,7 +99,9 @@ UBDesktopAnnotationController::UBDesktopAnnotationController(QObject *parent, UB mTransparentDrawingView->setAcceptDrops(true); - QString backgroundStyle = "QWidget {background-color: rgba(127, 127, 127, 0)}"; + QString backgroundStyle = + "QGraphicsView { background-color: rgba(127, 127, 127, 0); }" + "QWidget#qt_scrollarea_viewport { background-color: rgba(127, 127, 127, 0); }"; mTransparentDrawingView->setStyleSheet(backgroundStyle); mTransparentDrawingScene = std::make_shared(nullptr, false); @@ -149,10 +151,7 @@ UBDesktopAnnotationController::UBDesktopAnnotationController(QObject *parent, UB mDesktopMarkerPalette = new UBDesktopMarkerPalette(mTransparentDrawingView, rightPalette, "desktop"); mDesktopEraserPalette = new UBDesktopEraserPalette(mTransparentDrawingView, rightPalette, "desktop"); - mDesktopPalette->setBackgroundBrush(UBSettings::settings()->opaquePaletteColor); - mDesktopPenPalette->setBackgroundBrush(UBSettings::settings()->opaquePaletteColor); - mDesktopMarkerPalette->setBackgroundBrush(UBSettings::settings()->opaquePaletteColor); - mDesktopEraserPalette->setBackgroundBrush(UBSettings::settings()->opaquePaletteColor); + mDesktopPalette->setBackgroundBrush(QBrush(UBSettings::settings()->opaquePaletteColor)); // Hack : the size of the property palettes is computed the first time the palette is visible diff --git a/src/desktop/UBDesktopPropertyPalette.cpp b/src/desktop/UBDesktopPropertyPalette.cpp index 912f48cff..50b3c6488 100644 --- a/src/desktop/UBDesktopPropertyPalette.cpp +++ b/src/desktop/UBDesktopPropertyPalette.cpp @@ -35,7 +35,6 @@ #include "gui/UBMainWindow.h" #include "gui/UBToolbarButtonGroup.h" #include "gui/UBRightPalette.h" -#include "core/UBThemeManager.h" #include "core/memcheck.h" @@ -43,8 +42,8 @@ UBDesktopPropertyPalette::UBDesktopPropertyPalette(QWidget *parent, UBRightPalet :UBPropertyPalette(Qt::Horizontal, parent) ,rightPalette(_rightPalette) { - updateStyleSheet(); - connect(UBThemeManager::instance(), &UBThemeManager::themeChanged, this, &UBDesktopPropertyPalette::updateStyleSheet); + setObjectName("DesktopPropertyPalette"); + setAttribute(Qt::WA_StyledBackground, true); } int UBDesktopPropertyPalette::getParentRightOffset() @@ -52,18 +51,6 @@ int UBDesktopPropertyPalette::getParentRightOffset() return rightPalette->width(); } -void UBDesktopPropertyPalette::updateStyleSheet() -{ - if (UBThemeManager::instance()->isDarkMode()) - { - setStyleSheet("QWidget { background: qlineargradient(x1:0, y1:0.49, x2:0, y2:0.5, stop:0 #505050, stop:1 #3a3a3a); }"); - } - else - { - setStyleSheet("QWidget { background: qlineargradient(x1:0, y1:0.49, x2:0, y2:0.5, stop:0 #c3c3c3, stop:1 #b4b4b4); }"); - } -} - UBDesktopPenPalette::UBDesktopPenPalette(QWidget *parent, UBRightPalette* rightPalette, QString objectNamePrefix) : UBDesktopPropertyPalette(parent, rightPalette) diff --git a/src/desktop/UBDesktopPropertyPalette.h b/src/desktop/UBDesktopPropertyPalette.h index 455f90736..62652ca06 100644 --- a/src/desktop/UBDesktopPropertyPalette.h +++ b/src/desktop/UBDesktopPropertyPalette.h @@ -45,7 +45,6 @@ class UBDesktopPropertyPalette : public UBPropertyPalette UBDesktopPropertyPalette(QWidget *parent, UBRightPalette* _rightPalette); private: UBRightPalette* rightPalette; - void updateStyleSheet(); protected: virtual int getParentRightOffset(); }; diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index 832802bc8..3d3c69c0f 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -1682,7 +1682,7 @@ void UBDocumentTreeItemDelegate::processChangedText(const QString &str) const } else { - editor->setStyleSheet("background-color: #FFFFFF;"); + editor->setStyleSheet(""); } } } @@ -2189,8 +2189,6 @@ void UBDocumentController::setupViews() mDocumentUI->thumbnailWidget->setDocument(UBDocument::getDocument(proxy)); }); - mDocumentUI->thumbnailWidget->setBackgroundBrush(UBSettings::documentViewLightColor); - #ifdef Q_WS_MACX mMessageWindow = new UBMessageWindow(NULL); #else diff --git a/src/domain/UBGraphicsItemDelegate.cpp b/src/domain/UBGraphicsItemDelegate.cpp index 846fb20ec..e4193c836 100644 --- a/src/domain/UBGraphicsItemDelegate.cpp +++ b/src/domain/UBGraphicsItemDelegate.cpp @@ -1456,7 +1456,7 @@ void DelegateMediaControl::paint(QPainter *painter, int radius = frameWidth-clearance; QRectF r(position - radius, clearance+mSeecAreaBorderHeight, radius * 2, radius * 2); - painter->setBrush(UBSettings::documentViewLightColor); + painter->setBrush(UBSettings::documentThumbnailsViewColor); painter->setPen(Qt::black); painter->drawEllipse(r); } diff --git a/src/gui/UBActionPalette.cpp b/src/gui/UBActionPalette.cpp index f39f1fbff..66d241a09 100644 --- a/src/gui/UBActionPalette.cpp +++ b/src/gui/UBActionPalette.cpp @@ -66,7 +66,6 @@ void UBActionPalette::init(Qt::Orientation orientation) m_customCloseProcessing = false; mButtonSize = QSize(32, 32); - mIsClosable = false; mAutoClose = false; mActionGroup = nullptr; mToolButtonStyle = Qt::ToolButtonIconOnly; @@ -228,7 +227,7 @@ void UBActionPalette::updateLayout() void UBActionPalette::setClosable(bool pClosable) { - mIsClosable = pClosable; + UBFloatingPalette::setClosable(pClosable); updateLayout(); } @@ -236,7 +235,7 @@ void UBActionPalette::setClosable(bool pClosable) int UBActionPalette::border() { - if (mIsClosable) + if (isClosable()) return 10; else return 5; @@ -246,12 +245,11 @@ int UBActionPalette::border() void UBActionPalette::paintEvent(QPaintEvent *event) { UBFloatingPalette::paintEvent(event); +} - if (mIsClosable) - { - QPainter painter(this); - painter.drawPixmap(0, 0, QPixmap(":/images/close.svg")); - } +void UBActionPalette::onCloseButtonClicked() +{ + close(); } @@ -266,13 +264,6 @@ void UBActionPalette::close() void UBActionPalette::mouseReleaseEvent(QMouseEvent * event) { - if (mIsClosable && event->pos().x() >= 0 && event->pos().x() < QPixmap(":/images/close.svg").width() - && event->pos().y() >= 0 && event->pos().y() < QPixmap(":/images/close.svg").height()) - { - event->accept(); - close(); - } - UBFloatingPalette::mouseReleaseEvent(event); } @@ -310,7 +301,7 @@ UBActionPaletteButton::UBActionPaletteButton(QAction* action, QWidget * parent) { setIconSize(QSize(32, 32)); setDefaultAction(action); - setStyleSheet(QString("QToolButton {color: white; font-weight: bold; font-family: Arial; background-color: transparent; border: none}")); + setStyleSheet(QString("QToolButton {color: palette(button-text); font-weight: bold; font-family: Arial; background-color: transparent; border: none}")); setFocusPolicy(Qt::NoFocus); diff --git a/src/gui/UBActionPalette.h b/src/gui/UBActionPalette.h index caea49928..95c036cc2 100644 --- a/src/gui/UBActionPalette.h +++ b/src/gui/UBActionPalette.h @@ -87,6 +87,7 @@ class UBActionPalette : public UBFloatingPalette void customMouseReleased(); protected: + void onCloseButtonClicked() override; virtual void paintEvent(QPaintEvent *event); virtual void mouseReleaseEvent(QMouseEvent * event); virtual void init(Qt::Orientation orientation); @@ -98,7 +99,6 @@ class UBActionPalette : public UBFloatingPalette QList mActions; QMap mMapActionToButton; - bool mIsClosable; Qt::ToolButtonStyle mToolButtonStyle; bool mAutoClose; QSize mButtonSize; diff --git a/src/gui/UBBackgroundPalette.cpp b/src/gui/UBBackgroundPalette.cpp index ca64548f0..8e35f56dd 100644 --- a/src/gui/UBBackgroundPalette.cpp +++ b/src/gui/UBBackgroundPalette.cpp @@ -1,9 +1,12 @@ +#include + #include "UBBackgroundPalette.h" #include "gui/UBBackgroundManager.h" #include "gui/UBFlowLayout.h" #include "gui/UBMainWindow.h" + UBBackgroundPalette::UBBackgroundPalette(QWidget * parent) : UBActionPalette(parent) { @@ -16,13 +19,14 @@ UBBackgroundPalette::UBBackgroundPalette(QWidget * parent) void UBBackgroundPalette::init() { + setObjectName("BackgroundPalette"); + UBActionPalette::clearLayout(); delete layout(); m_customCloseProcessing = false; mButtonSize = QSize(32, 32); - mIsClosable = false; mAutoClose = false; mToolButtonStyle = Qt::ToolButtonIconOnly; mButtons.clear(); @@ -33,6 +37,7 @@ void UBBackgroundPalette::init() mBottomLayout = new QHBoxLayout(); mButtonScrollArea = new QScrollArea{this}; + mButtonScrollArea->setObjectName("BackgroundPaletteScrollArea"); mButtonScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); mButtonScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); mButtonScrollArea->setWidgetResizable(true); @@ -52,17 +57,19 @@ void UBBackgroundPalette::init() mSlider->setTracking(true); // valueChanged() is emitted during movement and not just upon releasing the slider mSliderLabel = new QLabel(tr("Grid size")); + mSliderLabel->setObjectName("BackgroundPaletteLabel"); mLightDarkModeLabel = new QLabel(tr("Switch background color")); + mLightDarkModeLabel->setObjectName("BackgroundPaletteLabel"); mResetDefaultGridSizeButton = createPaletteButton(UBApplication::mainWindow->actionDefaultGridSize, this); - mResetDefaultGridSizeButton->setFixedSize(24,24); + mResetDefaultGridSizeButton->setFixedSize(32,32); mActions << UBApplication::mainWindow->actionDefaultGridSize; UBApplication::mainWindow->actionDefaultGridSize->setProperty("ungrouped", true); // don't add to action group connect(UBApplication::mainWindow->actionDefaultGridSize, &QAction::triggered, this, &UBBackgroundPalette::defaultBackgroundGridSize); mLightDarkModeSwitch = createPaletteButton(UBApplication::mainWindow->actionLightDarkMode, this); - mLightDarkModeSwitch->setFixedSize(44,26); + mLightDarkModeSwitch->setFixedSize(64,32); mLightDarkModeSwitch->setCheckable(true); mActions << UBApplication::mainWindow->actionLightDarkMode; UBApplication::mainWindow->actionLightDarkMode->setProperty("ungrouped", true); // don't add to action group @@ -180,15 +187,20 @@ void UBBackgroundPalette::setActions(QList actions) void UBBackgroundPalette::updateLayout() { if (mToolButtonStyle == Qt::ToolButtonIconOnly) { - mVLayout->setContentsMargins (sLayoutContentMargin / 2 + border(), sLayoutContentMargin / 2 + border() - , sLayoutContentMargin / 2 + border(), sLayoutContentMargin / 2 + border()); + mVLayout->setContentsMargins(sLayoutContentMargin / 2 + border(), + sLayoutContentMargin / 2 + border(), + sLayoutContentMargin / 2 + border(), + sLayoutContentMargin / 2 + border()); } else { - mVLayout->setContentsMargins (sLayoutContentMargin + border(), sLayoutContentMargin + border() - , sLayoutContentMargin + border(), sLayoutContentMargin + border()); + mVLayout->setContentsMargins(sLayoutContentMargin + border(), + sLayoutContentMargin + border(), + sLayoutContentMargin + border(), + sLayoutContentMargin + border()); } + update(); } @@ -276,19 +288,6 @@ void UBBackgroundPalette::changeBackground(bool checked) void UBBackgroundPalette::backgroundChanged() { - bool dark = UBApplication::boardController->activeScene()->isDarkBackground(); - - if (dark) - { - mSliderLabel->setStyleSheet("QLabel { color : white; }"); - mLightDarkModeLabel->setStyleSheet("QLabel { color : white; }"); - } - else - { - mSliderLabel->setStyleSheet("QLabel { color : black; }"); - mLightDarkModeLabel->setStyleSheet("QLabel { color : black; }"); - } - updateActions(); } diff --git a/src/gui/UBCachePropertiesWidget.cpp b/src/gui/UBCachePropertiesWidget.cpp index da06b9313..aa5808df8 100644 --- a/src/gui/UBCachePropertiesWidget.cpp +++ b/src/gui/UBCachePropertiesWidget.cpp @@ -69,8 +69,7 @@ UBCachePropertiesWidget::UBCachePropertiesWidget(QWidget *parent, const char *na mName = "CachePropWidget"; mVisibleState = false; - mIconToLeft = QPixmap(":images/cache_open.png"); - mIconToRight = QPixmap(":images/cache_close.png"); + mTabIcon = QPixmap(":/images/toolPalette/cacheTool.png").scaled(18, 18, Qt::KeepAspectRatio, Qt::SmoothTransformation); setContentsMargins(10, 10, 10, 10); // Build the UI diff --git a/src/gui/UBDockDownloadWidget.cpp b/src/gui/UBDockDownloadWidget.cpp index 60c03f74b..03165b2ef 100644 --- a/src/gui/UBDockDownloadWidget.cpp +++ b/src/gui/UBDockDownloadWidget.cpp @@ -33,6 +33,8 @@ #include "globals/UBGlobals.h" #include "core/memcheck.h" +#include +#include UBDockDownloadWidget::UBDockDownloadWidget(QWidget *parent, const char *name):UBDockPaletteWidget(parent, name) , mpLayout(NULL) @@ -43,8 +45,7 @@ UBDockDownloadWidget::UBDockDownloadWidget(QWidget *parent, const char *name):UB SET_STYLE_SHEET(); - mIconToLeft = QPixmap(":images/download_open.png"); - mIconToRight = QPixmap(":images/download_close.png"); + mTabIcon = QApplication::style()->standardIcon(QStyle::SP_DriveHDIcon).pixmap(18, 18); mpLayout = new QVBoxLayout(this); setLayout(mpLayout); diff --git a/src/gui/UBDockPalette.cpp b/src/gui/UBDockPalette.cpp index a1bc3dc74..4184011b1 100644 --- a/src/gui/UBDockPalette.cpp +++ b/src/gui/UBDockPalette.cpp @@ -624,7 +624,8 @@ void UBTabDockPalette::paintEvent(QPaintEvent *) UBDockPaletteWidget* pCrntWidget = dock->mTabWidgets.at(i); QPainterPath path; path.setFillRule(Qt::WindingFill); - QPixmap iconPixmap; + Qt::ArrowType arrow = Qt::RightArrow; + QPixmap tabIcon; switch (dock->mOrientation) { case eUBDockOrientation_Left: @@ -632,13 +633,11 @@ void UBTabDockPalette::paintEvent(QPaintEvent *) path.addRoundedRect(0, yFrom, width(), TABSIZE, dock->radius(), dock->radius()); if (pCrntWidget) { if(dock->mCollapseWidth >= dock->width()) { - // Get the collapsed icon - iconPixmap = pCrntWidget->iconToRight(); + arrow = Qt::RightArrow; } else { - // Get the expanded icon - iconPixmap = pCrntWidget->iconToLeft(); + arrow = Qt::LeftArrow; } - + tabIcon = pCrntWidget->tabIcon(); } break; @@ -647,12 +646,11 @@ void UBTabDockPalette::paintEvent(QPaintEvent *) path.addRoundedRect(0, yFrom, width(), TABSIZE, dock->radius(), dock->radius()); if (pCrntWidget) { if(dock->mCollapseWidth >= dock->width()) { - // Get the collapsed icon - iconPixmap = pCrntWidget->iconToLeft(); + arrow = Qt::LeftArrow; } else { - // Get the expanded icon - iconPixmap = pCrntWidget->iconToRight(); + arrow = Qt::RightArrow; } + tabIcon = pCrntWidget->tabIcon(); } break; @@ -671,7 +669,37 @@ void UBTabDockPalette::paintEvent(QPaintEvent *) } painter.drawPath(path); - painter.drawPixmap(2, yFrom + 2, width() - 4, TABSIZE - 4, iconPixmap); + + // Optional tab icon + if (!tabIcon.isNull()) { + qreal iconTarget = 18.0; + QPixmap iconScaled = tabIcon.scaled(iconTarget, iconTarget, Qt::KeepAspectRatio, Qt::SmoothTransformation); + QPointF iconPos((width() - iconScaled.width()) / 2.0, yFrom + 4); + painter.drawPixmap(iconPos, iconScaled); + } + + const qreal arrowSize = 18.0; + QRectF arrowRect((width() - arrowSize) / 2.0, + yFrom + TABSIZE - arrowSize - 4, + arrowSize, + arrowSize); + QPainterPath arrowPath; + // right-pointing triangle within arrowRect + arrowPath.moveTo(arrowRect.left() + arrowRect.width() * 0.70, arrowRect.center().y()); + arrowPath.lineTo(arrowRect.left() + arrowRect.width() * 0.35, arrowRect.top() + arrowRect.height() * 0.20); + arrowPath.lineTo(arrowRect.left() + arrowRect.width() * 0.35, arrowRect.bottom() - arrowRect.height() * 0.20); + arrowPath.closeSubpath(); + if (arrow == Qt::LeftArrow) { + QTransform mirror; + mirror.scale(-1, 1); + mirror.translate(-(arrowRect.left() + arrowRect.right()), 0); + arrowPath = mirror.map(arrowPath); + } + QColor arrowColor = dock->palette().color(QPalette::ButtonText); + if (dock->mCurrentTab != i) { + arrowColor.setAlphaF(0.65); + } + painter.fillPath(arrowPath, arrowColor); yFrom += (TABSIZE + dock->tabSpacing()); painter.restore(); } diff --git a/src/gui/UBDockPaletteWidget.cpp b/src/gui/UBDockPaletteWidget.cpp index 406d533a5..3526a38e2 100644 --- a/src/gui/UBDockPaletteWidget.cpp +++ b/src/gui/UBDockPaletteWidget.cpp @@ -41,16 +41,6 @@ UBDockPaletteWidget::~UBDockPaletteWidget() } -QPixmap UBDockPaletteWidget::iconToRight() -{ - return mIconToRight; -} - -QPixmap UBDockPaletteWidget::iconToLeft() -{ - return mIconToLeft; -} - QString UBDockPaletteWidget::name() { return mName; diff --git a/src/gui/UBDockPaletteWidget.h b/src/gui/UBDockPaletteWidget.h index 2f5c4a38d..dffd52671 100644 --- a/src/gui/UBDockPaletteWidget.h +++ b/src/gui/UBDockPaletteWidget.h @@ -54,8 +54,7 @@ class UBDockPaletteWidget : public QWidget UBDockPaletteWidget(QWidget* parent=0, const char* name="UBDockPaletteWidget"); ~UBDockPaletteWidget(); - QPixmap iconToRight(); - QPixmap iconToLeft(); + QPixmap tabIcon() const { return mTabIcon; } QString name(); virtual bool visibleInMode(eUBDockPaletteWidgetMode mode) = 0; @@ -74,8 +73,7 @@ public slots: protected: - QPixmap mIconToRight; // arrow like this: > - QPixmap mIconToLeft; // arrow like this: < + QPixmap mTabIcon; // optional pictogram shown on tab QString mName; /* The current widget available mode list */ diff --git a/src/gui/UBDocumentThumbnailsView.cpp b/src/gui/UBDocumentThumbnailsView.cpp index 3c77048d0..9468aa5b3 100644 --- a/src/gui/UBDocumentThumbnailsView.cpp +++ b/src/gui/UBDocumentThumbnailsView.cpp @@ -62,6 +62,7 @@ UBDocumentThumbnailsView::UBDocumentThumbnailsView(QWidget* parent) setFrameShape(QFrame::NoFrame); setAlignment(Qt::AlignLeft | Qt::AlignTop); + QGraphicsView::setBackgroundBrush(QBrush(UBSettings::documentThumbnailsViewColor)); } @@ -134,15 +135,6 @@ void UBDocumentThumbnailsView::clearSelection() } } -void UBDocumentThumbnailsView::setBackgroundBrush(const QBrush& brush) -{ - if (mDocument) - { - mDocument->thumbnailScene()->setBackgroundBrush(brush); - } -} - - void UBDocumentThumbnailsView::mousePressEvent(QMouseEvent *event) { mClickTime.restart(); diff --git a/src/gui/UBDocumentThumbnailsView.h b/src/gui/UBDocumentThumbnailsView.h index fd616ec77..a88c228dd 100644 --- a/src/gui/UBDocumentThumbnailsView.h +++ b/src/gui/UBDocumentThumbnailsView.h @@ -65,8 +65,6 @@ class UBDocumentThumbnailsView : public UBThumbnailsView return mThumbnailWidth; } - void setBackgroundBrush(const QBrush& brush); - public slots: void setThumbnailWidth(qreal pThumbnailWidth); void sceneSelectionChanged(); diff --git a/src/gui/UBDownloadWidget.cpp b/src/gui/UBDownloadWidget.cpp index d4120f076..132743380 100644 --- a/src/gui/UBDownloadWidget.cpp +++ b/src/gui/UBDownloadWidget.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "UBDownloadWidget.h" @@ -135,7 +136,7 @@ void UBDownloadWidget::addCurrentDownloads() mpItem = new QTreeWidgetItem(mpTree); mpItem->setText(eItemColumn_Desc, actualDL.at(i).name); mpItem->setData(eItemColumn_Desc, Qt::UserRole, QVariant(actualDL.at(i).id)); - mpItem->setIcon(eItemColumn_Close, QIcon(":images/close.svg")); + mpItem->setIcon(eItemColumn_Close, style()->standardIcon(QStyle::SP_TitleBarCloseButton, nullptr, this)); mpTree->addTopLevelItem(mpItem); mpItem = new QTreeWidgetItem(mpTree); mpItem->setData(eItemColumn_Desc, Qt::UserRole, actualDL.at(i).currentSize); diff --git a/src/gui/UBFeaturesWidget.cpp b/src/gui/UBFeaturesWidget.cpp index cf2aba36d..ed680cb1f 100644 --- a/src/gui/UBFeaturesWidget.cpp +++ b/src/gui/UBFeaturesWidget.cpp @@ -59,8 +59,7 @@ UBFeaturesWidget::UBFeaturesWidget(QWidget *parent, const char *name) SET_STYLE_SHEET(); - mIconToLeft = QPixmap(":images/library_open.png"); - mIconToRight = QPixmap(":images/library_close.png"); + mTabIcon = QPixmap(":/images/libpalette/ApplicationsCategory.svg").scaled(18, 18, Qt::KeepAspectRatio, Qt::SmoothTransformation); setAcceptDrops(true); //Main UBFeature functionality diff --git a/src/gui/UBFloatingPalette.cpp b/src/gui/UBFloatingPalette.cpp index dd3baacff..5690f3282 100644 --- a/src/gui/UBFloatingPalette.cpp +++ b/src/gui/UBFloatingPalette.cpp @@ -29,6 +29,7 @@ #include #include +#include #include "UBFloatingPalette.h" @@ -43,8 +44,10 @@ UBFloatingPalette::UBFloatingPalette(Qt::Corner position, QWidget *parent) , mCustomPosition(false) , mIsMoving(false) , mCanBeMinimized(false) + , mIsClosable(false) , mMinimizedLocation(eMinimizedLocation_None) , mDefaultPosition(position) + , mCloseButton(nullptr) { setCursor(Qt::ArrowCursor); @@ -70,9 +73,35 @@ UBFloatingPalette::UBFloatingPalette(Qt::Corner position, QWidget *parent) } mBackgroundBrush = QBrush(UBSettings::paletteColor); + QPalette pal = palette(); + pal.setBrush(QPalette::Window, mBackgroundBrush); + setPalette(pal); mbGrip = true; } +void UBFloatingPalette::setClosable(bool closable) +{ + mIsClosable = closable; + + if (mIsClosable) + { + buildCloseButton(); + mCloseButton->show(); + mCloseButton->raise(); + } + else if (mCloseButton) + { + mCloseButton->hide(); + } + + update(); +} + +bool UBFloatingPalette::isClosable() const +{ + return mIsClosable; +} + void UBFloatingPalette::setGrip(bool newGrip) { mbGrip = newGrip; @@ -85,6 +114,9 @@ void UBFloatingPalette::setBackgroundBrush(const QBrush& brush) if (mBackgroundBrush != brush) { mBackgroundBrush = brush; + QPalette pal = palette(); + pal.setBrush(QPalette::Window, mBackgroundBrush); + setPalette(pal); update(); } } @@ -110,6 +142,15 @@ int UBFloatingPalette::border() return 0; } +int UBFloatingPalette::closeButtonMargin() const +{ + return 10; +} + +void UBFloatingPalette::onCloseButtonClicked() +{ + hide(); +} void UBFloatingPalette::enterEvent(UB::EnterEvent *event) { @@ -262,17 +303,13 @@ void UBFloatingPalette::removeAllAssociatedPalette() } } -void UBFloatingPalette::showEvent(QShowEvent *) -{ - moveInsideParent(pos()); -} - void UBFloatingPalette::paintEvent(QPaintEvent *) { QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::NoPen); - painter.setBrush(mBackgroundBrush); + painter.setBrush(palette().brush(QPalette::Window)); if(mbGrip) { @@ -282,11 +319,12 @@ void UBFloatingPalette::paintEvent(QPaintEvent *) borderPath.addRoundedRect(0, 0, width(), height(), radius(), radius()); borderPath.addRoundedRect(border(), border(), width() - 2 * border(), height() - 2 * border(), radius(), radius()); painter.drawPath(borderPath); - painter.setBrush(mBackgroundBrush); + painter.setBrush(palette().brush(QPalette::Window)); painter.drawRoundedRect(border(), border(), width() - 2 * border(), height() - 2 * border(), radius(), radius()); } else { + painter.setBrush(palette().brush(QPalette::Window)); painter.drawRoundedRect(border(), border(), width() - 2 * border(), height() - 2 * border(), radius(), radius()); } } @@ -296,6 +334,29 @@ int UBFloatingPalette::gripSize() return 5; } +void UBFloatingPalette::buildCloseButton() +{ + if (mCloseButton) + return; + + mCloseButton = new QToolButton(this); + mCloseButton->setObjectName("closeButton"); + mCloseButton->setAutoRaise(true); + mCloseButton->setToolButtonStyle(Qt::ToolButtonIconOnly); + mCloseButton->setText(QString()); + mCloseButton->setFixedSize(28, 28); + mCloseButton->setIconSize(QSize(12, 12)); + mCloseButton->setIcon(QIcon(":/images/close-no-bg.png")); + mCloseButton->setToolTip(tr("Close")); + const int margin = closeButtonMargin(); + mCloseButton->move(margin, margin); + mCloseButton->hide(); + + connect(mCloseButton, &QToolButton::clicked, this, [this]() { + onCloseButtonClicked(); + }); +} + void UBFloatingPalette::minimizePalette(const QPoint& pos) { if(!mCanBeMinimized) diff --git a/src/gui/UBFloatingPalette.h b/src/gui/UBFloatingPalette.h index 6f2118903..54b64da79 100644 --- a/src/gui/UBFloatingPalette.h +++ b/src/gui/UBFloatingPalette.h @@ -32,6 +32,7 @@ #include #include +#include #include "core/UB.h" @@ -71,18 +72,20 @@ class UBFloatingPalette : public QWidget void setBackgroundBrush(const QBrush& brush); void setGrip(bool newGrip); + void setClosable(bool closable); + bool isClosable() const; void setMinimizePermission(bool permission); protected: - virtual void enterEvent(UB::EnterEvent *event) override; - virtual void showEvent(QShowEvent *event) override; virtual void paintEvent(QPaintEvent *event) override; virtual int radius(); virtual int border(); virtual int gripSize(); + virtual int closeButtonMargin() const; + virtual void onCloseButtonClicked(); QBrush mBackgroundBrush; bool mbGrip; @@ -97,14 +100,17 @@ class UBFloatingPalette : public QWidget eMinimizedLocation minimizedLocation(){return mMinimizedLocation;} private: + void buildCloseButton(); void removeAllAssociatedPalette(); void minimizePalette(const QPoint& pos); QList mAssociatedPalette; QPoint mDragPosition; bool mCanBeMinimized; + bool mIsClosable; eMinimizedLocation mMinimizedLocation; Qt::Corner mDefaultPosition; + QToolButton* mCloseButton; signals: void mouseEntered(); diff --git a/src/gui/UBMessageWindow.cpp b/src/gui/UBMessageWindow.cpp index 99390bd26..08fa88b35 100644 --- a/src/gui/UBMessageWindow.cpp +++ b/src/gui/UBMessageWindow.cpp @@ -37,14 +37,17 @@ UBMessageWindow::UBMessageWindow(QWidget *parent) : UBFloatingPalette(Qt::BottomLeftCorner, parent) , mTimerID(-1) { + setObjectName("UBMessageWindow"); mLayout = new QHBoxLayout(this); - mSpinningWheel = new UBSpinningWheel(parent); - mLabel = new QLabel(parent); - mLabel->setStyleSheet(QString("QLabel { color: white; background-color: transparent; border: none; font-family: Arial; font-size: 14px }")); + mSpinningWheel = new UBSpinningWheel(this); + mSpinningWheel->setObjectName("UBMessageWindowSpinner"); + mLabel = new QLabel(this); + mLabel->setObjectName("UBMessageWindowLabel"); mOriginalAlpha = 255; mLayout->setContentsMargins(radius() + 15, 4, radius() + 15, 4); + mLayout->setSpacing(10); #ifdef Q_OS_OSX mLayout->setContentsMargins(radius() + 15, 8, radius() + 15, 10); diff --git a/src/gui/UBPageNavigationWidget.cpp b/src/gui/UBPageNavigationWidget.cpp index 765f377bf..42ee586e1 100644 --- a/src/gui/UBPageNavigationWidget.cpp +++ b/src/gui/UBPageNavigationWidget.cpp @@ -48,13 +48,13 @@ UBPageNavigationWidget::UBPageNavigationWidget(QWidget *parent, const char *name , mClock(NULL) { setObjectName(name); + setAttribute(Qt::WA_StyledBackground, true); mName = "PageNavigator"; mVisibleState = true; SET_STYLE_SHEET(); - mIconToRight = QPixmap(":images/pages_open.png"); - mIconToLeft = QPixmap(":images/pages_close.png"); + mTabIcon = QPixmap(":/images/toolbar/board.png").scaled(18, 18, Qt::KeepAspectRatio, Qt::SmoothTransformation); // Build the gui mLayout = new QVBoxLayout(this); @@ -71,13 +71,9 @@ UBPageNavigationWidget::UBPageNavigationWidget(QWidget *parent, const char *name mHLayout->addWidget(mPageNbr); mHLayout->addWidget(mClock); - // Configure the page number indicator - mPageNbr->setStyleSheet(QString("QLabel { color: white; background-color: transparent; border: none; font-family: Arial; font-weight: bold; font-size: 20px }")); setPageNumber(0, 0); mPageNbr->setAlignment(Qt::AlignHCenter); - // Configure the clock - mClock->setStyleSheet(QString("QLabel {color: white; background-color: transparent; text-align: center; font-family: Arial; font-weight: bold; font-size: 20px}")); mTimeFormat = QLocale::system().timeFormat(QLocale::ShortFormat); mClock->setAlignment(Qt::AlignHCenter); diff --git a/src/gui/UBSpinningWheel.cpp b/src/gui/UBSpinningWheel.cpp index bb7fecbc4..310841db5 100644 --- a/src/gui/UBSpinningWheel.cpp +++ b/src/gui/UBSpinningWheel.cpp @@ -62,6 +62,7 @@ void UBSpinningWheel::paintEvent(QPaintEvent *event) painter.translate(width() / 2, height() / 2); QPen pen; + pen.setColor(palette().color(QPalette::WindowText)); pen.setWidthF(side / 6.5); pen.setCapStyle(Qt::RoundCap); diff --git a/src/gui/UBStartupHintsPalette.cpp b/src/gui/UBStartupHintsPalette.cpp index 23876345e..ecfce4e3e 100644 --- a/src/gui/UBStartupHintsPalette.cpp +++ b/src/gui/UBStartupHintsPalette.cpp @@ -44,11 +44,11 @@ - UBStartupHintsPalette::UBStartupHintsPalette(QWidget *parent) : UBFloatingPalette(Qt::BottomRightCorner,parent) { setObjectName("UBStartupHintsPalette"); + setClosable(true); setFixedSize(800,600); mLayout = new QVBoxLayout(); @@ -71,9 +71,10 @@ UBStartupHintsPalette::UBStartupHintsPalette(QWidget *parent) : connect(mShowNextTime,SIGNAL(stateChanged(int)),this,SLOT(onShowNextTimeStateChanged(int))); connect(UBThemeManager::instance(), &UBThemeManager::themeChanged, mpSankoreAPI, &UBWidgetUniboardAPI::themeChanged); - + mButtonLayout->addStretch(); mButtonLayout->addWidget(mShowNextTime); + hide(); } @@ -86,28 +87,6 @@ UBStartupHintsPalette::~UBStartupHintsPalette() void UBStartupHintsPalette::paintEvent(QPaintEvent *event) { UBFloatingPalette::paintEvent(event); - - QPainter painter(this); - painter.drawPixmap(0, 0, QPixmap(":/images/close.svg")); -} - - -void UBStartupHintsPalette::close() -{ - hide(); -} - - -void UBStartupHintsPalette::mouseReleaseEvent(QMouseEvent * event) -{ - if (event->pos().x() >= 0 && event->pos().x() < QPixmap(":/images/close.svg").width() - && event->pos().y() >= 0 && event->pos().y() < QPixmap(":/images/close.svg").height()) - { - event->accept(); - close(); - } - - UBFloatingPalette::mouseReleaseEvent(event); } void UBStartupHintsPalette::onShowNextTimeStateChanged(int state) diff --git a/src/gui/UBStartupHintsPalette.h b/src/gui/UBStartupHintsPalette.h index 892ded60e..7f1da6a6b 100644 --- a/src/gui/UBStartupHintsPalette.h +++ b/src/gui/UBStartupHintsPalette.h @@ -53,11 +53,9 @@ public slots: protected: virtual void paintEvent(QPaintEvent *event); - virtual void mouseReleaseEvent(QMouseEvent * event); virtual void showEvent(QShowEvent *event); private: - void close(); int border(); QCheckBox* mShowNextTime; QVBoxLayout* mLayout; diff --git a/src/gui/UBThumbnail.cpp b/src/gui/UBThumbnail.cpp index a78a35b3c..c26e1a6b9 100644 --- a/src/gui/UBThumbnail.cpp +++ b/src/gui/UBThumbnail.cpp @@ -259,8 +259,7 @@ QVariant UBThumbnail::itemChange(GraphicsItemChange change, const QVariant& valu { if (change == QGraphicsItem::ItemSelectedHasChanged) { - const auto penColor = isSelected() ? UBSettings::treeViewBackgroundColor : Qt::transparent; - setPen({penColor, cSelectionWidth}); + update(); } return QGraphicsRectItem::itemChange(change, value); @@ -316,7 +315,7 @@ void UBThumbnail::paint(QPainter* painter, const QStyleOptionGraphicsItem* optio if (isSelected()) { const auto selectionRect = mapRectFromItem(mPixmapItem, mPixmapItem->boundingRect()) + cSelectionMargins; - painter->setPen(pen()); + painter->setPen(QPen(qApp->palette().color(QPalette::Highlight), cSelectionWidth)); painter->drawRect(selectionRect); } diff --git a/src/podcast/UBPodcastRecordingPalette.cpp b/src/podcast/UBPodcastRecordingPalette.cpp index a5cfe2176..8082f27b2 100644 --- a/src/podcast/UBPodcastRecordingPalette.cpp +++ b/src/podcast/UBPodcastRecordingPalette.cpp @@ -200,6 +200,6 @@ void UBVuMeter::paintEvent(QPaintEvent* e) int h = (height() - 8) * mVolume / 255; QRectF rect(0, height() - 4 - h, width(), h); - painter.fillRect(rect, UBSettings::documentViewLightColor); + painter.fillRect(rect, UBSettings::documentThumbnailsViewColor); } From 0b0edeeea3a80cab3f3b264516e8368c9fadec0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Thu, 12 Mar 2026 15:19:33 +0100 Subject: [PATCH 119/133] more tweaks on OpenBoard's style (arrows for treeviews and ddl, spinboxes, etc) --- resources/OpenBoard.qrc | 10 +-- resources/darkTheme.qss | 33 ++++++--- resources/etc/OpenBoard.css | 23 ------ resources/images/down_arrow.png | Bin 1137 -> 0 bytes resources/images/down_arrow.svg | 3 + resources/images/left_arrow.png | Bin 1179 -> 0 bytes resources/images/left_arrow.svg | 3 + resources/images/right_arrow.png | Bin 1125 -> 0 bytes resources/images/right_arrow.svg | 3 + resources/images/up_arrow.png | Bin 1156 -> 0 bytes resources/images/up_arrow.svg | 3 + resources/lightTheme.qss | 30 ++++++-- resources/style.qss | 82 ++++++++++++++++++++- resources/style/treeview-branch-closed.png | Bin 404 -> 0 bytes resources/style/treeview-branch-open.png | Bin 405 -> 0 bytes 15 files changed, 143 insertions(+), 47 deletions(-) delete mode 100644 resources/images/down_arrow.png create mode 100644 resources/images/down_arrow.svg delete mode 100644 resources/images/left_arrow.png create mode 100644 resources/images/left_arrow.svg delete mode 100644 resources/images/right_arrow.png create mode 100644 resources/images/right_arrow.svg delete mode 100644 resources/images/up_arrow.png create mode 100644 resources/images/up_arrow.svg delete mode 100644 resources/style/treeview-branch-closed.png delete mode 100644 resources/style/treeview-branch-open.png diff --git a/resources/OpenBoard.qrc b/resources/OpenBoard.qrc index 73cd9f11d..fe55f1d62 100644 --- a/resources/OpenBoard.qrc +++ b/resources/OpenBoard.qrc @@ -197,8 +197,6 @@ images/addItemToCurrentPage.svg images/addItemToNewPage.svg images/addItemToLibrary.svg - style/treeview-branch-closed.png - style/treeview-branch-open.png webbrowser/closetab.png webbrowser/loading.gif webbrowser/notfound.html @@ -324,10 +322,10 @@ images/cache_open.png images/cache_circle.png images/cache_square.png - images/down_arrow.png - images/up_arrow.png - images/left_arrow.png - images/right_arrow.png + images/down_arrow.svg + images/up_arrow.svg + images/left_arrow.svg + images/right_arrow.svg images/moveUp.svg images/moveDown.svg images/moveDownDisabled.svg diff --git a/resources/darkTheme.qss b/resources/darkTheme.qss index c0fa40ace..72abae0c2 100644 --- a/resources/darkTheme.qss +++ b/resources/darkTheme.qss @@ -138,7 +138,7 @@ QComboBox::drop-down { } QComboBox::down-arrow { - image: url(:/images/down_arrow.png); + image: url(:/images/down_arrow.svg); width: 12px; height: 12px; } @@ -198,13 +198,13 @@ QSpinBox::down-button:hover, QDoubleSpinBox::down-button:hover { } QSpinBox::up-arrow, QDoubleSpinBox::up-arrow { - image: url(:/images/up_arrow.png); + image: url(:/images/up_arrow.svg); width: 10px; height: 10px; } QSpinBox::down-arrow, QDoubleSpinBox::down-arrow { - image: url(:/images/down_arrow.png); + image: url(:/images/down_arrow.svg); width: 10px; height: 10px; } @@ -370,7 +370,18 @@ QGroupBox::title { } /* Tree and List views */ -QTreeView, QListView, QTableView { +QTreeView { + background-color: #2a2a2a; + color: #ffffff; + border: 1px solid #555555; + alternate-background-color: #323232; + selection-background-color: #2a82da; + selection-color: #ffffff; + show-decoration-selected: 0; + outline: none; +} + +QListView, QTableView { background-color: #2a2a2a; color: #ffffff; border: 1px solid #555555; @@ -396,13 +407,18 @@ QTreeView::item:selected, QListView::item:selected, QTableView::item:selected { QTreeView::item:selected:active, QListView::item:selected:active, -QTableView::item:selected:active, -QTreeView::branch:selected { +QTableView::item:selected:active { background: #2a82da; color: #ffffff; border: none; } +QTreeView::branch:selected { + background: transparent; + color: inherit; + border: none; +} + QTreeView QLineEdit, QListView QLineEdit, QTableView QLineEdit { @@ -716,8 +732,8 @@ QSizeGrip { background-color: transparent; } -/* Override OpenBoard.css button group styles for dark mode */ -/* Only override colors, preserve the border structure from OpenBoard.css */ +/* Override base button group colors for dark mode */ +/* Only override colors; the shared geometry lives in style.qss. */ QToolButton#ubButtonGroupLeft, QToolButton#ubButtonGroupCenter, QToolButton#ubButtonGroupRight, @@ -757,4 +773,3 @@ QWidget#UBFeaturesActionBar QToolButton { padding: 0px; } - diff --git a/resources/etc/OpenBoard.css b/resources/etc/OpenBoard.css index 5f76525d0..0c849702d 100644 --- a/resources/etc/OpenBoard.css +++ b/resources/etc/OpenBoard.css @@ -188,28 +188,6 @@ QTreeView::item padding-bottom: 1.5 px; } -QTreeView::branch:has-siblings:!adjoins-item, -QTreeView::branch:!has-children:!has-siblings:adjoins-item, -QTreeView::branch:has-siblings:adjoins-item -{ - border-image: none; - image: none; -} - -QTreeView::branch:has-children:!has-siblings:closed, -QTreeView::branch:closed:has-children:has-siblings -{ - border-image: none; - image: url(:/style/treeview-branch-closed.png); -} - -QTreeView::branch:open:has-children:!has-siblings, -QTreeView::branch:open:has-children:has-siblings -{ - border-image: none; - image: url(:/style/treeview-branch-open.png); -} - QSlider::groove:horizontal { border: 1px solid palette(mid); @@ -321,4 +299,3 @@ QLineEdit#ubWebBrowserLineEdit padding: 2 2px; background: palette(base); } - diff --git a/resources/images/down_arrow.png b/resources/images/down_arrow.png deleted file mode 100644 index 934280f35a2963a943a2d93d9eb2cbb89926e234..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1137 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBQ!3HE-C+YhDDaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#S9F5he4R}c>anMprB-lYeY$Kep*R+Vo@qXKw@TIiJqTph=Qq} zp`M{(7l+t6prReA5uRzDo>~kXKn^Q|6eBAGBar0<#L`eU$T=E}%wTaQAls0Ui9rxZ zM*(qWI}2Dm2gnA21Rw_KhtcS^GB7YRFic=)U;(NzFfuk^TmUf_q=$6@#H?vRHV7~Q zO=1G846?KUvY@&Q4GciCY^GO=H}w};15K3mba4#HaDF<|HbcZwqD_CJ(3aqX^N%TX zY`xWSBC$!r+LPm;0;giHLWjZ(j|mM^w>hcYh>Y?O_~RJB=PMAn@dLjjOTDs$i%USr zmFIIMdE(0U-rYTO_wC#4_s*C*=auh!Z}jzmnuT-xwv7u1?NfTpo&W|%!FK^IsV%qPc$_Yr_2hVL&IPrIa}v7}4o^#x zlHK@_Y2xd-S}$t~m~#!8Z$4*yrL^8vy7o=masBcOXBJ#dQ`miG;oB#Red`1Ry$?LF zQwaZ&#I~vP**)p$dw!$~>m0xN*!$34jqGn4yQS5Bp57*Xww_x-OWuX0@SIsjnFKprsTZN{>9$}Z>Wc1C-Rtj31y=ql?d-%mP;|n!+ z+;`7>zUOV2+Sg;pj+$S%<8n5wf75Q+Gw*l4RZ~7IWUxc}%YyZ33oI|hR9#Zj4-$7M zSbW>$@Qdw|89K9?-}n`K`6`KbFr`@#ss z-0N`PQ11mj%`X=5zV3Rrvif?<^yAU{TBn*+Jy~--{*djK_TP0I?!Nl?t>%1+*`*g8 zdynz7JeIw6^6$KxdAUC#nApr0+I>08)8csj-RG%$K7=tGJd&2lmaEUv{7&xPij%C1 z4oJ#9=DE*Vd;78Br1?b~&G(2q1hhzYZJ2i9`pkzqC$FcJ7goeFrOG%wyIbA+LTXo- zK-0db52G)?{K&QHnp|r6-5B+cFZFaCxfN#oQJa;WF;~)~?_c@$?(_Cr?;5nkFtJTP zz~GhK|Lbn!g_GS6SOruTeP?&xHoZgf`^*O{g^e0>Y+ucOyGeOt&!j!&ySo?Xu?mPJ zZfgPthFffm_^VAUrzR|YDf0c)7o9Fsu`}-$X^Q+~cy#yPfscG!;z60l)78&qol`;+ E03t8M_y7O^ diff --git a/resources/images/down_arrow.svg b/resources/images/down_arrow.svg new file mode 100644 index 000000000..f3c9dd5fc --- /dev/null +++ b/resources/images/down_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/left_arrow.png b/resources/images/left_arrow.png deleted file mode 100644 index 48d6e45cb49bbd1dac0c82f06c7ebb2f2b088993..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1179 zcmeAS@N?(olHy`uVBq!ia0vp^nn3Kp!3HGTXUC-gDaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#S9F5he4R}c>W5I4#^VNh?3y^w370~qEv=}#LT=BJwMkF1yemk zJwwAT4zY7UMLSX>JkvZqwHP>n999M?Mpgz!Aj=DgrJ-z)b2J#4!QxCnwjm=EgCLNO z0^-be7O;2@kPQL}Kn&6kqtR_;U|?oon841!0#svQWNg5=0Aemk59Myben&|H7;uwEGzK{OCyY%<{{I~Dd9JjMoW?B%n_MDoG+wKcIUs&(DrT@75{*rG}67NI4S;?Jc z_ZIjre)YKMzyrS~Ewj5q&VjAf-m6vE_=V0boH(r`{lad~GrekaoZ59JGOSlKwCF70 zeY?TMY0u0f4{Q#_Zn-0*`5{TDc{L~h1t0GvDLdND%q8x4S9BRkinPu;^1$#AugOIr zNzIg9hUU{2^iQ|*esW}|Cy$?MjN@(HhYZVs2F_ognm1Eb=HVF?ws1kYMQ3=0+9w}7 z_(1MZ@sm3XPUH$Tze>mzs?rT)n7LfKII3BH!QW{b6MTRgdkaK!H@h5MV%B-EwPm)( zSE)HuL(~jc#D1|gIW08L^!)&C3?kW%N-)Oq}ZExbKY`gPY&4Plk|bZ z@%EY^s~ys|Gq@Ku?_TI7=WtL;#AxO1H47%5-1#+e$ClFa6(^ot|78%9@+qfQLeHp@ z^W_{FowcbOKPJ}g`WGCrW!>WJtx@$$gMJ<;;J&1&E%9$ZZ`*+<+=tk{ToYov@bN8k z@c+3h>(3N$MkSmS>a2Bbx@a$Pb*Ednx}W}nOG4E(9fy<`G~YP+%l}{J+7yvhzq(fK zOWz?{`Tmc~)Ep<*!~0|eX1q~f;~Zygf3d_p@m0OSSAU6DejZwLuBf>#{`@u0O<#}O z{@b!DHS2@Q3%sugYka@or5vofIN<8^kgv+lcT0LUE=ivA_j`!Ro9^1ilh;{t{q98` zQrx-Rnk)GKjB z?{s_#G7)YK+r%k)_G{3+ZqLTR+P#i$)1#DFTm8yKmi-eCuAjf~+V7CL@6Rqd@FHRH zXZ6KXr};E&fB8>*S^V>wx8K@d|6yD|wZ|#6^xXe51-4S@C(p&`t)1k%BI8E<3gM71 t(xO)#$-daEhaZky*`do`={f&M<`qdyjw1%Zko22WQ%mvv4FO#pb-&G`TT diff --git a/resources/images/left_arrow.svg b/resources/images/left_arrow.svg new file mode 100644 index 000000000..c7d64d1d0 --- /dev/null +++ b/resources/images/left_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/right_arrow.png b/resources/images/right_arrow.png deleted file mode 100644 index a64d932be3efa2da8bc5ed678208f637d0e7692d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1125 zcmeAS@N?(olHy`uVBq!ia0vp^nn3Kp!3HGTXUC-gDaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#S9F5he4R}c>W5I4#^VNh?3y^w370~qEv=}#LT=BJwMkF1yemk zJwwAT4zY7UMLSX>JkvZqwHP>n999M?Mpgz!Aj=DgrJ-z)b2J#4!QxCnwjm=EgCLNO z0^-be7O;2@kPQL}Kn&6kqtR_;U|?oon841!0#svQWNg5=0Aemk59MybenkeY$;uwfG-{;S} zzO-P@n^#UcXDfv;;fpr37wOcEV=OHzDvoft0^8) zL1$EAJI-yCk{6%kG`U{Ii zOZ9D0aW%cT^QFn^rIVK}nc@0Q(dv9w<`P{^HG#RVYd2b1M0#{3x~#rzxBB1`)4Psy z)MkHtvF+CUHQ!PcrB8&abg%nq=g}qlgl*B~wcn14doDb=zc*v*)wr5TBD>CAzggEC zde|H&nD6}Me(65`%d#$YpK9++Zq4{4T{B%|_i4wXB1?}d%e((S?~+mJ|Dm_i`GV(s z)$c_-_dRyiPWj_lGJoIERrSq_`Guw_+{nB7!SfSmWKY6$p!pN`_)Sy%aVIOjX2KPg z^)4SKU;US&d$T2`uBrN0LyGE3&UKFOHe5~EG@-^_OtIqNs|QPTS8~QRB&;~Eb$QAj zw`s~h4rRSuqPjA=ezoAA3{#nPs-=Io$nRtmdU + + diff --git a/resources/images/up_arrow.png b/resources/images/up_arrow.png deleted file mode 100644 index a970f17cb3ed693f4a2e985569ed785dc41c2209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1156 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBQ!3HE-C+YhDDaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#S9F5he4R}c>anMprB-lYeY$Kep*R+Vo@qXKw@TIiJqTph=Qq} zp`M{(7l+t6prReA5uRzDo>~kXKn^Q|6eBAGBar0<#L`eU$T=E}%wTaQAls0Ui9rxZ zM*(qWI}2Dm2gnA21Rw_KhtcS^GB7YRFic=)U;(NzFfuk^TmUf_q=$6@#H?vRHV7~Q zO=1G846?KUvY@&Q4GciCY^GO=H}w};15GsWba4#HaDF=Tem8HT#PPMRBIb*9iWG0& z(TMzcv+Ua&x4>H}Pvjq*T6*;AmAH;6Ejf#}ZQYXPy;Hg5(4v?{TepUJ-pLEvCi=7H ze)+UM+uhdhXI7>^pYwU;`^tOIZPU~4J)gP#yX9xUyK|;+HZ71VmYM64eT9Agg~}^O zzwh_)_d3IyJ1fRH{DR8|r`)eEcZXcO>%sdjkKJun*V&yhd20eRcv|+A2YE9bls{Gy znICn_<52aa4|-qrPC6y!@ZszX_KbxuXUsI*(*Af})OGoL!VUt`2K*PZE(^{*pJ9HS zKk7PvoVX*~exA$CG0oyu%hYY!&G)D_G-lVnbn{)d*rp_>yh2a^#~enj%-=c2Vpi?j zKfO@hd}rfjiN6;;xuza3)H?k6f`88uVTTXx27#yMYOhsEGlsKotKX2 z{5YvoA@=Lsl(`H|_Dwsxg6@a>?6>ihP~yyYzTdft&Huw~!~Tm(mkodaaah~)dTHt6 z$8#9;Ht{V!eueGwMA?0d(vF$u+|97iZJHC~pH{1peUQ6%rM^sZiqd+aB`PFwM`@ED80pTIMz zCbyrSn<_TRz(?p_OP%L3-mVAb30r3FyipP&cYmT;czi^;QLtJ=^R=Wcj1!NF-e;Y9 zJoboj(%mF4y{11EoX_-DeRIHrMp%&`{EZ48slH6N;XPIk&wbfR!JppHAy&B?Du4ujWI>2>% zou|~4hW>4_lY2B6%X4gTe~DWM4fyY|go diff --git a/resources/images/up_arrow.svg b/resources/images/up_arrow.svg new file mode 100644 index 000000000..3bc4a5ca4 --- /dev/null +++ b/resources/images/up_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/lightTheme.qss b/resources/lightTheme.qss index 23d4a8f16..7443bc9c1 100644 --- a/resources/lightTheme.qss +++ b/resources/lightTheme.qss @@ -89,14 +89,14 @@ QDoubleSpinBox::down-button:hover { QSpinBox::up-arrow, QDoubleSpinBox::up-arrow { - image: url(:/images/up_arrow.png); + image: url(:/images/up_arrow.svg); width: 10px; height: 10px; } QSpinBox::down-arrow, QDoubleSpinBox::down-arrow { - image: url(:/images/down_arrow.png); + image: url(:/images/down_arrow.svg); width: 10px; height: 10px; } @@ -107,7 +107,7 @@ QComboBox::drop-down { } QComboBox::down-arrow { - image: url(:/images/down_arrow.png); + image: url(:/images/down_arrow.svg); width: 12px; height: 12px; } @@ -427,7 +427,17 @@ QScrollBar::sub-page:horizontal { background: transparent; } -QTreeView, +QTreeView { + background-color: #ffffff; + color: #1f2937; + border: 1px solid #d9e0e8; + alternate-background-color: #fbfcfe; + selection-background-color: #eaf4ff; + selection-color: #1f2937; + show-decoration-selected: 0; + outline: none; +} + QListView, QTableView { background-color: #ffffff; @@ -444,7 +454,6 @@ QTreeView::item, QListView::item, QTableView::item { padding: 4px; - border-radius: 2px; } QTreeView::item:hover, @@ -462,13 +471,18 @@ QTableView::item:selected { QTreeView::item:selected:active, QListView::item:selected:active, -QTableView::item:selected:active, -QTreeView::branch:selected { +QTableView::item:selected:active { background: #3d8fd1; color: #ffffff; border: none; } +QTreeView::branch:selected { + background: transparent; + color: inherit; + border: none; +} + QTreeView QLineEdit, QListView QLineEdit, QTableView QLineEdit { @@ -624,7 +638,7 @@ QToolTip { color: #1f2937; border: 1px solid #d9e0e8; padding: 6px; - border-radius: 6px; + border-radius: 3px; } #BackgroundPaletteScrollArea { diff --git a/resources/style.qss b/resources/style.qss index 640a55f36..32840a69d 100644 --- a/resources/style.qss +++ b/resources/style.qss @@ -82,6 +82,54 @@ QToolBar QToolButton background: transparent; } +/* Preserve grouped toolbar button geometry across platforms. */ +QToolButton#ubButtonGroupLeft, +QToolButton#desktop-ubButtonGroupLeft +{ + margin-top: 1px; + margin-right: 0px; + padding: 5px; + height: 14px; +} + +QToolButton#ubButtonGroupCenter, +QToolButton#desktop-ubButtonGroupCenter +{ + margin-top: 1px; + margin-right: 0px; + margin-left: 0px; + padding: 5px; + height: 14px; +} + +QToolButton#ubButtonGroupRight, +QToolButton#desktop-ubButtonGroupRight +{ + margin-top: 1px; + margin-left: 0px; + padding: 5px; + height: 14px; +} + +QToolButton#ubButtonGroupLeft:checked, +QToolButton#desktop-ubButtonGroupLeft:checked +{ + padding-right: 4px; +} + +QToolButton#ubButtonGroupCenter:checked, +QToolButton#desktop-ubButtonGroupCenter:checked +{ + padding-right: 4px; + padding-left: 4px; +} + +QToolButton#ubButtonGroupRight:checked, +QToolButton#desktop-ubButtonGroupRight:checked +{ + padding-left: 4px; +} + QLabel#DockPaletteWidgetTitle { color: palette(bright-text); @@ -127,7 +175,7 @@ QComboBox#DockPaletteWidgetComboBox:drop-down QComboBox#DockPaletteWidgetComboBox::down-arrow { - image:url(:/images/down_arrow.png); + image:url(:/images/down_arrow.svg); background: palette(button); border: 2px solid palette(mid); height:16px; @@ -181,6 +229,38 @@ QSlider::groove::horizontal border: 1px solid palette(dark); } +QTreeView::branch:has-siblings:!adjoins-item, +QTreeView::branch:!has-children:!has-siblings:adjoins-item, +QTreeView::branch:has-siblings:adjoins-item +{ + border-image: none; + image: none; + width: 12px; + height: 12px; +} + +QTreeView::branch:has-children:!has-siblings:closed, +QTreeView::branch:closed:has-children:has-siblings, +QTreeView::branch:selected:has-children:!has-siblings:closed, +QTreeView::branch:selected:closed:has-children:has-siblings +{ + border-image: none; + image: url(:/images/right_arrow.svg); + width: 12px; + height: 12px; +} + +QTreeView::branch:open:has-children:!has-siblings, +QTreeView::branch:open:has-children:has-siblings, +QTreeView::branch:selected:open:has-children:!has-siblings, +QTreeView::branch:selected:open:has-children:has-siblings +{ + border-image: none; + image: url(:/images/down_arrow.svg); + width: 12px; + height: 12px; +} + QLabel#UBTGEditionDocumentTitle { color: palette(text); diff --git a/resources/style/treeview-branch-closed.png b/resources/style/treeview-branch-closed.png deleted file mode 100644 index 2c566533e5424e5724028032938f99870a3904e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 404 zcmeAS@N?(olHy`uVBq!ia0vp^96-#&!2%?|PB#$)QY`6?zK#qG8~eHcB(ehe3dtTp zz6=aistgPb%?u1b{{!il3=E|P3=FRl7#OT(FffScPl`Y422{(G&9Lw(k1=&kHeO=j~a&d84=*xB9Q2+|Hd%8G=a9mHGus-0ykMj); zK0NdOFVi|{cz{uuS$XlF{hnNY9!xwv|1BlBM2cH(K4j|Q`7in3`qMToFJl9PQ?jXl zj((W^(EPA|TRcy^#4|%f1IG|YMP_d0rq5G0KK~ai#_`-<`SL!0<9q*75*j%EB)!&9Lw(k1=&kHeO=j~a&d84=*xB9Q2+{cc)B=-a9lU-GUPjCAi(lG zMxjn{f8#89#g9TPLc9t;+*Ky5sBqtKd3k5hgw0bHZ`gbF-5Iaqo>z z40R0+fGEVk!phXl%EVmTz{twLz~naT0u&9o`6-!cmAEyyw(XSxYGCkm^>bP0l+XkK D&53~1 From b214c1ade5dd4cf082c19aa671d53e3b463209a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Mon, 16 Mar 2026 17:59:03 +0100 Subject: [PATCH 120/133] feat: more colors and new color prefs dialog for customization --- resources/darkTheme.qss | 251 ++++++++ resources/etc/OpenBoard.css | 11 + resources/forms/brushProperties.ui | 313 ++-------- resources/forms/mainWindow.ui | 102 ++++ resources/forms/preferences.ui | 202 ++----- resources/lightTheme.qss | 261 ++++++++ src/board/CMakeLists.txt | 2 + src/board/UBBoardController.cpp | 193 +++++- src/board/UBBoardController.h | 11 + src/board/UBColorPreferencesDialog.cpp | 729 +++++++++++++++++++++++ src/board/UBColorPreferencesDialog.h | 152 +++++ src/board/UBDrawingController.cpp | 13 +- src/board/UBDrawingController.h | 1 + src/board/board.pri | 3 +- src/core/UBPreferencesController.cpp | 169 +----- src/core/UBPreferencesController.h | 13 +- src/core/UBSetting.cpp | 45 ++ src/core/UBSetting.h | 4 + src/core/UBSettings.cpp | 143 ++++- src/core/UBSettings.h | 15 + src/core/UBShortcutManager.cpp | 7 +- src/desktop/UBDesktopPropertyPalette.cpp | 19 +- src/gui/UBToolbarButtonGroup.cpp | 85 ++- src/gui/UBToolbarButtonGroup.h | 7 +- 24 files changed, 2088 insertions(+), 663 deletions(-) create mode 100644 src/board/UBColorPreferencesDialog.cpp create mode 100644 src/board/UBColorPreferencesDialog.h diff --git a/resources/darkTheme.qss b/resources/darkTheme.qss index 72abae0c2..944b7eeac 100644 --- a/resources/darkTheme.qss +++ b/resources/darkTheme.qss @@ -66,11 +66,13 @@ QPushButton:hover { QPushButton:pressed { background-color: #2a82da; + color: #ffffff; border: 1px solid #2a82da; } QPushButton:checked { background-color: #2a82da; + color: #ffffff; } QPushButton:disabled { @@ -81,6 +83,7 @@ QPushButton:disabled { QPushButton:default { background-color: #2a82da; + color: #ffffff; border: 2px solid #3d8fd1; } @@ -529,11 +532,13 @@ QToolButton:hover { QToolButton:pressed { background-color: #2a82da; + color: #ffffff; border: 1px solid #2a82da; } QToolButton:checked { background-color: #2a82da; + color: #ffffff; } QToolButton[popupMode="1"] { /* only for MenuButtonPopup */ @@ -766,9 +771,255 @@ QToolButton#desktop-ubButtonGroupCenter:checked, QToolButton#desktop-ubButtonGroupRight:checked { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #2a82da, stop: 1 #1e5fa0); + color: #ffffff; + border: 1px solid #2a82da; +} + +QToolButton#ubButtonGroupRight[colorPaletteConfigButton="true"], +QToolButton#desktop-ubButtonGroupRight[colorPaletteConfigButton="true"] +{ + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #616161, stop: 1 #4a4a4a); + color: #ffffff; + border-top: none; + border-bottom: none; + border-left: none; + border-right: none; +} + +QToolButton#ubButtonGroupRight[colorPaletteConfigButton="true"]:hover, +QToolButton#desktop-ubButtonGroupRight[colorPaletteConfigButton="true"]:hover +{ + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #6c6c6c, stop: 1 #555555); + color: #ffffff; +} + +QToolButton#ubButtonGroupRight[colorPaletteConfigButton="true"]:pressed, +QToolButton#desktop-ubButtonGroupRight[colorPaletteConfigButton="true"]:pressed +{ + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #747474, stop: 1 #5e5e5e); + color: #ffffff; +} + +QDialog#colorPreferencesDialog { + background-color: #353535; +} + +QDialog#colorPreferencesDialog QWidget#colorPreferencesHeader { + background-color: #2b2b2b; + border: 1px solid #555555; + border-radius: 8px; +} + +QDialog#colorPreferencesDialog QLabel#colorPreferencesHeaderLabel { + color: #f8fafc; + font-size: 14px; + font-weight: 600; + background: transparent; +} + +QDialog#colorPreferencesDialog QSlider#colorPreferencesPaletteSizeSlider { + min-width: 190px; + background: transparent; +} + +QDialog#colorPreferencesDialog QSlider#colorPreferencesPaletteSizeSlider::groove:horizontal { + height: 6px; + background-color: #404040; + border: none; + border-radius: 3px; +} + +QDialog#colorPreferencesDialog QSlider#colorPreferencesPaletteSizeSlider::handle:horizontal { + width: 18px; + margin: -7px 0; + background-color: #2a82da; + border: 1px solid #3d8fd1; + border-radius: 9px; +} + +QDialog#colorPreferencesDialog QSlider#colorPreferencesPaletteSizeSlider::sub-page:horizontal { + background-color: #2a82da; + border-radius: 3px; +} + +QDialog#colorPreferencesDialog QLabel#colorPreferencesPaletteSizeValue { + min-width: 32px; + padding: 4px 8px; + background: #2a2a2a; + color: #f8fafc; + border: 1px solid #555555; + border-radius: 4px; + font-size: 14px; + font-weight: 600; +} + +QDialog#colorPreferencesDialog QWidget#colorPreferencesHint { + background: #4b4324; + border: 1px solid #7b6b33; + border-radius: 6px; +} + +QDialog#colorPreferencesDialog QLabel#colorPreferencesHintIcon { + background: transparent; + min-width: 20px; +} + +QDialog#colorPreferencesDialog QLabel#colorPreferencesHintText { + background: transparent; + color: #f1e3a8; + font-size: 12px; + line-height: 1.3em; +} + +QDialog#colorPreferencesDialog QTabWidget#colorPreferencesTabWidget::pane { + border: none; + background: transparent; + top: -1px; +} + +QDialog#colorPreferencesDialog QTabBar::tab, +QDialog#colorPreferencesDialog QTabBar::tab:top { + background: #2b2b2b; + color: #b7c3d4; + border: 1px solid #555555; + border-radius: 4px; + padding: 8px 18px; + margin-right: 8px; + font-weight: 600; +} + +QDialog#colorPreferencesDialog QTabBar::tab:selected { + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #2a82da, stop: 1 #1e5fa0); + color: #ffffff; border: 1px solid #2a82da; } +QDialog#colorPreferencesDialog QTabBar::tab:hover:!selected { + background: #404040; + color: #ffffff; +} + +QDialog#colorPreferencesDialog QWidget#colorPreferencesSection { + background: #2b2b2b; + border: 1px solid #555555; + border-radius: 8px; +} + +QDialog#colorPreferencesDialog QLabel#colorPreferencesSectionTitle { + background: transparent; + color: #f8fafc; + font-size: 13px; + font-weight: 600; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame { + border-radius: 6px; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="light"] { + background: #ffffff; + border: 1px solid #d9e0e8; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] { + background: #1f1f1f; + border: 1px solid #555555; +} + +QDialog#colorPreferencesDialog QLabel#colorShortcutLabel { + background: transparent; + color: #94a3b8; + font-size: 11px; + font-weight: 700; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] QLabel#colorShortcutLabel { + color: #e2e8f0; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame QToolButton#ubButtonGroupLeft, +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame QToolButton#ubButtonGroupCenter, +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame QToolButton#ubButtonGroupRight { + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #fdfefe, stop: 1 #e7edf4); + border-top: 1px solid #d9e0e8; + border-bottom: 1px solid #d9e0e8; + border-left: none; + border-right: none; + border-radius: 0px; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="light"] QToolButton#ubButtonGroupLeft { + border-left: 1px solid #d9e0e8; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="light"] QToolButton#ubButtonGroupRight { + border-right: 1px solid #d9e0e8; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] QToolButton#ubButtonGroupLeft, +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] QToolButton#ubButtonGroupCenter, +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] QToolButton#ubButtonGroupRight { + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #505050, stop: 1 #3a3a3a); + border-top: 1px solid #555555; + border-bottom: 1px solid #555555; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] QToolButton#ubButtonGroupLeft { + border-left: 1px solid #555555; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] QToolButton#ubButtonGroupRight { + border-right: 1px solid #555555; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame QToolButton:hover { + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #f4f9ff, stop: 1 #dcebf9); + border-top-color: #c6d9ec; + border-bottom-color: #c6d9ec; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] QToolButton:hover { + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #606060, stop: 1 #4a4a4a); + border-top-color: #6a6a6a; + border-bottom-color: #6a6a6a; +} + +QDialog#colorPreferencesDialog QLabel#colorPreferencesOpacityValue { + color: #ffffff; + font-size: 13px; + font-weight: 700; + background: transparent; +} + +QDialog#colorPreferencesDialog QPushButton#colorPreferencesResetButton { + padding: 7px 14px; + background: #454545; + color: #f8fafc; + border: 1px solid #555555; + border-radius: 4px; + font-weight: 600; +} + +QDialog#colorPreferencesDialog QPushButton#colorPreferencesResetButton:hover { + background: #505050; + border: 1px solid #6a6a6a; +} + +QDialog#colorPreferencesDialog QDialogButtonBox#colorPreferencesButtonBox QPushButton { + min-width: 92px; + padding: 8px 18px; + border-radius: 4px; + font-weight: 600; +} + QWidget#UBFeaturesActionBar QToolButton { padding: 0px; diff --git a/resources/etc/OpenBoard.css b/resources/etc/OpenBoard.css index 0c849702d..b4ec1d09d 100644 --- a/resources/etc/OpenBoard.css +++ b/resources/etc/OpenBoard.css @@ -15,6 +15,17 @@ QComboBox QAbstractItemView background: palette(button); } +QPushButton:focus, +QPushButton:pressed, +QPushButton:checked, +QPushButton:default, +QToolButton:focus, +QToolButton:pressed, +QToolButton:checked +{ + color: palette(highlighted-text); +} + QTextEdit, QLineEdit, QComboBox#DockPaletteWidgetComboBox QAbstractItemView diff --git a/resources/forms/brushProperties.ui b/resources/forms/brushProperties.ui index 5c4de12cf..b26db6a88 100644 --- a/resources/forms/brushProperties.ui +++ b/resources/forms/brushProperties.ui @@ -20,251 +20,7 @@ QFrame::Plain - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - Pen is Pressure Sensitive - - - - - - - Qt::Horizontal - - - - 198 - 20 - - - - - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - - - Qt::Horizontal - - - - 154 - 20 - - - - - - - - Opacity - - - - - - - 20 - - - 100 - - - 50 - - - Qt::Horizontal - - - QSlider::TicksAbove - - - 20 - - - - - - - Qt::Horizontal - - - - 156 - 20 - - - - - - - - - - - Qt::LeftToRight - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - - - On Light Background - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 32 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - - - On Dark Background - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 32 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - - - + @@ -458,20 +214,57 @@
- - - - Qt::Vertical + + + + QFrame::NoFrame - - - 20 - 40 - + + QFrame::Raised - + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Pen is Pressure Sensitive + + + + + + + Qt::Horizontal + + + + 198 + 20 + + + + + +
- + QFrame::NoFrame @@ -518,7 +311,7 @@ - + Qt::Horizontal @@ -534,12 +327,6 @@
- - UBColorPicker - QFrame -
gui/UBColorPicker.h
- 1 -
UBCircleFrame QFrame diff --git a/resources/forms/mainWindow.ui b/resources/forms/mainWindow.ui index a435ec9e8..09673691f 100644 --- a/resources/forms/mainWindow.ui +++ b/resources/forms/mainWindow.ui @@ -555,6 +555,108 @@ 5
+ + + true + + + + :/images/toolbar/color.png:/images/toolbar/color.png + + + Color 6 + + + Color 6 + + + 6 + + + + + true + + + + :/images/toolbar/color.png:/images/toolbar/color.png + + + Color 7 + + + Color 7 + + + 7 + + + + + true + + + + :/images/toolbar/color.png:/images/toolbar/color.png + + + Color 8 + + + Color 8 + + + 8 + + + + + true + + + + :/images/toolbar/color.png:/images/toolbar/color.png + + + Color 9 + + + Color 9 + + + 9 + + + + + true + + + + :/images/toolbar/color.png:/images/toolbar/color.png + + + Color 10 + + + Color 10 + + + 0 + + + + + + :/images/toolbar/settings.png:/images/toolbar/settings.png + + + Color Preferences + + + Open color preferences + + diff --git a/resources/forms/preferences.ui b/resources/forms/preferences.ui index e82bc5d80..4ec35bd9f 100644 --- a/resources/forms/preferences.ui +++ b/resources/forms/preferences.ui @@ -7,7 +7,7 @@ 0 0 1074 - 566 + 816 @@ -24,10 +24,7 @@ - QFrame::Shape::NoFrame - - - QFrame::Shadow::Raised + QFrame::NoFrame @@ -51,9 +48,6 @@ - - Qt::Orientation::Horizontal - 40 @@ -82,7 +76,7 @@ - 0 + 4 @@ -148,11 +142,8 @@ - - Qt::Orientation::Horizontal - - QSizePolicy::Policy::Preferred + QSizePolicy::Fixed @@ -164,9 +155,6 @@ - - Qt::Orientation::Horizontal - 40 @@ -219,11 +207,8 @@ - - Qt::Orientation::Horizontal - - QSizePolicy::Policy::Preferred + QSizePolicy::Fixed @@ -235,9 +220,6 @@ - - Qt::Orientation::Horizontal - 40 @@ -303,11 +285,8 @@ - - Qt::Orientation::Horizontal - - QSizePolicy::Policy::Fixed + QSizePolicy::Fixed @@ -319,9 +298,6 @@ - - Qt::Orientation::Horizontal - 40 @@ -353,11 +329,8 @@ - - Qt::Orientation::Horizontal - - QSizePolicy::Policy::Expanding + QSizePolicy::Fixed @@ -394,11 +367,8 @@ - - Qt::Orientation::Horizontal - - QSizePolicy::Policy::Preferred + QSizePolicy::Fixed @@ -435,7 +405,7 @@ - QLayout::SizeConstraint::SetDefaultConstraint + QLayout::SetDefaultConstraint @@ -471,9 +441,6 @@ - - Qt::Orientation::Vertical - 20 @@ -486,11 +453,8 @@ - - Qt::Orientation::Horizontal - - QSizePolicy::Policy::Preferred + QSizePolicy::Fixed @@ -502,11 +466,8 @@ - - Qt::Orientation::Horizontal - - QSizePolicy::Policy::Preferred + QSizePolicy::Fixed @@ -593,9 +554,6 @@ - - Qt::Orientation::Horizontal - 40 @@ -608,11 +566,8 @@ - - Qt::Orientation::Horizontal - - QSizePolicy::Policy::Preferred + QSizePolicy::Fixed @@ -766,7 +721,7 @@ 0 0 1032 - 220 + 470 @@ -778,19 +733,13 @@ true - QFrame::Shape::NoFrame - - - QFrame::Shadow::Raised + QFrame::NoFrame - QFrame::Shape::NoFrame - - - QFrame::Shadow::Raised + QFrame::NoFrame @@ -802,9 +751,6 @@ - - Qt::Orientation::Horizontal - 40 @@ -822,10 +768,7 @@ - QFrame::Shape::StyledPanel - - - QFrame::Shadow::Raised + QFrame::NoFrame @@ -835,17 +778,11 @@ - QFrame::Shape::NoFrame - - - QFrame::Shadow::Raised + QFrame::NoFrame - - Qt::Orientation::Horizontal - 154 @@ -873,10 +810,10 @@ 50 - Qt::Orientation::Horizontal + Qt::Horizontal - QSlider::TickPosition::TicksAbove + QSlider::NoTicks 20 @@ -885,9 +822,6 @@ - - Qt::Orientation::Horizontal - 156 @@ -902,10 +836,7 @@ - QFrame::Shape::NoFrame - - - QFrame::Shadow::Raised + QFrame::NoFrame @@ -917,9 +848,6 @@ - - Qt::Orientation::Horizontal - 40 @@ -937,10 +865,7 @@ - QFrame::Shape::StyledPanel - - - QFrame::Shadow::Raised + QFrame::NoFrame @@ -950,17 +875,11 @@ - QFrame::Shape::NoFrame - - - QFrame::Shadow::Raised + QFrame::NoFrame - - Qt::Orientation::Horizontal - 154 @@ -988,10 +907,10 @@ 50 - Qt::Orientation::Horizontal + Qt::Horizontal - QSlider::TickPosition::TicksAbove + QSlider::NoTicks 20 @@ -1000,9 +919,6 @@ - - Qt::Orientation::Horizontal - 156 @@ -1019,9 +935,6 @@ - - Qt::Orientation::Vertical - 20 @@ -1037,13 +950,19 @@ Pen - + - - QFrame::Shape::NoFrame + + + 0 + 0 + + + + Qt::DefaultContextMenu - - QFrame::Shadow::Raised + + QFrame::NoFrame @@ -1054,13 +973,10 @@ Marker - + - QFrame::Shape::NoFrame - - - QFrame::Shadow::Raised + QFrame::NoFrame @@ -1151,7 +1067,7 @@ - QLineEdit::EchoMode::Password + QLineEdit::Password @@ -1162,11 +1078,8 @@ - - Qt::Orientation::Horizontal - - QSizePolicy::Policy::Preferred + QSizePolicy::Fixed @@ -1181,9 +1094,6 @@ - - Qt::Orientation::Vertical - 20 @@ -1208,19 +1118,25 @@ - - true + + + 0 + 0 + QScrollArea:disabled {border: 1px solid red;} + + true + 0 0 1032 - 173 + 423 @@ -1296,10 +1212,10 @@ - + true - + 1 @@ -1375,9 +1291,9 @@ - - QPushButton:checked {background-color: red} - + + QPushButton:checked {background-color: red} + Record @@ -1553,7 +1469,7 @@ */ - Qt::TextInteractionFlag::TextSelectableByKeyboard|Qt::TextInteractionFlag::TextSelectableByMouse + Qt::NoTextInteraction @@ -1598,7 +1514,7 @@ Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu - Qt::TextInteractionFlag::TextSelectableByKeyboard|Qt::TextInteractionFlag::TextSelectableByMouse + Qt::NoTextInteraction @@ -2310,7 +2226,7 @@ Public License instead of this License. But first, please read --8<---------------cut here---------------end--------------->8--- - Qt::TextInteractionFlag::TextSelectableByKeyboard|Qt::TextInteractionFlag::TextSelectableByMouse + Qt::NoTextInteraction @@ -2680,7 +2596,7 @@ Public License instead of this License. --8<---------------cut here---------------end--------------->8--- - Qt::TextInteractionFlag::TextSelectableByKeyboard|Qt::TextInteractionFlag::TextSelectableByMouse + Qt::NoTextInteraction @@ -3387,7 +3303,7 @@ Public License instead of this License. But first, please read --8<---------------cut here---------------end--------------->8--- - Qt::TextInteractionFlag::TextSelectableByKeyboard|Qt::TextInteractionFlag::TextSelectableByMouse + Qt::NoTextInteraction @@ -3601,7 +3517,7 @@ hr { height: 1px; border-width: 0; } UBPreferredBackgroundWidget QWidget
gui/UBPreferredBackgroundWidget.h
- + UBScreenLayoutPreview QWidget diff --git a/resources/lightTheme.qss b/resources/lightTheme.qss index 7443bc9c1..dd81d453d 100644 --- a/resources/lightTheme.qss +++ b/resources/lightTheme.qss @@ -302,6 +302,267 @@ QToolButton#desktop-ubButtonGroupRight:checked { border-right: 1px solid #2a82da; } +QToolButton#ubButtonGroupRight[colorPaletteConfigButton="true"], +QToolButton#desktop-ubButtonGroupRight[colorPaletteConfigButton="true"] { + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #e8edf4, stop: 1 #cfd8e3); + color: #334155; + border-top: 1px solid #bcc8d5; + border-bottom: 1px solid #bcc8d5; + border-left: 1px solid #bcc8d5; + border-right: 1px solid #bcc8d5; +} + +QToolButton#ubButtonGroupRight[colorPaletteConfigButton="true"]:hover, +QToolButton#desktop-ubButtonGroupRight[colorPaletteConfigButton="true"]:hover { + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #dee6ef, stop: 1 #c4d0dc); + color: #1e293b; +} + +QToolButton#ubButtonGroupRight[colorPaletteConfigButton="true"]:pressed, +QToolButton#desktop-ubButtonGroupRight[colorPaletteConfigButton="true"]:pressed { + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #d1dae5, stop: 1 #b4c1d0); + color: #0f172a; +} + +QDialog#colorPreferencesDialog { + background-color: #f2f6fa; +} + +QDialog#colorPreferencesDialog QWidget#colorPreferencesHeader { + background-color: #edf2f7; + border: 1px solid #d9e0e8; + border-radius: 10px; +} + +QDialog#colorPreferencesDialog QLabel#colorPreferencesHeaderLabel { + color: #0f172a; + font-size: 14px; + font-weight: 600; + background: transparent; +} + +QDialog#colorPreferencesDialog QSlider#colorPreferencesPaletteSizeSlider { + min-width: 190px; + background: transparent; +} + +QDialog#colorPreferencesDialog QSlider#colorPreferencesPaletteSizeSlider::groove:horizontal { + height: 6px; + background-color: #d7e1ec; + border: none; + border-radius: 3px; +} + +QDialog#colorPreferencesDialog QSlider#colorPreferencesPaletteSizeSlider::handle:horizontal { + width: 18px; + margin: -7px 0; + background-color: #3d8fd1; + border: 1px solid #2a82da; + border-radius: 9px; +} + +QDialog#colorPreferencesDialog QSlider#colorPreferencesPaletteSizeSlider::sub-page:horizontal { + background-color: #3d8fd1; + border-radius: 3px; +} + +QDialog#colorPreferencesDialog QLabel#colorPreferencesPaletteSizeValue { + min-width: 32px; + padding: 4px 8px; + background: #ffffff; + color: #0f172a; + border: 1px solid #d9e0e8; + border-radius: 6px; + font-size: 14px; + font-weight: 600; +} + +QDialog#colorPreferencesDialog QWidget#colorPreferencesHint { + background: #fff8db; + border: 1px solid #ead9a2; + border-radius: 8px; +} + +QDialog#colorPreferencesDialog QLabel#colorPreferencesHintIcon { + background: transparent; + min-width: 20px; +} + +QDialog#colorPreferencesDialog QLabel#colorPreferencesHintText { + background: transparent; + color: #5b4b1f; + font-size: 12px; + line-height: 1.3em; +} + +QDialog#colorPreferencesDialog QTabWidget#colorPreferencesTabWidget::pane { + border: none; + background: transparent; + top: -1px; +} + +QDialog#colorPreferencesDialog QTabBar::tab, +QDialog#colorPreferencesDialog QTabBar::tab:top { + background: #e2eaf3; + color: #475569; + border: 1px solid #d9e0e8; + border-radius: 6px; + padding: 8px 18px; + margin-right: 8px; + font-weight: 600; +} + +QDialog#colorPreferencesDialog QTabBar::tab:selected { + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #5aa5e0, stop: 1 #3d8fd1); + color: #ffffff; + border: 1px solid #2a82da; +} + +QDialog#colorPreferencesDialog QTabBar::tab:hover:!selected { + background: #e8eff7; + color: #1e293b; +} + +QDialog#colorPreferencesDialog QWidget#colorPreferencesSection { + background: #edf2f7; + border: 1px solid #d9e0e8; + border-radius: 10px; +} + +QDialog#colorPreferencesDialog QLabel#colorPreferencesSectionTitle { + background: transparent; + color: #0f172a; + font-size: 13px; + font-weight: 600; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame { + border-radius: 8px; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="light"] { + background: #ffffff; + border: 1px solid #d9e0e8; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] { + background: #131a24; + border: 1px solid #475569; +} + +QDialog#colorPreferencesDialog QLabel#colorShortcutLabel { + background: transparent; + color: #64748b; + font-size: 11px; + font-weight: 700; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] QLabel#colorShortcutLabel { + color: #cbd5e1; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame QToolButton#ubButtonGroupLeft, +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame QToolButton#ubButtonGroupCenter, +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame QToolButton#ubButtonGroupRight { + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #fdfefe, stop: 1 #e7edf4); + border-top: 1px solid #d9e0e8; + border-bottom: 1px solid #d9e0e8; + border-left: none; + border-right: none; + border-radius: 0px; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="light"] QToolButton#ubButtonGroupLeft { + border-left: 1px solid #d9e0e8; + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="light"] QToolButton#ubButtonGroupRight { + border-right: 1px solid #d9e0e8; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] QToolButton#ubButtonGroupLeft, +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] QToolButton#ubButtonGroupCenter, +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] QToolButton#ubButtonGroupRight { + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #505050, stop: 1 #3a3a3a); + border-top: 1px solid #435066; + border-bottom: 1px solid #435066; + color: #ffffff; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] QToolButton#ubButtonGroupLeft { + border-left: 1px solid #435066; + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] QToolButton#ubButtonGroupRight { + border-right: 1px solid #435066; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame QToolButton:hover { + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #f4f9ff, stop: 1 #dcebf9); + border-top-color: #c6d9ec; + border-bottom-color: #c6d9ec; +} + +QDialog#colorPreferencesDialog QFrame#colorPreviewFrame[previewMode="dark"] QToolButton:hover { + background: qlineargradient(x1: 0, y1: 0.49, x2: 0, y2: 0.5, stop: 0 #606060, stop: 1 #4a4a4a); + border-top-color: #64748b; + border-bottom-color: #64748b; +} + +QDialog#colorPreferencesDialog QLabel#colorPreferencesOpacityValue { + color: #0f172a; + font-size: 13px; + font-weight: 700; + background: transparent; +} + +QDialog#colorPreferencesDialog QPushButton#colorPreferencesResetButton { + padding: 7px 14px; + background: #f7f9fc; + color: #334155; + border: 1px solid #d9e0e8; + border-radius: 6px; + font-weight: 600; +} + +QDialog#colorPreferencesDialog QPushButton#colorPreferencesResetButton:hover { + background: #eef6ff; + border: 1px solid #d3e4f6; +} + +QDialog#colorPreferencesDialog QPushButton#colorPreferencesResetButton:focus, +QDialog#colorPreferencesDialog QPushButton#colorPreferencesResetButton:pressed, +QDialog#colorPreferencesDialog QPushButton#colorPreferencesResetButton:checked, +QDialog#colorPreferencesDialog QPushButton#colorPreferencesResetButton:default { + background: #3d8fd1; + color: #ffffff; + border: 1px solid #2a82da; +} + +QDialog#colorPreferencesDialog QDialogButtonBox#colorPreferencesButtonBox QPushButton { + min-width: 92px; + padding: 8px 18px; + border-radius: 6px; + font-weight: 600; +} + +QDialog#colorPreferencesDialog QDialogButtonBox#colorPreferencesButtonBox QPushButton:focus, +QDialog#colorPreferencesDialog QDialogButtonBox#colorPreferencesButtonBox QPushButton:pressed, +QDialog#colorPreferencesDialog QDialogButtonBox#colorPreferencesButtonBox QPushButton:checked, +QDialog#colorPreferencesDialog QDialogButtonBox#colorPreferencesButtonBox QPushButton:default { + background-color: #3d8fd1; + color: #ffffff; + border: 1px solid #2a82da; +} + QCheckBox, QRadioButton { color: #1f2937; diff --git a/src/board/CMakeLists.txt b/src/board/CMakeLists.txt index 8e20f849e..6ebccd022 100644 --- a/src/board/CMakeLists.txt +++ b/src/board/CMakeLists.txt @@ -5,6 +5,8 @@ target_sources(${PROJECT_NAME} PRIVATE UBBoardPaletteManager.h UBBoardView.cpp UBBoardView.h + UBColorPreferencesDialog.cpp + UBColorPreferencesDialog.h UBDrawingController.cpp UBDrawingController.h UBFeaturesController.cpp diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index bab59bddf..af91b5f59 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -36,6 +36,7 @@ #include "board/UBBoardPaletteManager.h" #include "board/UBBoardView.h" +#include "board/UBColorPreferencesDialog.h" #include "board/UBDrawingController.h" #include "board/UBFeaturesController.h" @@ -352,31 +353,23 @@ void UBBoardController::setupToolbar() { UBSettings *settings = UBSettings::settings(); - // Setup color choice widget - QList colorActions; - colorActions.append(mMainWindow->actionColor0); - colorActions.append(mMainWindow->actionColor1); - colorActions.append(mMainWindow->actionColor2); - colorActions.append(mMainWindow->actionColor3); - colorActions.append(mMainWindow->actionColor4); + buildColorActions(); - UBToolbarButtonGroup *colorChoice = - new UBToolbarButtonGroup(mMainWindow->boardToolBar, colorActions); - colorChoice->setLabel(tr("Color")); + mColorChoice = new UBToolbarButtonGroup(mMainWindow->boardToolBar, mColorActions, QString(), settings->colorPaletteSize); + mColorChoice->setLabel(tr("Color")); - mMainWindow->boardToolBar->insertWidget(mMainWindow->actionBackgrounds, colorChoice); + mMainWindow->boardToolBar->insertWidget(mMainWindow->actionBackgrounds, mColorChoice); - connect(settings->appToolBarDisplayText, SIGNAL(changed(QVariant)), colorChoice, SLOT(displayText(QVariant))); - connect(colorChoice, SIGNAL(activated(int)), this, SLOT(setColorIndex(int))); - connect(UBDrawingController::drawingController(), SIGNAL(colorIndexChanged(int)), colorChoice, SLOT(setCurrentIndex(int))); + connect(settings->appToolBarDisplayText, SIGNAL(changed(QVariant)), mColorChoice, SLOT(displayText(QVariant))); + connect(mColorChoice, SIGNAL(activated(int)), this, SLOT(setColorIndex(int))); + connect(UBDrawingController::drawingController(), SIGNAL(colorIndexChanged(int)), mColorChoice, SLOT(setCurrentIndex(int))); connect(UBDrawingController::drawingController(), SIGNAL(colorIndexChanged(int)), UBDrawingController::drawingController(), SIGNAL(colorPaletteChanged())); - connect(UBDrawingController::drawingController(), SIGNAL(colorPaletteChanged()), colorChoice, SLOT(colorPaletteChanged())); + connect(UBDrawingController::drawingController(), SIGNAL(colorPaletteChanged()), mColorChoice, SLOT(colorPaletteChanged())); connect(UBDrawingController::drawingController(), SIGNAL(colorPaletteChanged()), this, SLOT(colorPaletteChanged())); + connect(mMainWindow->actionColorPreferences, SIGNAL(triggered()), this, SLOT(openColorPreferencesDialog())); - colorChoice->displayText(QVariant(settings->appToolBarDisplayText->get().toBool())); - colorChoice->colorPaletteChanged(); - colorChoice->setCurrentIndex(settings->penColorIndex()); - colorActions.at(settings->penColorIndex())->setChecked(true); + mColorChoice->displayText(QVariant(settings->appToolBarDisplayText->get().toBool())); + updateColorButtonsForPaletteSize(); // Setup line width choice widget QList lineWidthActions; @@ -441,6 +434,73 @@ void UBBoardController::setupToolbar() } +void UBBoardController::buildColorActions() +{ + mColorActions.clear(); + + mColorActions << mMainWindow->actionColor0 + << mMainWindow->actionColor1 + << mMainWindow->actionColor2 + << mMainWindow->actionColor3 + << mMainWindow->actionColor4 + << mMainWindow->actionColor5 + << mMainWindow->actionColor6 + << mMainWindow->actionColor7 + << mMainWindow->actionColor8 + << mMainWindow->actionColor9 + << mMainWindow->actionColorPreferences; +} + + +int UBBoardController::currentToolColorIndex() const +{ + if (UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Marker) + { + return UBSettings::settings()->markerColorIndex(); + } + + return UBSettings::settings()->penColorIndex(); +} + + +void UBBoardController::updateColorButtonsForPaletteSize() +{ + const int paletteSize = UBSettings::settings()->colorPaletteSize; + + for (int i = 0; i < mColorActions.size(); ++i) + { + QAction* action = mColorActions.at(i); + + if (!action) + continue; + + if (!action->isCheckable()) + { + action->setEnabled(true); + continue; + } + + const bool enabled = i < paletteSize; + action->setEnabled(enabled); + action->setVisible(true); + + if (!enabled) + { + action->setChecked(false); + } + } + + if (mColorChoice) + { + mColorChoice->setSelectableCount(paletteSize); + mColorChoice->colorPaletteChanged(); + + int index = qBound(0, currentToolColorIndex(), paletteSize - 1); + mColorChoice->setCurrentIndex(index); + } +} + + void UBBoardController::setToolCursor(int tool) { if (mActiveScene) @@ -1876,6 +1936,9 @@ void UBBoardController::setColorIndex(int pColorIndex) { UBDrawingController::drawingController()->setColorIndex(pColorIndex); + const bool isMarkerTool = (UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Marker); + const int appliedIndex = isMarkerTool ? UBSettings::settings()->markerColorIndex() : UBSettings::settings()->penColorIndex(); + if (UBDrawingController::drawingController()->stylusTool() != UBStylusTool::Marker && UBDrawingController::drawingController()->stylusTool() != UBStylusTool::Line && UBDrawingController::drawingController()->stylusTool() != UBStylusTool::Text && @@ -1889,8 +1952,10 @@ void UBBoardController::setColorIndex(int pColorIndex) UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Text || UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Selector) { - mPenColorOnDarkBackground = UBSettings::settings()->penColors(true).at(pColorIndex); - mPenColorOnLightBackground = UBSettings::settings()->penColors(false).at(pColorIndex); + QList darkColors = UBSettings::settings()->penColors(true); + QList lightColors = UBSettings::settings()->penColors(false); + mPenColorOnDarkBackground = darkColors.value(appliedIndex, darkColors.value(0, Qt::white)); + mPenColorOnLightBackground = lightColors.value(appliedIndex, lightColors.value(0, Qt::black)); if (UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Selector) { @@ -1904,10 +1969,12 @@ void UBBoardController::setColorIndex(int pColorIndex) emit penColorChanged(); } - else if (UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Marker) + else if (isMarkerTool) { - mMarkerColorOnDarkBackground = UBSettings::settings()->markerColors(true).at(pColorIndex); - mMarkerColorOnLightBackground = UBSettings::settings()->markerColors(false).at(pColorIndex); + QList darkColors = UBSettings::settings()->markerColors(true); + QList lightColors = UBSettings::settings()->markerColors(false); + mMarkerColorOnDarkBackground = darkColors.value(appliedIndex, darkColors.value(0, Qt::white)); + mMarkerColorOnLightBackground = lightColors.value(appliedIndex, lightColors.value(0, Qt::black)); } } @@ -1920,6 +1987,84 @@ void UBBoardController::colorPaletteChanged() } +void UBBoardController::openColorPreferencesDialog() +{ + if (mColorPreferencesDialog) + { + mColorPreferencesDialog->raise(); + mColorPreferencesDialog->activateWindow(); + return; + } + + UBSettings* settings = UBSettings::settings(); + const int paletteSize = settings->colorPaletteSize; + + QList penLightColors = settings->boardPenLightBackgroundSelectedColors->colors(); + QList penDarkColors = settings->boardPenDarkBackgroundSelectedColors->colors(); + QList markerLightColors = settings->boardMarkerLightBackgroundSelectedColors->colors(); + QList markerDarkColors = settings->boardMarkerDarkBackgroundSelectedColors->colors(); + + mColorPreferencesDialog = new UBColorPreferencesDialog(mMainWindow, + paletteSize, + penLightColors, + penDarkColors, + markerLightColors, + markerDarkColors, + qRound(settings->boardMarkerAlpha->get().toDouble() * 100.0)); + mColorPreferencesDialog->setAttribute(Qt::WA_DeleteOnClose); + connect(mColorPreferencesDialog, SIGNAL(accepted()), this, SLOT(colorPreferencesDialogAccepted())); + mColorPreferencesDialog->open(); +} + + +void UBBoardController::colorPreferencesDialogAccepted() +{ + UBColorPreferencesDialog* dialog = qobject_cast(sender()); + if (!dialog) + return; + + UBSettings* settings = UBSettings::settings(); + + const int selectedPaletteSize = dialog->paletteSize(); + settings->setColorPaletteSize(selectedPaletteSize); + + auto applyColors = [](UBColorListSetting* target, const QList& defaults, const QList& updated) + { + QList stored = target->colors(); + + QList normalized = stored; + for (int i = normalized.size(); i < UBSettings::maxColorPaletteSize; ++i) + { + normalized.append(defaults.value(i % defaults.size(), QColor(Qt::black))); + } + + if (normalized.size() > UBSettings::maxColorPaletteSize) + { + normalized = normalized.mid(0, UBSettings::maxColorPaletteSize); + } + + const int limit = qMin(normalized.size(), updated.size()); + for (int i = 0; i < limit; ++i) + { + normalized[i] = updated.at(i); + } + + target->setColors(normalized); + }; + + applyColors(settings->boardPenLightBackgroundSelectedColors, settings->defaultPenColors(false), dialog->penLightColors()); + applyColors(settings->boardPenDarkBackgroundSelectedColors, settings->defaultPenColors(true), dialog->penDarkColors()); + applyColors(settings->boardMarkerLightBackgroundSelectedColors, settings->defaultMarkerColors(false), dialog->markerLightColors()); + applyColors(settings->boardMarkerDarkBackgroundSelectedColors, settings->defaultMarkerColors(true), dialog->markerDarkColors()); + + const qreal markerAlpha = dialog->markerOpacity() / 100.0; + UBDrawingController::drawingController()->setMarkerAlpha(markerAlpha); + + updateColorButtonsForPaletteSize(); + UBDrawingController::drawingController()->refreshColorPalette(); +} + + qreal UBBoardController::currentZoom() const { if (mControlView) diff --git a/src/board/UBBoardController.h b/src/board/UBBoardController.h index b427fd726..7cb5ad239 100644 --- a/src/board/UBBoardController.h +++ b/src/board/UBBoardController.h @@ -34,6 +34,7 @@ #include #include +#include #include #include "core/UB.h" @@ -62,6 +63,8 @@ class UBGraphicsWidgetItem; class UBBoardPaletteManager; class UBItem; class UBGraphicsItem; +class UBToolbarButtonGroup; +class UBColorPreferencesDialog; class UBBoardController : public UBDocumentContainer @@ -296,6 +299,9 @@ class UBBoardController : public UBDocumentContainer void initBackgroundGridSize(); void updatePageSizeState(); int autosaveTimeoutFromSettings() const; + void buildColorActions(); + void updateColorButtonsForPaletteSize(); + int currentToolColorIndex() const; UBMainWindow *mMainWindow; std::shared_ptr mActiveScene; @@ -316,6 +322,7 @@ class UBBoardController : public UBDocumentContainer QColor mPenColorOnLightBackground; QColor mMarkerColorOnDarkBackground; QColor mMarkerColorOnLightBackground; + QPointer mColorPreferencesDialog; qreal mSystemScaleFactor; bool mCleanupDone; QMap > mActionTexts; @@ -327,6 +334,8 @@ class UBBoardController : public UBDocumentContainer QString mActionUngroupText; std::shared_ptr mInitialDocumentScene; QList> mRecentDocuments; + QList mColorActions; + UBToolbarButtonGroup* mColorChoice{nullptr}; QTimer *mAutosaveTimer; @@ -334,6 +343,8 @@ class UBBoardController : public UBDocumentContainer void stylusToolDoubleClicked(int tool); void boardViewResized(QResizeEvent* event); void colorPaletteChanged(); + void openColorPreferencesDialog(); + void colorPreferencesDialogAccepted(); void libraryDialogClosed(int ret); void lastWindowClosed(); void onDownloadModalFinished(); diff --git a/src/board/UBColorPreferencesDialog.cpp b/src/board/UBColorPreferencesDialog.cpp new file mode 100644 index 000000000..c41f37695 --- /dev/null +++ b/src/board/UBColorPreferencesDialog.cpp @@ -0,0 +1,729 @@ +/* + * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) + * + * Copyright (C) 2013 Open Education Foundation + * + * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour + * l'Education Numérique en Afrique (GIP ENA) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + +#include "UBColorPreferencesDialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core/UBApplication.h" +#include "core/UBSettings.h" +#include "gui/UBMainWindow.h" + + +UBColorPreferencesDialog::UBColorPreferencesDialog(QWidget* parent, + int paletteSize, + const QList& penLightColors, + const QList& penDarkColors, + const QList& markerLightColors, + const QList& markerDarkColors, + int markerOpacityPercent) + : QDialog(parent) + , mPenLightColors(penLightColors) + , mPenDarkColors(penDarkColors) + , mMarkerLightColors(opaqueColors(markerLightColors)) + , mMarkerDarkColors(opaqueColors(markerDarkColors)) + , mDefaultPenLightColors(UBSettings::settings()->defaultPenColors(false)) + , mDefaultPenDarkColors(UBSettings::settings()->defaultPenColors(true)) + , mDefaultMarkerLightColors(opaqueColors(UBSettings::settings()->defaultMarkerColors(false))) + , mDefaultMarkerDarkColors(opaqueColors(UBSettings::settings()->defaultMarkerColors(true))) + , mDefaultMarkerOpacityPercent(qBound(1, qRound(UBSettings::settings()->boardMarkerAlpha->defaultValue().toDouble() * 100.0), 100)) + , mMinPaletteSize(UBSettings::minColorPaletteSize) + , mMaxPaletteSize(UBSettings::maxColorPaletteSize) +{ + setModal(true); + setWindowTitle(tr("Color Preferences")); + setMinimumWidth(520); + setObjectName(QStringLiteral("colorPreferencesDialog")); + + const int boundedPaletteSize = qBound(mMinPaletteSize, paletteSize, mMaxPaletteSize); + + ensureSize(mPenLightColors, mDefaultPenLightColors); + ensureSize(mPenDarkColors, mDefaultPenDarkColors); + ensureSize(mMarkerLightColors, mDefaultMarkerLightColors); + ensureSize(mMarkerDarkColors, mDefaultMarkerDarkColors); + + QVBoxLayout* mainLayout = new QVBoxLayout(this); + mainLayout->setContentsMargins(20, 18, 20, 18); + mainLayout->setSpacing(16); + + const QString paletteSizeToolTip = tr("This setting applies to the pen and marker palettes."); + + QWidget* sizeWidget = new QWidget(this); + sizeWidget->setObjectName(QStringLiteral("colorPreferencesHeader")); + QHBoxLayout* sizeLayout = new QHBoxLayout(sizeWidget); + sizeLayout->setContentsMargins(14, 12, 14, 12); + sizeLayout->setSpacing(12); + + QLabel* sizeLabel = new QLabel(tr("Palette size"), sizeWidget); + sizeLabel->setObjectName(QStringLiteral("colorPreferencesHeaderLabel")); + sizeLabel->setToolTip(paletteSizeToolTip); + mPaletteSizeSlider = new QSlider(Qt::Horizontal, sizeWidget); + mPaletteSizeSlider->setObjectName(QStringLiteral("colorPreferencesPaletteSizeSlider")); + mPaletteSizeSlider->setRange(mMinPaletteSize, mMaxPaletteSize); + mPaletteSizeSlider->setSingleStep(1); + mPaletteSizeSlider->setPageStep(1); + mPaletteSizeSlider->setTickInterval(1); + mPaletteSizeSlider->setTickPosition(QSlider::TicksBelow); + mPaletteSizeSlider->setValue(boundedPaletteSize); + mPaletteSizeSlider->setToolTip(paletteSizeToolTip); + connect(mPaletteSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(paletteSizeChanged(int))); + mPaletteSizeValue = new QLabel(QString::number(boundedPaletteSize), sizeWidget); + mPaletteSizeValue->setObjectName(QStringLiteral("colorPreferencesPaletteSizeValue")); + mPaletteSizeValue->setAlignment(Qt::AlignCenter); + mPaletteSizeValue->setToolTip(paletteSizeToolTip); + sizeLayout->addWidget(sizeLabel); + sizeLayout->addWidget(mPaletteSizeSlider, 1); + sizeLayout->addWidget(mPaletteSizeValue); + mainLayout->addWidget(sizeWidget); + + mTabWidget = new QTabWidget(this); + mTabWidget->setObjectName(QStringLiteral("colorPreferencesTabWidget")); + mTabWidget->setIconSize(QSize(18, 18)); + + QWidget* penTab = createToolTab(tr("Light background"), + tr("Dark background"), + mPenLightFrame, + mPenDarkFrame, + mPenLightShortcutLabels, + mPenDarkShortcutLabels, + mPenLightButtons, + mPenDarkButtons, + mPenLightColors, + mPenDarkColors, + QStringLiteral("penLight"), + QStringLiteral("penDark"), + mResetPenButton); + penTab->setObjectName(QStringLiteral("colorPreferencesPenTab")); + mResetPenButton->setText(tr("Reset pen")); + mResetPenButton->setObjectName(QStringLiteral("colorPreferencesResetButton")); + connect(mResetPenButton, SIGNAL(clicked()), this, SLOT(resetPenSettings())); + mTabWidget->addTab(penTab, tr("Pen")); + + QWidget* markerTab = createToolTab(tr("Light background"), + tr("Dark background"), + mMarkerLightFrame, + mMarkerDarkFrame, + mMarkerLightShortcutLabels, + mMarkerDarkShortcutLabels, + mMarkerLightButtons, + mMarkerDarkButtons, + mMarkerLightColors, + mMarkerDarkColors, + QStringLiteral("markerLight"), + QStringLiteral("markerDark"), + mResetMarkerButton); + markerTab->setObjectName(QStringLiteral("colorPreferencesMarkerTab")); + mResetMarkerButton->setText(tr("Reset marker")); + mResetMarkerButton->setObjectName(QStringLiteral("colorPreferencesResetButton")); + connect(mResetMarkerButton, SIGNAL(clicked()), this, SLOT(resetMarkerSettings())); + + QVBoxLayout* markerLayout = qobject_cast(markerTab->layout()); + if (markerLayout) + { + QHBoxLayout* opacityLayout = new QHBoxLayout(); + QLabel* opacityLabel = new QLabel(tr("Marker opacity"), markerTab); + opacityLabel->setObjectName(QStringLiteral("colorPreferencesSectionTitle")); + mMarkerOpacitySlider = new QSlider(Qt::Horizontal, markerTab); + mMarkerOpacitySlider->setObjectName(QStringLiteral("colorPreferencesOpacitySlider")); + mMarkerOpacitySlider->setRange(1, 100); + mMarkerOpacitySlider->setValue(qBound(1, markerOpacityPercent, 100)); + connect(mMarkerOpacitySlider, SIGNAL(valueChanged(int)), this, SLOT(markerOpacityChanged(int))); + mMarkerOpacityValue = new QLabel(markerTab); + mMarkerOpacityValue->setObjectName(QStringLiteral("colorPreferencesOpacityValue")); + mMarkerOpacityValue->setMinimumWidth(40); + opacityLayout->addWidget(opacityLabel); + opacityLayout->addWidget(mMarkerOpacitySlider); + opacityLayout->addWidget(mMarkerOpacityValue); + markerLayout->insertLayout(markerLayout->count() - 2, opacityLayout); + } + + mTabWidget->addTab(markerTab, tr("Marker")); + connect(mTabWidget, SIGNAL(currentChanged(int)), this, SLOT(updateTabIcons(int))); + updateTabIcons(mTabWidget->currentIndex()); + mainLayout->addWidget(mTabWidget); + + QWidget* hintWidget = new QWidget(this); + hintWidget->setObjectName(QStringLiteral("colorPreferencesHint")); + QHBoxLayout* hintLayout = new QHBoxLayout(hintWidget); + hintLayout->setContentsMargins(14, 10, 14, 10); + hintLayout->setSpacing(10); + + QLabel* hintIcon = new QLabel(hintWidget); + hintIcon->setObjectName(QStringLiteral("colorPreferencesHintIcon")); + hintIcon->setPixmap(QIcon(QStringLiteral(":/images/toolbar/tip.png")).pixmap(20, 20)); + hintIcon->setAlignment(Qt::AlignTop | Qt::AlignHCenter); + + QLabel* hintLabel = new QLabel( + tr("When you switch between light and dark background in OpenBoard, each color is replaced by its counterpart so your annotations stay readable."), + hintWidget); + hintLabel->setObjectName(QStringLiteral("colorPreferencesHintText")); + hintLabel->setWordWrap(true); + + hintLayout->addWidget(hintIcon, 0, Qt::AlignTop); + hintLayout->addWidget(hintLabel, 1); + mainLayout->addWidget(hintWidget); + + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + buttons->setObjectName(QStringLiteral("colorPreferencesButtonBox")); + QPushButton* defaultSettingsButton = buttons->addButton(tr("Default settings"), QDialogButtonBox::ResetRole); + defaultSettingsButton->setObjectName(QStringLiteral("colorPreferencesResetButton")); + connect(defaultSettingsButton, SIGNAL(clicked()), this, SLOT(resetDefaultSettings())); + connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); + mainLayout->addWidget(buttons); + + updateBackgroundFrames(); + paletteSizeChanged(boundedPaletteSize); + markerOpacityChanged(mMarkerOpacitySlider->value()); +} + + +int UBColorPreferencesDialog::paletteSize() const +{ + return mPaletteSizeSlider->value(); +} + + +QList UBColorPreferencesDialog::penLightColors() const +{ + return mPenLightColors; +} + + +QList UBColorPreferencesDialog::penDarkColors() const +{ + return mPenDarkColors; +} + + +QList UBColorPreferencesDialog::markerLightColors() const +{ + return mMarkerLightColors; +} + + +QList UBColorPreferencesDialog::markerDarkColors() const +{ + return mMarkerDarkColors; +} + + +int UBColorPreferencesDialog::markerOpacity() const +{ + return mMarkerOpacitySlider->value(); +} + + +void UBColorPreferencesDialog::paletteSizeChanged(int value) +{ + Q_UNUSED(value); + + ensureSize(mPenLightColors, mDefaultPenLightColors); + ensureSize(mPenDarkColors, mDefaultPenDarkColors); + ensureSize(mMarkerLightColors, mDefaultMarkerLightColors); + ensureSize(mMarkerDarkColors, mDefaultMarkerDarkColors); + + const int visibleCount = mPaletteSizeSlider->value(); + if (mPaletteSizeValue) + mPaletteSizeValue->setText(QString::number(visibleCount)); + + auto setRowWidth = [visibleCount](QWidget* frame, const QList& buttons) + { + if (!frame) + return; + + const int buttonWidth = buttons.isEmpty() ? 0 : buttons.first()->width(); + int rowWidth = visibleCount * buttonWidth; + + if (QGridLayout* layout = qobject_cast(frame->layout())) + { + const QMargins margins = layout->contentsMargins(); + rowWidth += margins.left() + margins.right(); + rowWidth += qMax(0, visibleCount - 1) * layout->horizontalSpacing(); + } + + frame->setMinimumWidth(rowWidth); + frame->setMaximumWidth(rowWidth); + }; + + refreshPenSwatches(); + refreshMarkerSwatches(); + + setRowWidth(mPenLightFrame, mPenLightButtons); + setRowWidth(mPenDarkFrame, mPenDarkButtons); + setRowWidth(mMarkerLightFrame, mMarkerLightButtons); + setRowWidth(mMarkerDarkFrame, mMarkerDarkButtons); +} + + +void UBColorPreferencesDialog::penSwatchClicked() +{ + QToolButton* button = qobject_cast(sender()); + if (!button) + return; + + const QString role = button->property("role").toString(); + const int index = button->property("index").toInt(); + QList* colors = role == QLatin1String("penDark") ? &mPenDarkColors : &mPenLightColors; + + if (!colors || index < 0 || index >= colors->size()) + return; + + const QColor chosen = QColorDialog::getColor(colors->at(index), this, tr("Select Pen Color")); + if (!chosen.isValid()) + return; + + (*colors)[index] = chosen; + refreshPenSwatches(); +} + + +void UBColorPreferencesDialog::markerSwatchClicked() +{ + QToolButton* button = qobject_cast(sender()); + if (!button) + return; + + const QString role = button->property("role").toString(); + const int index = button->property("index").toInt(); + QList* colors = role == QLatin1String("markerDark") ? &mMarkerDarkColors : &mMarkerLightColors; + + if (!colors || index < 0 || index >= colors->size()) + return; + + QColor initialColor = colors->at(index); + initialColor.setAlpha(255); + + const QColor chosen = QColorDialog::getColor(initialColor, this, tr("Select Marker Color")); + if (!chosen.isValid()) + return; + + QColor opaqueChosen = chosen; + opaqueChosen.setAlpha(255); + (*colors)[index] = opaqueChosen; + refreshMarkerSwatches(); +} + + +void UBColorPreferencesDialog::markerOpacityChanged(int value) +{ + mMarkerOpacityValue->setText(QString::number(value) + QStringLiteral("%")); + refreshMarkerSwatches(); +} + + +void UBColorPreferencesDialog::resetPenSettings() +{ + mPenLightColors = mDefaultPenLightColors; + mPenDarkColors = mDefaultPenDarkColors; + + ensureSize(mPenLightColors, mDefaultPenLightColors); + ensureSize(mPenDarkColors, mDefaultPenDarkColors); + refreshPenSwatches(); +} + + +void UBColorPreferencesDialog::resetMarkerSettings() +{ + mMarkerLightColors = mDefaultMarkerLightColors; + mMarkerDarkColors = mDefaultMarkerDarkColors; + + ensureSize(mMarkerLightColors, mDefaultMarkerLightColors); + ensureSize(mMarkerDarkColors, mDefaultMarkerDarkColors); + mMarkerOpacitySlider->setValue(mDefaultMarkerOpacityPercent); + refreshMarkerSwatches(); +} + + +void UBColorPreferencesDialog::resetDefaultSettings() +{ + mPaletteSizeSlider->setValue(UBSettings::defaultColorPaletteSize); + resetPenSettings(); + resetMarkerSettings(); +} + + +QWidget* UBColorPreferencesDialog::createToolTab(const QString& lightTitle, + const QString& darkTitle, + QWidget*& lightFrame, + QWidget*& darkFrame, + QList& lightShortcutLabels, + QList& darkShortcutLabels, + QList& lightButtons, + QList& darkButtons, + const QList& lightColors, + const QList& darkColors, + const QString& lightRole, + const QString& darkRole, + QPushButton*& resetButton) +{ + QWidget* tab = new QWidget(this); + QVBoxLayout* tabLayout = new QVBoxLayout(tab); + tabLayout->setContentsMargins(8, 14, 8, 6); + tabLayout->setSpacing(14); + + buildColorSection(tabLayout, lightTitle, lightFrame, lightShortcutLabels, lightButtons, lightColors, lightRole); + buildColorSection(tabLayout, darkTitle, darkFrame, darkShortcutLabels, darkButtons, darkColors, darkRole); + + tabLayout->addStretch(); + + QHBoxLayout* resetLayout = new QHBoxLayout(); + resetLayout->addStretch(); + resetButton = new QPushButton(tab); + resetLayout->addWidget(resetButton); + tabLayout->addLayout(resetLayout); + + return tab; +} + + +void UBColorPreferencesDialog::buildColorSection(QVBoxLayout* parentLayout, + const QString& title, + QWidget*& frame, + QList& shortcutLabels, + QList& buttons, + const QList& colors, + const QString& role) +{ + QWidget* parentWidget = parentLayout ? parentLayout->parentWidget() : this; + QWidget* sectionWidget = new QWidget(parentWidget); + sectionWidget->setObjectName(QStringLiteral("colorPreferencesSection")); + QVBoxLayout* sectionLayout = new QVBoxLayout(sectionWidget); + sectionLayout->setContentsMargins(14, 12, 14, 12); + sectionLayout->setSpacing(8); + + QLabel* titleLabel = new QLabel(title, sectionWidget); + titleLabel->setObjectName(QStringLiteral("colorPreferencesSectionTitle")); + sectionLayout->addWidget(titleLabel); + + frame = new QFrame(sectionWidget); + frame->setObjectName(QStringLiteral("colorPreviewFrame")); + frame->setProperty("previewMode", role.endsWith(QLatin1String("Dark")) ? QStringLiteral("dark") : QStringLiteral("light")); + frame->setAutoFillBackground(true); + frame->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + + QGridLayout* layout = new QGridLayout(frame); + layout->setSizeConstraint(QLayout::SetFixedSize); + layout->setContentsMargins(10, 8, 10, 8); + layout->setHorizontalSpacing(0); + layout->setVerticalSpacing(4); + buildSwatches(layout, shortcutLabels, buttons, colors, role); + sectionLayout->addWidget(frame, 0, Qt::AlignHCenter); + parentLayout->addWidget(sectionWidget); +} + + +void UBColorPreferencesDialog::buildSwatches(QGridLayout* layout, + QList& shortcutLabels, + QList& buttons, + const QList& colors, + const QString& role) +{ + QWidget* parent = layout ? layout->parentWidget() : this; + + for (int i = 0; i < mMaxPaletteSize; ++i) + { + QLabel* shortcut = new QLabel(colorIndexLabel(i), parent); + shortcut->setObjectName(QStringLiteral("colorShortcutLabel")); + shortcut->setAlignment(Qt::AlignCenter); + shortcut->setFixedSize(32, 14); + shortcut->setToolTip(colorToolTip(i)); + shortcutLabels.append(shortcut); + + QToolButton* button = new QToolButton(parent); + button->setAutoRaise(false); + button->setIconSize(QSize(18, 18)); + button->setFixedSize(34, 30); + button->setProperty("index", i); + button->setProperty("role", role); + button->setToolTip(colorToolTip(i)); + buttons.append(button); + + if (layout) + { + layout->addWidget(shortcut, 0, i); + layout->addWidget(button, 1, i); + } + } + + const bool isMarkerRow = role.startsWith(QLatin1String("marker")); + + for (QToolButton* button : buttons) + { + if (isMarkerRow) + connect(button, SIGNAL(clicked()), this, SLOT(markerSwatchClicked())); + else + connect(button, SIGNAL(clicked()), this, SLOT(penSwatchClicked())); + } + + refreshSwatches(shortcutLabels, buttons, colors, mPaletteSizeSlider->value()); +} + + +void UBColorPreferencesDialog::refreshSwatches(QList& shortcutLabels, + QList& buttons, + const QList& colors, + int visibleCount) +{ + for (int i = 0; i < buttons.size(); ++i) + { + QLabel* shortcut = i < shortcutLabels.size() ? shortcutLabels.at(i) : nullptr; + QToolButton* button = buttons.at(i); + const bool visible = i < visibleCount; + + if (shortcut) + { + shortcut->setVisible(visible); + shortcut->setText(colorIndexLabel(i)); + shortcut->setToolTip(colorToolTip(i)); + } + + button->setVisible(visible); + button->setEnabled(visible); + button->setToolTip(colorToolTip(i)); + + if (visible) + { + QString objectName; + if (i == 0) + objectName = QStringLiteral("ubButtonGroupLeft"); + else if (i == visibleCount - 1) + objectName = QStringLiteral("ubButtonGroupRight"); + else + objectName = QStringLiteral("ubButtonGroupCenter"); + + if (button->objectName() != objectName) + { + button->setObjectName(objectName); + button->style()->unpolish(button); + button->style()->polish(button); + } + } + + if (i < colors.size()) + { + button->setIcon(swatchIcon(colors.at(i))); + } + } +} + + +void UBColorPreferencesDialog::refreshPenSwatches() +{ + const int visibleCount = mPaletteSizeSlider->value(); + refreshSwatches(mPenLightShortcutLabels, mPenLightButtons, mPenLightColors, visibleCount); + refreshSwatches(mPenDarkShortcutLabels, mPenDarkButtons, mPenDarkColors, visibleCount); +} + + +void UBColorPreferencesDialog::refreshMarkerSwatches() +{ + const int visibleCount = mPaletteSizeSlider->value(); + const QList markerLightWithOpacity = markerColorsWithOpacity(mMarkerLightColors); + const QList markerDarkWithOpacity = markerColorsWithOpacity(mMarkerDarkColors); + refreshSwatches(mMarkerLightShortcutLabels, mMarkerLightButtons, markerLightWithOpacity, visibleCount); + refreshSwatches(mMarkerDarkShortcutLabels, mMarkerDarkButtons, markerDarkWithOpacity, visibleCount); +} + + +void UBColorPreferencesDialog::ensureSize(QList& colors, const QList& defaults) +{ + if (defaults.isEmpty()) + return; + + for (int i = colors.size(); i < mMaxPaletteSize; ++i) + { + colors.append(defaults.value(i % defaults.size(), QColor(Qt::black))); + } + + if (colors.size() > mMaxPaletteSize) + { + colors = colors.mid(0, mMaxPaletteSize); + } +} + + +void UBColorPreferencesDialog::updateBackgroundFrames() +{ + auto applyBackground = [](QWidget* widget, const QList& labels, const QColor& background, const QColor& foreground) + { + if (!widget) + return; + + QPalette palette = widget->palette(); + palette.setColor(QPalette::Window, background); + palette.setColor(QPalette::WindowText, foreground); + widget->setPalette(palette); + + for (QLabel* label : labels) + { + if (!label) + continue; + + QPalette labelPalette = label->palette(); + labelPalette.setColor(QPalette::WindowText, foreground); + labelPalette.setColor(QPalette::Text, foreground); + label->setPalette(labelPalette); + } + }; + + applyBackground(mPenLightFrame, mPenLightShortcutLabels, QColor(Qt::white), QColor(Qt::black)); + applyBackground(mMarkerLightFrame, mMarkerLightShortcutLabels, QColor(Qt::white), QColor(Qt::black)); + applyBackground(mPenDarkFrame, mPenDarkShortcutLabels, QColor(Qt::black), QColor(Qt::white)); + applyBackground(mMarkerDarkFrame, mMarkerDarkShortcutLabels, QColor(Qt::black), QColor(Qt::white)); +} + + +QList UBColorPreferencesDialog::opaqueColors(const QList& colors) +{ + QList opaque; + + for (const auto& color : colors) + { + QColor opaqueColor = color; + opaqueColor.setAlpha(255); + opaque.append(opaqueColor); + } + + return opaque; +} + + +QIcon UBColorPreferencesDialog::swatchIcon(const QColor& color) +{ + const QSize size(12, 12); + QPixmap pixmap(size); + pixmap.fill(color); + return QIcon(pixmap); +} + + +QList UBColorPreferencesDialog::markerColorsWithOpacity(const QList& colors) const +{ + QList adjusted; + adjusted.reserve(colors.size()); + + const qreal opacityFactor = mMarkerOpacitySlider ? (mMarkerOpacitySlider->value() / 100.0) : 1.0; + + for (const QColor& color : colors) + { + QColor c = color; + c.setAlphaF(qBound(0.0, c.alphaF() * opacityFactor, 1.0)); + adjusted.append(c); + } + + return adjusted; +} + + +QString UBColorPreferencesDialog::colorIndexLabel(int index) const +{ + return QString::number(index + 1); +} + + +QAction* UBColorPreferencesDialog::colorActionForIndex(int index) const +{ + if (!UBApplication::mainWindow) + return nullptr; + + switch (index) + { + case 0: return UBApplication::mainWindow->actionColor0; + case 1: return UBApplication::mainWindow->actionColor1; + case 2: return UBApplication::mainWindow->actionColor2; + case 3: return UBApplication::mainWindow->actionColor3; + case 4: return UBApplication::mainWindow->actionColor4; + case 5: return UBApplication::mainWindow->actionColor5; + case 6: return UBApplication::mainWindow->actionColor6; + case 7: return UBApplication::mainWindow->actionColor7; + case 8: return UBApplication::mainWindow->actionColor8; + case 9: return UBApplication::mainWindow->actionColor9; + default: return nullptr; + } +} + + +QString UBColorPreferencesDialog::shortcutTextForIndex(int index) const +{ + QAction* action = colorActionForIndex(index); + if (!action) + return QString(); + + QStringList shortcutTexts; + for (const auto& shortcut : action->shortcuts()) + { + const QString text = shortcut.toString(QKeySequence::NativeText); + if (!text.isEmpty()) + shortcutTexts.append(text); + } + + return shortcutTexts.join(QStringLiteral(", ")); +} + + +QString UBColorPreferencesDialog::colorToolTip(int index) const +{ + const QString shortcutText = shortcutTextForIndex(index); + if (shortcutText.isEmpty()) + return tr("Color %1").arg(index + 1); + + return tr("Shortcut: %1").arg(shortcutText); +} + + +void UBColorPreferencesDialog::updateTabIcons(int currentIndex) +{ + const int penIndex = 0; + const int markerIndex = 1; + + if (!mTabWidget || mTabWidget->count() <= markerIndex) + return; + + mTabWidget->setTabIcon(penIndex, QIcon(currentIndex == penIndex + ? QStringLiteral(":/images/stylusPalette/penOn.svg") + : QStringLiteral(":/images/stylusPalette/pen.svg"))); + + mTabWidget->setTabIcon(markerIndex, QIcon(currentIndex == markerIndex + ? QStringLiteral(":/images/stylusPalette/markerOn.svg") + : QStringLiteral(":/images/stylusPalette/marker.svg"))); +} diff --git a/src/board/UBColorPreferencesDialog.h b/src/board/UBColorPreferencesDialog.h new file mode 100644 index 000000000..1386fa8bd --- /dev/null +++ b/src/board/UBColorPreferencesDialog.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) + * + * Copyright (C) 2013 Open Education Foundation + * + * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour + * l'Education Numérique en Afrique (GIP ENA) + * + * This file is part of OpenBoard. + * + * OpenBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, + * with a specific linking exception for the OpenSSL project's + * "OpenSSL" library (or with modified versions of it that use the + * same license as the "OpenSSL" library). + * + * OpenBoard is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenBoard. If not, see . + */ + + + + +#ifndef UBCOLORPREFERENCESDIALOG_H +#define UBCOLORPREFERENCESDIALOG_H + +#include +#include +#include +#include + +class QWidget; +class QGridLayout; +class QLabel; +class QVBoxLayout; +class QSlider; +class QTabWidget; +class QToolButton; +class QPushButton; +class QAction; +class QIcon; + +class UBColorPreferencesDialog : public QDialog +{ + Q_OBJECT + + public: + UBColorPreferencesDialog(QWidget* parent, + int paletteSize, + const QList& penLightColors, + const QList& penDarkColors, + const QList& markerLightColors, + const QList& markerDarkColors, + int markerOpacityPercent); + + int paletteSize() const; + QList penLightColors() const; + QList penDarkColors() const; + QList markerLightColors() const; + QList markerDarkColors() const; + int markerOpacity() const; + + private slots: + void paletteSizeChanged(int value); + void penSwatchClicked(); + void markerSwatchClicked(); + void markerOpacityChanged(int value); + void resetPenSettings(); + void resetMarkerSettings(); + void resetDefaultSettings(); + void updateTabIcons(int currentIndex); + + private: + QWidget* createToolTab(const QString& lightTitle, + const QString& darkTitle, + QWidget*& lightFrame, + QWidget*& darkFrame, + QList& lightShortcutLabels, + QList& darkShortcutLabels, + QList& lightButtons, + QList& darkButtons, + const QList& lightColors, + const QList& darkColors, + const QString& lightRole, + const QString& darkRole, + QPushButton*& resetButton); + void buildColorSection(QVBoxLayout* parentLayout, + const QString& title, + QWidget*& frame, + QList& shortcutLabels, + QList& buttons, + const QList& colors, + const QString& role); + void buildSwatches(QGridLayout* layout, + QList& shortcutLabels, + QList& buttons, + const QList& colors, + const QString& role); + void refreshSwatches(QList& shortcutLabels, QList& buttons, const QList& colors, int visibleCount); + void refreshPenSwatches(); + void refreshMarkerSwatches(); + void ensureSize(QList& colors, const QList& defaults); + void updateBackgroundFrames(); + static QIcon swatchIcon(const QColor& color); + static QList opaqueColors(const QList& colors); + QList markerColorsWithOpacity(const QList& colors) const; + QString colorIndexLabel(int index) const; + QAction* colorActionForIndex(int index) const; + QString shortcutTextForIndex(int index) const; + QString colorToolTip(int index) const; + + QSlider* mPaletteSizeSlider{nullptr}; + QLabel* mPaletteSizeValue{nullptr}; + QTabWidget* mTabWidget{nullptr}; + QSlider* mMarkerOpacitySlider{nullptr}; + QLabel* mMarkerOpacityValue{nullptr}; + QWidget* mPenLightFrame{nullptr}; + QWidget* mPenDarkFrame{nullptr}; + QWidget* mMarkerLightFrame{nullptr}; + QWidget* mMarkerDarkFrame{nullptr}; + QPushButton* mResetPenButton{nullptr}; + QPushButton* mResetMarkerButton{nullptr}; + QList mPenLightShortcutLabels; + QList mPenDarkShortcutLabels; + QList mMarkerLightShortcutLabels; + QList mMarkerDarkShortcutLabels; + QList mPenLightButtons; + QList mPenDarkButtons; + QList mMarkerLightButtons; + QList mMarkerDarkButtons; + QList mPenLightColors; + QList mPenDarkColors; + QList mMarkerLightColors; + QList mMarkerDarkColors; + QList mDefaultPenLightColors; + QList mDefaultPenDarkColors; + QList mDefaultMarkerLightColors; + QList mDefaultMarkerDarkColors; + const int mDefaultMarkerOpacityPercent; + const int mMinPaletteSize; + const int mMaxPaletteSize; +}; + + + +#endif // UBCOLORPREFERENCESDIALOG_H diff --git a/src/board/UBDrawingController.cpp b/src/board/UBDrawingController.cpp index 3af026399..130d61adb 100644 --- a/src/board/UBDrawingController.cpp +++ b/src/board/UBDrawingController.cpp @@ -283,7 +283,11 @@ QColor UBDrawingController::toolColor(bool onDarkBackground) void UBDrawingController::setColorIndex(int index) { - Q_ASSERT(index >= 0 && index < UBSettings::settings()->colorPaletteSize); + int paletteSize = UBSettings::settings()->colorPaletteSize; + if (paletteSize <= 0) + return; + + index = qBound(0, index, paletteSize - 1); if (stylusTool() == UBStylusTool::Marker) { @@ -347,6 +351,12 @@ void UBDrawingController::setMarkerAlpha(qreal alpha) emit colorPaletteChanged(); } + +void UBDrawingController::refreshColorPalette() +{ + emit colorPaletteChanged(); +} + void UBDrawingController::setActiveRuler(UBAbstractDrawRuler* ruler) { mActiveRuler = ruler; @@ -445,4 +455,3 @@ void UBDrawingController::captureToolSelected(bool checked) if (checked) setStylusTool(UBStylusTool::Capture); } - diff --git a/src/board/UBDrawingController.h b/src/board/UBDrawingController.h index a7affa6ed..8286938c1 100644 --- a/src/board/UBDrawingController.h +++ b/src/board/UBDrawingController.h @@ -82,6 +82,7 @@ class UBDrawingController : public QObject void setLineWidthIndex(int index); void setColorIndex(int index); void setEraserWidthIndex(int index); + void refreshColorPalette(); signals: void stylusToolChanged(int tool, int previousTool = -1); diff --git a/src/board/board.pri b/src/board/board.pri index c8d421e4e..3d9b399b0 100644 --- a/src/board/board.pri +++ b/src/board/board.pri @@ -2,16 +2,17 @@ HEADERS += src/board/UBBoardController.h \ src/board/UBBoardPaletteManager.h \ src/board/UBBoardView.h \ + src/board/UBColorPreferencesDialog.h \ src/board/UBDrawingController.h \ src/board/UBFeaturesController.h SOURCES += src/board/UBBoardController.cpp \ src/board/UBBoardPaletteManager.cpp \ src/board/UBBoardView.cpp \ + src/board/UBColorPreferencesDialog.cpp \ src/board/UBDrawingController.cpp \ src/board/UBFeaturesController.cpp - diff --git a/src/core/UBPreferencesController.cpp b/src/core/UBPreferencesController.cpp index f6d38b396..76c5fa479 100644 --- a/src/core/UBPreferencesController.cpp +++ b/src/core/UBPreferencesController.cpp @@ -379,16 +379,7 @@ void UBPreferencesController::wire() connect(mPreferencesUI->darkBackgroundOpacitySlider, SIGNAL(valueChanged(int)), this, SLOT(darkBackgroundCrossOpacityValueChanged(int))); // pen - QList penLightBackgroundColors = settings->boardPenLightBackgroundColors->colors(); - QList penDarkBackgroundColors = settings->boardPenDarkBackgroundColors->colors(); - QList penLightBackgroundSelectedColors = settings->boardPenLightBackgroundSelectedColors->colors(); - QList penDarkBackgroundSelectedColors = settings->boardPenDarkBackgroundSelectedColors->colors(); - - mPenProperties = new UBBrushPropertiesFrame(mPreferencesUI->penFrame, - penLightBackgroundColors, penDarkBackgroundColors, penLightBackgroundSelectedColors, - penDarkBackgroundSelectedColors, this); - - mPenProperties->opacityFrame->hide(); + mPenProperties = new UBBrushPropertiesFrame(mPreferencesUI->penFrame); connect(mPenProperties->fineSlider, SIGNAL(valueChanged(int)), this, SLOT(widthSliderChanged(int))); connect(mPenProperties->mediumSlider, SIGNAL(valueChanged(int)), this, SLOT(widthSliderChanged(int))); @@ -398,14 +389,7 @@ void UBPreferencesController::wire() connect(mPenProperties->circleSpinBox, SIGNAL(valueChanged(int)), this, SLOT(penPreviewFromSizeChanged(int))); // marker - QList markerLightBackgroundColors = settings->boardMarkerLightBackgroundColors->colors(); - QList markerDarkBackgroundColors = settings->boardMarkerDarkBackgroundColors->colors(); - QList markerLightBackgroundSelectedColors = settings->boardMarkerLightBackgroundSelectedColors->colors(); - QList markerDarkBackgroundSelectedColors = settings->boardMarkerDarkBackgroundSelectedColors->colors(); - - mMarkerProperties = new UBBrushPropertiesFrame(mPreferencesUI->markerFrame, markerLightBackgroundColors, - markerDarkBackgroundColors, markerLightBackgroundSelectedColors, - markerDarkBackgroundSelectedColors, this); + mMarkerProperties = new UBBrushPropertiesFrame(mPreferencesUI->markerFrame); mMarkerProperties->pressureSensitiveCheckBox->setText(tr("Marker is pressure sensitive")); @@ -415,7 +399,6 @@ void UBPreferencesController::wire() connect(mMarkerProperties->mediumSlider, SIGNAL(valueChanged(int)), this, SLOT(widthSliderChanged(int))); connect(mMarkerProperties->strongSlider, SIGNAL(valueChanged(int)), this, SLOT(widthSliderChanged(int))); connect(mMarkerProperties->pressureSensitiveCheckBox, SIGNAL(clicked(bool)), settings, SLOT(setMarkerPressureSensitive(bool))); - connect(mMarkerProperties->opacitySlider, SIGNAL(valueChanged(int)), this, SLOT(opacitySliderChanged(int))); // about tab connect(mPreferencesUI->checkSoftwareUpdateAtLaunchCheckBox, SIGNAL(clicked(bool)), settings->appEnableAutomaticSoftwareUpdates, SLOT(setBool(bool))); @@ -518,8 +501,6 @@ void UBPreferencesController::init() mMarkerProperties->strongSlider->setValue(settings->boardMarkerStrongWidth->get().toDouble() * sSliderRatio); mMarkerProperties->pressureSensitiveCheckBox->setChecked(settings->boardMarkerPressureSensitive->get().toBool()); - mMarkerProperties->opacitySlider->setValue(settings->boardMarkerAlpha->get().toDouble() * 100); - // shortcut tab mPreferencesUI->shortcutTableView->setModel(UBShortcutManager::shortcutManager()); mPreferencesUI->shortcutTableView->horizontalHeader()->setModel(UBShortcutManager::shortcutManager()); @@ -587,18 +568,6 @@ void UBPreferencesController::defaultSettings() mPenProperties->pressureSensitiveCheckBox->setChecked(settings->boardPenPressureSensitive->reset().toBool()); mPenProperties->circleCheckBox->setChecked(settings->showPenPreviewCircle->reset().toBool()); mPenProperties->circleSpinBox->setValue(settings->penPreviewFromSize->reset().toInt()); - - settings->boardPenLightBackgroundSelectedColors->reset(); - QList lightBackgroundSelectedColors = settings->boardPenLightBackgroundSelectedColors->colors(); - - settings->boardPenDarkBackgroundSelectedColors->reset(); - QList darkBackgroundSelectedColors = settings->boardPenDarkBackgroundSelectedColors->colors(); - - for (int i = 0 ; i < settings->colorPaletteSize ; i++) - { - mPenProperties->lightBackgroundColorPickers[i]->setSelectedColorIndex(lightBackgroundSelectedColors.indexOf(settings->penColors(false).at(i))); - mPenProperties->darkBackgroundColorPickers[i]->setSelectedColorIndex(darkBackgroundSelectedColors.indexOf(settings->penColors(true).at(i))); - } } else if (mPreferencesUI->mainTabWidget->currentWidget() == mPreferencesUI->markerTab) { @@ -606,20 +575,6 @@ void UBPreferencesController::defaultSettings() mMarkerProperties->mediumSlider->setValue(settings->boardMarkerMediumWidth->reset().toDouble() * sSliderRatio); mMarkerProperties->strongSlider->setValue(settings->boardMarkerStrongWidth->reset().toDouble() * sSliderRatio); mMarkerProperties->pressureSensitiveCheckBox->setChecked(settings->boardMarkerPressureSensitive->reset().toBool()); - - mMarkerProperties->opacitySlider->setValue(settings->boardMarkerAlpha->reset().toDouble() * 100); - - settings->boardMarkerLightBackgroundSelectedColors->reset(); - QList lightBackgroundSelectedColors = settings->boardMarkerLightBackgroundSelectedColors->colors(); - - settings->boardMarkerDarkBackgroundSelectedColors->reset(); - QList darkBackgroundSelectedColors = settings->boardMarkerDarkBackgroundSelectedColors->colors(); - - for (int i = 0 ; i < settings->colorPaletteSize ; i++) - { - mMarkerProperties->lightBackgroundColorPickers[i]->setSelectedColorIndex(lightBackgroundSelectedColors.indexOf(settings->markerColors(false).at(i))); - mMarkerProperties->darkBackgroundColorPickers[i]->setSelectedColorIndex(darkBackgroundSelectedColors.indexOf(settings->markerColors(true).at(i))); - } } else if (mPreferencesUI->mainTabWidget->currentWidget() == mPreferencesUI->aboutTab) { @@ -788,54 +743,6 @@ void UBPreferencesController::widthSliderChanged(int value) } -void UBPreferencesController::opacitySliderChanged(int value) -{ - qreal opacity = ((qreal)value) / 100; - - QObject *slider = sender(); - - if (slider == mMarkerProperties->opacitySlider) - { - UBDrawingController::drawingController()->setMarkerAlpha(opacity); - } -} - - -void UBPreferencesController::colorSelected(const QColor& color) -{ - UBColorPicker *colorPicker = qobject_cast(sender()); - - int index = mPenProperties->lightBackgroundColorPickers.indexOf(colorPicker); - - if (index >= 0) - { - UBDrawingController::drawingController()->setPenColor(false, color, index); - return; - } - - index = mPenProperties->darkBackgroundColorPickers.indexOf(colorPicker); - - if (index >= 0) - { - UBDrawingController::drawingController()->setPenColor(true, color, index); - } - - index = mMarkerProperties->lightBackgroundColorPickers.indexOf(colorPicker); - - if (index >= 0) - { - UBDrawingController::drawingController()->setMarkerColor(false, color, index); - } - - index = mMarkerProperties->darkBackgroundColorPickers.indexOf(colorPicker); - - if (index >= 0) - { - UBDrawingController::drawingController()->setMarkerColor(true, color, index); - } - -} - void UBPreferencesController::setCrossColorOnDarkBackground(const QColor& color) { UBSettings::settings()->boardCrossColorDarkBackground->set(color.name(QColor::HexArgb)); @@ -964,79 +871,9 @@ void UBPreferencesController::resetClicked() mPreferencesUI->noCtrl->setEnabled(!UBShortcutManager::shortcutManager()->hasCtrlConflicts()); } -UBBrushPropertiesFrame::UBBrushPropertiesFrame(QFrame* owner, const QList& lightBackgroundColors, - const QList& darkBackgroundColors, const QList& lightBackgroundSelectedColors, - const QList& darkBackgroundSelectedColors, UBPreferencesController* controller) +UBBrushPropertiesFrame::UBBrushPropertiesFrame(QFrame* owner) { setupUi(owner); - - QPalette lightBackgroundPalette = QApplication::palette(); - lightBackgroundPalette.setColor(QPalette::Window, Qt::white); - - lightBackgroundFrame->setAutoFillBackground(true); - lightBackgroundFrame->setPalette(lightBackgroundPalette); - - QPalette darkBackgroundPalette = QApplication::palette(); - darkBackgroundPalette.setColor(QPalette::Window, Qt::black); - darkBackgroundPalette.setColor(QPalette::ButtonText, Qt::white); - darkBackgroundPalette.setColor(QPalette::WindowText, Qt::white); - - darkBackgroundFrame->setAutoFillBackground(true); - darkBackgroundFrame->setPalette(darkBackgroundPalette); - darkBackgroundLabel->setPalette(darkBackgroundPalette); - - QList firstLightBackgroundColor; - firstLightBackgroundColor.append(lightBackgroundColors[0]); - - lightBackgroundColorPicker0->setColors(firstLightBackgroundColor); - lightBackgroundColorPicker0->setSelectedColorIndex(0); - lightBackgroundColorPickers.append(lightBackgroundColorPicker0); - - for (int i = 1 ; i < UBSettings::settings()->colorPaletteSize ; i++) - { - UBColorPicker *picker = new UBColorPicker(lightBackgroundFrame); - picker->setObjectName(QString("penLightBackgroundColor%1").arg(i)); - picker->setMinimumSize(QSize(32, 32)); - picker->setFrameShape(QFrame::StyledPanel); - picker->setFrameShadow(QFrame::Raised); - - lightBackgroundLayout->addWidget(picker); - - picker->setColors(lightBackgroundColors); - - picker->setSelectedColorIndex(lightBackgroundColors.indexOf(lightBackgroundSelectedColors.at(i))); - - lightBackgroundColorPickers.append(picker); - - QObject::connect(picker, SIGNAL(colorSelected(const QColor&)), controller, SLOT(colorSelected(const QColor&))); - - } - - QList firstDarkBackgroundColor; - firstDarkBackgroundColor.append(darkBackgroundColors[0]); - - darkBackgroundColorPicker0->setColors(firstDarkBackgroundColor); - darkBackgroundColorPicker0->setSelectedColorIndex(0); - darkBackgroundColorPickers.append(darkBackgroundColorPicker0); - - for (int i = 1 ; i < UBSettings::settings()->colorPaletteSize ; i++) - { - UBColorPicker *picker = new UBColorPicker(darkBackgroundFrame); - picker->setObjectName(QString("penDarkBackgroundColor%1").arg(i)); - picker->setMinimumSize(QSize(32, 32)); - picker->setFrameShape(QFrame::StyledPanel); - picker->setFrameShadow(QFrame::Raised); - - darkBackgroundLayout->addWidget(picker); - - picker->setColors(darkBackgroundColors); - picker->setSelectedColorIndex(darkBackgroundColors.indexOf(darkBackgroundSelectedColors.at(i))); - - darkBackgroundColorPickers.append(picker); - - QObject::connect(picker, SIGNAL(colorSelected(const QColor&)), controller, SLOT(colorSelected(const QColor&))); - - } } UBScreenListLineEdit::UBScreenListLineEdit(QWidget *parent) diff --git a/src/core/UBPreferencesController.h b/src/core/UBPreferencesController.h index e46762996..0e8116578 100644 --- a/src/core/UBPreferencesController.h +++ b/src/core/UBPreferencesController.h @@ -99,8 +99,6 @@ class UBPreferencesController : public QObject void darkBackgroundCrossOpacityValueChanged(int value); void lightBackgroundCrossOpacityValueChanged(int value); void widthSliderChanged(int value); - void opacitySliderChanged(int value); - void colorSelected(const QColor&); void setCrossColorOnDarkBackground(const QColor& color); void setCrossColorOnLightBackground(const QColor& color); void toolbarPositionChanged(bool checked); @@ -126,14 +124,9 @@ class UBPreferencesController : public QObject class UBBrushPropertiesFrame : public Ui::brushProperties { - - public: - UBBrushPropertiesFrame(QFrame* owner, const QList& lightBackgroundColors,const QList& darkBackgroundColors, const QList& lightBackgroundSelectedColors,const QList& darkBackgroundSelectedColors, UBPreferencesController* controller); - - virtual ~UBBrushPropertiesFrame(){} - - QList lightBackgroundColorPickers; - QList darkBackgroundColorPickers; +public: + explicit UBBrushPropertiesFrame(QFrame* owner); + virtual ~UBBrushPropertiesFrame(){} }; diff --git a/src/core/UBSetting.cpp b/src/core/UBSetting.cpp index 78f08052d..7ba14a738 100644 --- a/src/core/UBSetting.cpp +++ b/src/core/UBSetting.cpp @@ -156,6 +156,29 @@ QList UBColorListSetting::colors() const return mColors; } +QList UBColorListSetting::defaultColors() const +{ + QList colors; + + for (const auto& serializedColor : defaultValue().toStringList()) + { +#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)) + QColor color = QColor::fromString(serializedColor); +#else + QColor color; + color.setNamedColor(serializedColor); +#endif + if (mAlpha >= 0) + { + color.setAlphaF(mAlpha); + } + + colors.append(color); + } + + return colors; +} + void UBColorListSetting::setColor(int pIndex, const QColor& color) { QStringList list = get().toStringList(); @@ -171,6 +194,28 @@ void UBColorListSetting::setColor(int pIndex, const QColor& color) set(list); } +void UBColorListSetting::setColors(const QList& colors) +{ + mColors.clear(); + + QStringList serialized; + serialized.reserve(colors.size()); + + for (const QColor& inputColor : colors) + { + QColor color = inputColor; + if (mAlpha >= 0) + { + color.setAlphaF(mAlpha); + } + + serialized << color.name(QColor::HexArgb); + mColors << color; + } + + set(serialized); +} + void UBColorListSetting::setAlpha(qreal pAlpha) { mAlpha = pAlpha; diff --git a/src/core/UBSetting.h b/src/core/UBSetting.h index 94f135029..2618da9e9 100644 --- a/src/core/UBSetting.h +++ b/src/core/UBSetting.h @@ -104,9 +104,13 @@ class UBColorListSetting : public UBSetting virtual QVariant reset(); QList colors() const; + QList defaultColors() const; void setColor(int pIndex, const QColor& color); + // Replace the entire color list and persist it. + void setColors(const QList& colors); + void setAlpha(qreal pAlpha); protected: diff --git a/src/core/UBSettings.cpp b/src/core/UBSettings.cpp index f86d27054..0d6cd120c 100644 --- a/src/core/UBSettings.cpp +++ b/src/core/UBSettings.cpp @@ -50,7 +50,10 @@ int UBSettings::crossSize = 24; int UBSettings::defaultCrossSize = 24; int UBSettings::minCrossSize = 12; int UBSettings::maxCrossSize = 96; //TODO: user-settable? -int UBSettings::colorPaletteSize = 5; +const int UBSettings::minColorPaletteSize = 5; +const int UBSettings::maxColorPaletteSize = 10; +const int UBSettings::defaultColorPaletteSize = 8; +int UBSettings::colorPaletteSize = UBSettings::defaultColorPaletteSize; int UBSettings::objectFrameWidth = 20; int UBSettings::boardMargin = 10; @@ -138,6 +141,30 @@ int UBSettings::objectInControlViewMargin = 100; QString UBSettings::appPingMessage = "__uniboard_ping"; +QList UBSettings::normalizedColors(const QList& current, + const QList& defaults, + int targetSize, + bool& changed) +{ + QList result = current; + + if (result.size() < targetSize) + { + for (int i = result.size(); i < targetSize; ++i) + { + result.append(defaults.value(i % defaults.size(), QColor(Qt::black))); + } + changed = true; + } + else if (result.size() > targetSize) + { + result = result.mid(0, targetSize); + changed = true; + } + + return result; +} + UBSettings* UBSettings::settings() { if (!sSingleton) { @@ -304,6 +331,13 @@ void UBSettings::init() boardCrossColorDarkBackground = new UBSetting(this, "Board", "CrossColorDarkBackground", "#C8C0C0C0"); boardCrossColorLightBackground = new UBSetting(this, "Board", "CrossColorLightBackground", "#A5E1FF"); + boardColorPaletteSize = new UBSetting(this, "Board", "ColorPaletteSize", defaultColorPaletteSize); + colorPaletteSize = qBound(minColorPaletteSize, boardColorPaletteSize->get().toInt(), maxColorPaletteSize); + if (colorPaletteSize != boardColorPaletteSize->get().toInt()) + { + boardColorPaletteSize->set(colorPaletteSize); + } + QStringList gridLightBackgroundColors; gridLightBackgroundColors << "#000000" << "#FF0000" << "#004080" << "#008000" << "#FFDD00" << "#C87400" << "#800040" << "#008080" << "#A5E1FF"; boardGridLightBackgroundColors = new UBColorListSetting(this, "Board", "GridLightBackgroundColors", gridLightBackgroundColors, -1.0); @@ -317,17 +351,17 @@ void UBSettings::init() boardPenLightBackgroundColors = new UBColorListSetting(this, "Board", "PenLightBackgroundColors", penLightBackgroundColors, 1.0); QStringList penDarkBackgroundColors; - penDarkBackgroundColors << "#FFFFFF" << "#FF3400" <<"#66C0FF" << "#81FF5C" << "#FFFF00" << "#B68360" << "#FF497E" << "#8D69FF" << "#000000"; + penDarkBackgroundColors << "#FFFFFF" << "#FF3400" <<"#66C0FF" << "#81FF5C" << "#FFFF00" << "#B68360" << "#FF497E" << "#8D69FF" << "#C8C0C0" << "#000000"; boardPenDarkBackgroundColors = new UBColorListSetting(this, "Board", "PenDarkBackgroundColors", penDarkBackgroundColors, 1.0); boardMarkerAlpha = new UBSetting(this, "Board", "MarkerAlpha", 0.5); QStringList markerLightBackgroundColors; - markerLightBackgroundColors << "#E3FF00" << "#FF0000" <<"#004080" << "#008000" << "#C87400" << "#800040" << "#008080" << "#000000"; + markerLightBackgroundColors << "#E3FF00" << "#FF0000" <<"#004080" << "#008000" << "#C87400" << "#800040" << "#008080" << "#000000" << "#FFA500" << "#8000FF"; boardMarkerLightBackgroundColors = new UBColorListSetting(this, "Board", "MarkerLightBackgroundColors", markerLightBackgroundColors, boardMarkerAlpha->get().toDouble()); QStringList markerDarkBackgroundColors; - markerDarkBackgroundColors << "#FFFF00" << "#FF4400" <<"#66C0FF" << "#81FF5C" << "#B68360" << "#FF497E" << "#8D69FF" << "#FFFFFF"; + markerDarkBackgroundColors << "#FFFF00" << "#FF4400" <<"#66C0FF" << "#81FF5C" << "#B68360" << "#FF497E" << "#8D69FF" << "#FFFFFF" << "#00FFFF" << "#FFD700"; boardMarkerDarkBackgroundColors = new UBColorListSetting(this, "Board", "MarkerDarkBackgroundColors", markerDarkBackgroundColors, boardMarkerAlpha->get().toDouble()); QStringList penLightBackgroundSelectedColors; @@ -336,7 +370,7 @@ void UBSettings::init() QStringList markerLightBackgroundSelectedColors; QStringList markerDarkBackgroundSelectedColors; - for (int i = 0; i < colorPaletteSize; i++) + for (int i = 0; i < maxColorPaletteSize; i++) { penLightBackgroundSelectedColors << penLightBackgroundColors[i]; penDarkBackgroundSelectedColors << penDarkBackgroundColors[i]; @@ -644,20 +678,25 @@ QColor UBSettings::currentPenColor() QColor UBSettings::penColor(bool onDarkBackground) { QList colors = penColors(onDarkBackground); - return colors.at(penColorIndex()); + int index = qBound(0, penColorIndex(), colors.size() - 1); + return colors.value(index, colors.isEmpty() ? QColor(Qt::black) : colors.first()); } QList UBSettings::penColors(bool onDarkBackground) { - if (onDarkBackground) - { - return boardPenDarkBackgroundSelectedColors->colors(); - } - else + UBColorListSetting* selected = onDarkBackground ? boardPenDarkBackgroundSelectedColors : boardPenLightBackgroundSelectedColors; + UBColorListSetting* defaultsSetting = onDarkBackground ? boardPenDarkBackgroundColors : boardPenLightBackgroundColors; + + bool changed = false; + QList normalized = normalizedColors(selected->colors(), defaultsSetting->colors(), maxColorPaletteSize, changed); + + if (changed) { - return boardPenLightBackgroundSelectedColors->colors(); + selected->setColors(normalized); } + + return normalized.mid(0, colorPaletteSize); } @@ -726,20 +765,79 @@ QColor UBSettings::currentMarkerColor() QColor UBSettings::markerColor(bool onDarkBackground) { QList colors = markerColors(onDarkBackground); - return colors.at(markerColorIndex()); + int index = qBound(0, markerColorIndex(), colors.size() - 1); + return colors.value(index, colors.isEmpty() ? QColor(Qt::black) : colors.first()); } QList UBSettings::markerColors(bool onDarkBackground) { - if (onDarkBackground) + UBColorListSetting* selected = onDarkBackground ? boardMarkerDarkBackgroundSelectedColors : boardMarkerLightBackgroundSelectedColors; + UBColorListSetting* defaultsSetting = onDarkBackground ? boardMarkerDarkBackgroundColors : boardMarkerLightBackgroundColors; + + bool changed = false; + QList normalized = normalizedColors(selected->colors(), defaultsSetting->colors(), maxColorPaletteSize, changed); + + if (changed) { - return boardMarkerDarkBackgroundSelectedColors->colors(); + selected->setColors(normalized); } - else + + return normalized.mid(0, colorPaletteSize); +} + + +QList UBSettings::defaultPenColors(bool onDarkBackground) const +{ + UBColorListSetting* setting = onDarkBackground ? boardPenDarkBackgroundColors : boardPenLightBackgroundColors; + return setting->defaultColors(); +} + + +QList UBSettings::defaultMarkerColors(bool onDarkBackground) const +{ + UBColorListSetting* setting = onDarkBackground ? boardMarkerDarkBackgroundColors : boardMarkerLightBackgroundColors; + return setting->defaultColors(); +} + + +void UBSettings::setColorPaletteSize(int size) +{ + int clamped = qBound(minColorPaletteSize, size, maxColorPaletteSize); + + if (clamped == colorPaletteSize) + return; + + colorPaletteSize = clamped; + boardColorPaletteSize->set(colorPaletteSize); + + auto normalizeSelected = [this](UBColorListSetting* selected, UBColorListSetting* defaultsSetting) { - return boardMarkerLightBackgroundSelectedColors->colors(); + bool changed = false; + QList normalized = normalizedColors(selected->colors(), defaultsSetting->colors(), maxColorPaletteSize, changed); + if (changed) + { + selected->setColors(normalized); + } + }; + + normalizeSelected(boardPenLightBackgroundSelectedColors, boardPenLightBackgroundColors); + normalizeSelected(boardPenDarkBackgroundSelectedColors, boardPenDarkBackgroundColors); + normalizeSelected(boardMarkerLightBackgroundSelectedColors, boardMarkerLightBackgroundColors); + normalizeSelected(boardMarkerDarkBackgroundSelectedColors, boardMarkerDarkBackgroundColors); + + int maxIndex = qMax(0, colorPaletteSize - 1); + if (penColorIndex() > maxIndex) + { + setPenColorIndex(maxIndex); + } + + if (markerColorIndex() > maxIndex) + { + setMarkerColorIndex(maxIndex); } + + emit colorContextChanged(); } //----------------------------------------// @@ -1455,7 +1553,7 @@ void UBSettings::checkNewSettings() << boardMarkerLightBackgroundSelectedColors; foreach (UBColorListSetting* setting, colorSettings) { - if (setting->colors().size() < 5) + if (setting->colors().size() < minColorPaletteSize) setting->reset(); } @@ -1485,6 +1583,15 @@ void UBSettings::checkNewSettings() setting->set(currentColors); } + int storedPaletteSize = boardColorPaletteSize->get().toInt(); + if (storedPaletteSize < minColorPaletteSize || storedPaletteSize > maxColorPaletteSize) + { + storedPaletteSize = defaultColorPaletteSize; + boardColorPaletteSize->set(storedPaletteSize); + } + + setColorPaletteSize(storedPaletteSize); + // A typo was corrected in version 1.3 removeSetting("Board/useSystemOnScreenKeybard"); diff --git a/src/core/UBSettings.h b/src/core/UBSettings.h index ca68c291f..f87e8e7cf 100644 --- a/src/core/UBSettings.h +++ b/src/core/UBSettings.h @@ -52,6 +52,10 @@ class UBSettings : public QObject UBSettings(QObject *parent = 0); virtual ~UBSettings(); void cleanNonPersistentSettings(); + static QList normalizedColors(const QList& current, + const QList& defaults, + int targetSize, + bool& changed); public: @@ -69,6 +73,7 @@ class UBSettings : public QObject QColor currentPenColor(); QColor penColor(bool onDarkBackground); QList penColors(bool onDarkBackground); + QList defaultPenColors(bool onDarkBackground) const; // Marker related int markerWidthIndex(); @@ -77,6 +82,12 @@ class UBSettings : public QObject QColor currentMarkerColor(); QColor markerColor(bool onDarkBackground); QList markerColors(bool onDarkBackground); + QList defaultMarkerColors(bool onDarkBackground) const; + + // Palette size + void setColorPaletteSize(int size); + int colorPaletteMin() const { return minColorPaletteSize; } + int colorPaletteMax() const { return maxColorPaletteSize; } // Eraser related int eraserWidthIndex(); @@ -195,6 +206,9 @@ class UBSettings : public QObject static int maxCrossSize; static int colorPaletteSize; + static const int minColorPaletteSize; + static const int maxColorPaletteSize; + static const int defaultColorPaletteSize; static int objectFrameWidth; static QString documentGroupName; @@ -301,6 +315,7 @@ class UBSettings : public QObject UBSetting* boardCrossColorDarkBackground; UBSetting* boardCrossColorLightBackground; + UBSetting* boardColorPaletteSize; UBColorListSetting* boardGridLightBackgroundColors; UBColorListSetting* boardGridDarkBackgroundColors; diff --git a/src/core/UBShortcutManager.cpp b/src/core/UBShortcutManager.cpp index 06e00e848..0f54fd7dd 100644 --- a/src/core/UBShortcutManager.cpp +++ b/src/core/UBShortcutManager.cpp @@ -203,7 +203,12 @@ void UBShortcutManager::addMainActions(UBMainWindow *mainWindow) mainWindow->actionColor1, mainWindow->actionColor2, mainWindow->actionColor3, - mainWindow->actionColor4 + mainWindow->actionColor4, + mainWindow->actionColor5, + mainWindow->actionColor6, + mainWindow->actionColor7, + mainWindow->actionColor8, + mainWindow->actionColor9 }, mainWindow); addActions(tr("Background"), { diff --git a/src/desktop/UBDesktopPropertyPalette.cpp b/src/desktop/UBDesktopPropertyPalette.cpp index 50b3c6488..f647f3e7a 100644 --- a/src/desktop/UBDesktopPropertyPalette.cpp +++ b/src/desktop/UBDesktopPropertyPalette.cpp @@ -63,9 +63,15 @@ UBDesktopPenPalette::UBDesktopPenPalette(QWidget *parent, UBRightPalette* rightP colorActions.append(UBApplication::mainWindow->actionColor2); colorActions.append(UBApplication::mainWindow->actionColor3); colorActions.append(UBApplication::mainWindow->actionColor4); + colorActions.append(UBApplication::mainWindow->actionColor5); + colorActions.append(UBApplication::mainWindow->actionColor6); + colorActions.append(UBApplication::mainWindow->actionColor7); + colorActions.append(UBApplication::mainWindow->actionColor8); + colorActions.append(UBApplication::mainWindow->actionColor9); + colorActions.append(UBApplication::mainWindow->actionColorPreferences); UBToolbarButtonGroup *colorChoice = - new UBToolbarButtonGroup(UBApplication::mainWindow->boardToolBar, colorActions, objectNamePrefix); + new UBToolbarButtonGroup(UBApplication::mainWindow->boardToolBar, colorActions, objectNamePrefix, UBSettings::settings()->colorPaletteSize); colorChoice->displayText(false); @@ -160,8 +166,14 @@ UBDesktopMarkerPalette::UBDesktopMarkerPalette(QWidget *parent, UBRightPalette* colorActions.append(UBApplication::mainWindow->actionColor2); colorActions.append(UBApplication::mainWindow->actionColor3); colorActions.append(UBApplication::mainWindow->actionColor4); - - UBToolbarButtonGroup *colorChoice = new UBToolbarButtonGroup(UBApplication::mainWindow->boardToolBar, colorActions, objectNamePrefix); + colorActions.append(UBApplication::mainWindow->actionColor5); + colorActions.append(UBApplication::mainWindow->actionColor6); + colorActions.append(UBApplication::mainWindow->actionColor7); + colorActions.append(UBApplication::mainWindow->actionColor8); + colorActions.append(UBApplication::mainWindow->actionColor9); + colorActions.append(UBApplication::mainWindow->actionColorPreferences); + + UBToolbarButtonGroup *colorChoice = new UBToolbarButtonGroup(UBApplication::mainWindow->boardToolBar, colorActions, objectNamePrefix, UBSettings::settings()->colorPaletteSize); colorChoice->displayText(false); //connect(colorChoice, SIGNAL(activated(int)), this, SLOT(UBApplication::boardController->setColorIndex(int))); @@ -188,4 +200,3 @@ UBDesktopMarkerPalette::UBDesktopMarkerPalette(QWidget *parent, UBRightPalette* layout()->addWidget(lineWidthChoice); } - diff --git a/src/gui/UBToolbarButtonGroup.cpp b/src/gui/UBToolbarButtonGroup.cpp index 2c2e25233..1daba1e3b 100644 --- a/src/gui/UBToolbarButtonGroup.cpp +++ b/src/gui/UBToolbarButtonGroup.cpp @@ -40,10 +40,11 @@ #include "core/memcheck.h" -UBToolbarButtonGroup::UBToolbarButtonGroup(QToolBar *toolBar, const QList &actions, QString objectNameprefix) +UBToolbarButtonGroup::UBToolbarButtonGroup(QToolBar *toolBar, const QList &actions, QString objectNameprefix, int selectableCount) : QWidget(toolBar) , mActions(actions) , mCurrentIndex(-1) + , mSelectableCount(selectableCount <= 0 ? actions.size() : qMin(selectableCount, actions.size())) , mDisplayLabel(true) , mActionGroup(0) { @@ -68,12 +69,17 @@ UBToolbarButtonGroup::UBToolbarButtonGroup(QToolBar *toolBar, const QListaddAction(action); + if (action->isCheckable()) + mActionGroup->addAction(action); QToolButton *button = new QToolButton(this); mButtons.append(button); button->setDefaultAction(action); - button->setCheckable(true); + button->setCheckable(action->isCheckable()); + if (action->objectName() == QLatin1String("actionColorPreferences")) + { + button->setProperty("colorPaletteConfigButton", true); + } if(i == 0) { @@ -95,13 +101,15 @@ UBToolbarButtonGroup::UBToolbarButtonGroup(QToolBar *toolBar, const QListsetObjectName("ubButtonGroupCenter"); } - connect(button, SIGNAL(triggered(QAction*)), this, SLOT(selected(QAction*))); + connect(button, SIGNAL(triggered(QAction*)), this, SLOT(setSelected(QAction*))); horizontalLayout->addWidget(button); mLabel = action->text(); buttonSize = button->sizeHint(); i++; } + + setSelectableCount(mSelectableCount); } UBToolbarButtonGroup::~UBToolbarButtonGroup() @@ -114,6 +122,33 @@ void UBToolbarButtonGroup::setLabel(const QString& label) mLabel = label; } +void UBToolbarButtonGroup::setSelectableCount(int count) +{ + mSelectableCount = qBound(0, count, mActions.size()); + + for (int i = 0; i < mButtons.size(); ++i) + { + QAction* action = mActions.at(i); + bool selectable = action->isCheckable() && i < mSelectableCount; + + if (action->isCheckable()) + { + action->setEnabled(selectable); + mButtons.at(i)->setVisible(selectable); + } + else + { + action->setEnabled(true); + mButtons.at(i)->setVisible(true); + } + } + + if (mCurrentIndex >= mSelectableCount) + { + mCurrentIndex = -1; + } +} + void UBToolbarButtonGroup::setIcon(const QIcon &icon, int index) { Q_ASSERT(index < mActions.size()); @@ -144,30 +179,17 @@ void UBToolbarButtonGroup::setColor(const QColor &color, int index) setIcon(icon, index); } -void UBToolbarButtonGroup::selected(QAction *action) +void UBToolbarButtonGroup::setSelected(QAction *action) { -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - foreach(QObject *widget, action->associatedObjects()) -#else - foreach(QWidget *widget, action->associatedWidgets()) -#endif - { - QToolButton *button = qobject_cast(widget); - if (button) - { - int i = 0; - foreach(QAction *eachAction, mActions) - { - if (eachAction == action) - { - setCurrentIndex(i); - emit activated(i); - break; - } - i++; - } - } - } + int index = mActions.indexOf(action); + if (index < 0 || index >= mSelectableCount) + return; + + if (!action->isCheckable()) + return; + + setCurrentIndex(index); + emit activated(index); } int UBToolbarButtonGroup::currentIndex() const @@ -177,7 +199,10 @@ int UBToolbarButtonGroup::currentIndex() const void UBToolbarButtonGroup::setCurrentIndex(int index) { - Q_ASSERT(index < mButtons.size()); + Q_ASSERT(index < mSelectableCount || mSelectableCount == 0); + + if (mSelectableCount == 0) + return; if (index != mCurrentIndex) { @@ -224,6 +249,8 @@ void UBToolbarButtonGroup::paintEvent(QPaintEvent *) void UBToolbarButtonGroup::colorPaletteChanged() { + setSelectableCount(qMin(UBSettings::settings()->colorPaletteSize, mActions.size())); + bool isDarkBackground = UBSettings::settings()->isDarkBackground(); QList colors; @@ -238,7 +265,7 @@ void UBToolbarButtonGroup::colorPaletteChanged() colors = UBSettings::settings()->markerColors(isDarkBackground); } - for (int i = 0; i < mButtons.size() && i < colors.size(); i++) + for (int i = 0; i < mSelectableCount && i < colors.size(); i++) { setColor(colors.at(i), i); } diff --git a/src/gui/UBToolbarButtonGroup.h b/src/gui/UBToolbarButtonGroup.h index 6ab0d785a..25e419839 100644 --- a/src/gui/UBToolbarButtonGroup.h +++ b/src/gui/UBToolbarButtonGroup.h @@ -42,13 +42,15 @@ class UBToolbarButtonGroup : public QWidget Q_OBJECT; public: - UBToolbarButtonGroup(QToolBar *toolbar, const QList &actions = QList(), QString objectNameprefix = ""); + UBToolbarButtonGroup(QToolBar *toolbar, const QList &actions = QList(), QString objectNameprefix = "", int selectableCount = -1); virtual ~UBToolbarButtonGroup(); void setIcon(const QIcon &icon, int index); void setColor(const QColor &color, int index); int currentIndex() const; void setLabel(const QString& label); + void setSelectableCount(int count); + int selectableCount() const { return mSelectableCount; } protected: void paintEvent(QPaintEvent *); @@ -59,6 +61,7 @@ class UBToolbarButtonGroup : public QWidget QList mActions; QList mButtons; int mCurrentIndex; + int mSelectableCount; bool mDisplayLabel; QActionGroup* mActionGroup; @@ -68,7 +71,7 @@ class UBToolbarButtonGroup : public QWidget void displayText(QVariant display); private slots: - void selected(QAction *action); + void setSelected(QAction *action); signals: void activated(int index); From abbf89386cebdb8943ca641f12f39c404e05a71e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Mon, 2 Feb 2026 16:41:19 +0100 Subject: [PATCH 121/133] fix: drag&drop multiple pages and selection behavior In Document Thumbnails view : - restored 1.7.3 selection behavior - fixed drag and drop #1402 issue - when no page is selected, selecting one now works even if Shift is pressed --- src/gui/UBDocumentThumbnailsView.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/gui/UBDocumentThumbnailsView.cpp b/src/gui/UBDocumentThumbnailsView.cpp index 9468aa5b3..89404b123 100644 --- a/src/gui/UBDocumentThumbnailsView.cpp +++ b/src/gui/UBDocumentThumbnailsView.cpp @@ -160,6 +160,12 @@ void UBDocumentThumbnailsView::mousePressEvent(QMouseEvent *event) mSelectionSpan = index2 - index1; selectItems(qMin(index1, index2), mSelectionSpan < 0 ? - mSelectionSpan + 1 : mSelectionSpan + 1); } + else + { + int index = sceneItem->sceneIndex(); + selectItemAt(index, Qt::ControlModifier & event->modifiers()); + mSelectionSpan = 0; + } } else { @@ -170,7 +176,7 @@ void UBDocumentThumbnailsView::mousePressEvent(QMouseEvent *event) } else { - thumbnailScene->hightlightItem(sceneItem->sceneIndex(), true); + thumbnailScene->hightlightItem(sceneItem->sceneIndex()); } mSelectionSpan = 0; @@ -241,6 +247,25 @@ void UBDocumentThumbnailsView::mouseReleaseEvent(QMouseEvent *event) emit mouseClick(itemAt(event->pos()), 0); } + // clicking on the same thumbnail with no modifiers should make it the only one selected + // Not done in the mousePressEvent function to let the drag and drop feature work as intented + if (event->modifiers() == Qt::NoModifier) + { + UBThumbnail* sceneItem = dynamic_cast(itemAt(event->pos())); + + if (sceneItem) + { + if (sceneItem->isSelected() && mDocument) + { + auto thumbnailScene = mDocument->thumbnailScene(); + if (thumbnailScene) + { + thumbnailScene->hightlightItem(sceneItem->sceneIndex(), true); + } + } + } + } + // do not forward event to parent class as this affects selection } From ed8e113283cec93fe1941a28fdf076baabc5a0ee Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Tue, 24 Feb 2026 13:43:35 +0100 Subject: [PATCH 122/133] fix: board thumbnails after duplicating scene - when duplicating a scene in board mode while the left palette is hidden and then showing the palette, the thumbnail arrangement was broken - unconditionally rearrange thumbnails when showing palette Signed-off-by: letsfindaway --- src/gui/UBBoardThumbnailsView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/UBBoardThumbnailsView.cpp b/src/gui/UBBoardThumbnailsView.cpp index 002a13917..718a05756 100644 --- a/src/gui/UBBoardThumbnailsView.cpp +++ b/src/gui/UBBoardThumbnailsView.cpp @@ -160,7 +160,7 @@ void UBBoardThumbnailsView::resizeEvent(QResizeEvent *event) bool scrollbarWasHidden = mScrollbarVisible && !verticalScrollBar()->isVisible(); // Refresh the scene, except if resizing because scrollbar was hidden - if (event->size().width() > 0 && !scrollbarWasHidden && mDocument) + if (event->oldSize().width() == 0 || (event->size().width() > 0 && !scrollbarWasHidden && mDocument)) { mDocument->thumbnailScene()->arrangeThumbnails(); ensureVisibleThumbnail(UBApplication::boardController->activeSceneIndex()); From c3d509c3e4b2ff91a65710c28932e0c733932cff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Tue, 24 Feb 2026 14:26:29 +0100 Subject: [PATCH 123/133] fixed a bug probably caused by the adding of new information between xstartref and the root object, making any pdf export to fail because it could not find the /Root object. Simply increased the size of the portion that is read to find it --- src/pdf-merger/OverlayDocumentParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pdf-merger/OverlayDocumentParser.cpp b/src/pdf-merger/OverlayDocumentParser.cpp index e885688b2..98cdfc124 100644 --- a/src/pdf-merger/OverlayDocumentParser.cpp +++ b/src/pdf-merger/OverlayDocumentParser.cpp @@ -39,7 +39,7 @@ using namespace merge_lib; using namespace std; -int OverlayDocumentParser::DOC_PART_WITH_START_OF_XREF = 30; +int OverlayDocumentParser::DOC_PART_WITH_START_OF_XREF = 1024; unsigned int partSize = 10485760; // = 10 Mb Document * OverlayDocumentParser::parseDocument(const char * fileName) From 5066250f683f0d47dfc5cb545377aef77a976215 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Wed, 25 Feb 2026 08:18:11 +0100 Subject: [PATCH 124/133] build: adapt to poppler 26.02 - poppler 26.02 removes an obsolete parameter from the constructor of SplashOutputDev - conditionally remove this parameter depending on poppler version Signed-off-by: letsfindaway --- src/pdf/XPDFRenderer.cpp | 4 ++++ src/pdf/XPDFRenderer.h | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/pdf/XPDFRenderer.cpp b/src/pdf/XPDFRenderer.cpp index 4d6c98f8f..8e361430c 100644 --- a/src/pdf/XPDFRenderer.cpp +++ b/src/pdf/XPDFRenderer.cpp @@ -235,7 +235,11 @@ QImage* XPDFRenderer::createPDFImageUncached(int pageNumber, qreal xscale, qreal if(mSplashUncached) delete mSplashUncached; +#if POPPLER_VERSION_MAJOR > 26 || (POPPLER_VERSION_MAJOR == 26 && POPPLER_VERSION_MINOR >= 2) + mSplashUncached = new SplashOutputDev(splashModeRGB8, 1, constants::paperColor); +#else mSplashUncached = new SplashOutputDev(splashModeRGB8, 1, false, constants::paperColor); +#endif mSplashUncached->startDoc(mDocument); int rotation = 0; // in degrees (get it from the worldTransform if we want to support rotation) diff --git a/src/pdf/XPDFRenderer.h b/src/pdf/XPDFRenderer.h index 0e8de81a2..6264ae1b0 100644 --- a/src/pdf/XPDFRenderer.h +++ b/src/pdf/XPDFRenderer.h @@ -42,6 +42,7 @@ #include #include #include +#include class PDFDoc; @@ -105,7 +106,11 @@ class XPDFRenderer : public PDFRenderer cachedImage = QImage(); delete splash; } +#if POPPLER_VERSION_MAJOR > 26 || (POPPLER_VERSION_MAJOR == 26 && POPPLER_VERSION_MINOR >= 2) + splash = new SplashOutputDev(splashModeRGB8, 1, paperColor); +#else splash = new SplashOutputDev(splashModeRGB8, 1, false, paperColor); +#endif cachedPageNumber = pageNumber; } From 37f12ebd2f991ffcbf84ff5136d51266b4a76748 Mon Sep 17 00:00:00 2001 From: letsfindaway Date: Mon, 2 Mar 2026 17:50:26 +0100 Subject: [PATCH 125/133] fix: enable Cookie storage - default WebEngine profile is private browsing since Qt 6 - use a named profile to enable cookie storage as with Qt 5 - name it Default, so that it actually uses the same location Signed-off-by: letsfindaway --- src/web/UBWebController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/UBWebController.cpp b/src/web/UBWebController.cpp index 34503d80f..aad2d210a 100644 --- a/src/web/UBWebController.cpp +++ b/src/web/UBWebController.cpp @@ -95,7 +95,7 @@ UBWebController::UBWebController(UBMainWindow* mainWindow) } else { - mWebProfile = QWebEngineProfile::defaultProfile(); + mWebProfile = new QWebEngineProfile("Default"); mWebProfile->setHttpCacheType(QWebEngineProfile::DiskHttpCache); } From 8d13f1fe80e3fa47b5fe5e096b6134722b4bea4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Thu, 19 Mar 2026 12:31:05 +0100 Subject: [PATCH 126/133] don't force white background on widgets for Qt versions above 6.8.0 --- src/domain/UBGraphicsWidgetItem.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/domain/UBGraphicsWidgetItem.cpp b/src/domain/UBGraphicsWidgetItem.cpp index 8edb79d30..906b23003 100644 --- a/src/domain/UBGraphicsWidgetItem.cpp +++ b/src/domain/UBGraphicsWidgetItem.cpp @@ -168,10 +168,9 @@ UBGraphicsWidgetItem::UBGraphicsWidgetItem(const QUrl &pWidgetUrl, QGraphicsItem setAutoFillBackground(false); /* - * Quick workaround for https://bugreports.qt.io/browse/QTBUG-128241 (bug appearing with Qt 6.7.2) - * To test with Qt 6.8.1 and then change the following directive if really fixed with it + * Quick workaround for https://bugreports.qt.io/browse/QTBUG-128241 (bug appearing with Qt 6.7.2, fixed in 6.8.1) */ -#if (QT_VERSION < QT_VERSION_CHECK(6, 7, 2)) +#if (QT_VERSION < QT_VERSION_CHECK(6, 7, 2) || QT_VERSION > QT_VERSION_CHECK(6, 8, 0)) mWebEngineView->setAttribute(Qt::WA_TranslucentBackground); mWebEngineView->page()->setBackgroundColor(QColor(Qt::transparent)); #else From dbf95608281b1b92d6c5a8811313f875868d80e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Thu, 2 Apr 2026 10:52:47 +0200 Subject: [PATCH 127/133] fixed a bug where thumbnails would be empty after a PDF import --- src/core/UBDocumentManager.cpp | 2 +- src/document/UBDocument.cpp | 8 ++++++-- src/document/UBDocument.h | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/core/UBDocumentManager.cpp b/src/core/UBDocumentManager.cpp index 37d738334..a940de21b 100644 --- a/src/core/UBDocumentManager.cpp +++ b/src/core/UBDocumentManager.cpp @@ -338,7 +338,7 @@ int UBDocumentManager::importPages(const QFile& file, std::shared_ptr scene = doc->createPage(pageIndex, false, false); + std::shared_ptr scene = doc->createPage(pageIndex, false, false, true, false); importAdaptor->placeImportedItemToScene(scene, page); doc->persistPage(scene, pageIndex, false, false, false, false); pageIndex++; diff --git a/src/document/UBDocument.cpp b/src/document/UBDocument.cpp index 7bd4fd5a1..7057ae4d0 100644 --- a/src/document/UBDocument.cpp +++ b/src/document/UBDocument.cpp @@ -196,7 +196,7 @@ bool UBDocument::copyPage(int fromIndex, std::shared_ptr to, int toI return copyPage(fromIndex, to.get(), toIndex); } -std::shared_ptr UBDocument::createPage(int index, bool saveToc, bool cached, bool useUndoRedoStack) +std::shared_ptr UBDocument::createPage(int index, bool saveToc, bool cached, bool useUndoRedoStack, bool createThumbnail) { // create a new TOC entry for the page assureHeaderLoaderFinished(); @@ -217,7 +217,11 @@ std::shared_ptr UBDocument::createPage(int index, bool saveToc, } thumbnailScene()->insertThumbnail(index, false); - mThumbnailScene->ensureThumbnail(index, scene.get()); + + if (createThumbnail) + { + mThumbnailScene->ensureThumbnail(index, scene.get()); + } return scene; } diff --git a/src/document/UBDocument.h b/src/document/UBDocument.h index c055ba7cd..5adfe168f 100644 --- a/src/document/UBDocument.h +++ b/src/document/UBDocument.h @@ -64,7 +64,7 @@ class UBDocument : public std::enable_shared_from_this bool movePage(int fromIndex, int toIndex); bool copyPage(int fromIndex, std::shared_ptr to, int toIndex); std::shared_ptr createPage(int index, bool saveToc = true, bool cached = true, - bool useUndoRedoStack = true); + bool useUndoRedoStack = true, bool createThumbnail = true); void persistPage(std::shared_ptr scene, int index, bool isAutomaticBackup = false, bool forceImmediateSaving = false, bool persistThumbnail = true, bool addToCache = true); std::shared_ptr loadScene(int index, bool cacheNeighboringScenes = true); From 57a25576b2d9234301083694d18dec97a21171d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fauconnier?= Date: Thu, 2 Apr 2026 11:19:34 +0200 Subject: [PATCH 128/133] removed forcing styles on replacement dialog --- src/document/UBDocumentController.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index 3d3c69c0f..14c6c2e5a 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -109,8 +109,6 @@ UBDocumentReplaceDialog::UBDocumentReplaceDialog(const QString &pIncommingName, , mCancel(false) , mMultipleFiles(multipleFiles) { - this->setStyleSheet("background:white;"); - QVBoxLayout *mainLayout = new QVBoxLayout(this); QVBoxLayout *labelLayout = new QVBoxLayout(); @@ -222,20 +220,16 @@ void UBDocumentReplaceDialog::reject() void UBDocumentReplaceDialog::reactOnTextChanged(const QString &pStr) { // if !mFileNameList.contains(pStr.trimmed(), Qt::CaseSensitive) - if (!validString(pStr)) { acceptButton->setEnabled(false); - mLineEdit->setStyleSheet("background:#FFB3C8;"); acceptButton->setEnabled(false); } else if (mFileNameList.contains(pStr.trimmed(), Qt::CaseSensitive)) { acceptButton->setEnabled(true); - mLineEdit->setStyleSheet("background:#FFB3C8;"); acceptButton->setText(replaceText); } else { acceptButton->setEnabled(true); - mLineEdit->setStyleSheet("background:white;"); acceptButton->setText(acceptText); } } From 445794d5ee6caeffbe976d9d8d7959fb9d05eb7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20W=C3=BCnsche?= Date: Thu, 23 Apr 2026 12:06:04 +0200 Subject: [PATCH 129/133] =?UTF-8?q?Update=20StartupHints=20for=20alignment?= =?UTF-8?q?=20with=20versions=201.7.7=20and=20upcoming=201.8=20What?= =?UTF-8?q?=E2=80=99s=20new:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improved content layout and refreshed styling Integrated dark and light themes Enhanced navigation bar and hint presentation Scrollbar now matches the active theme Hint 1 is now interactive All available StartupHints languages have been patched Most content remains unchanged. This update primarily focuses on styling, display improvements, smoother navigation, and better UI harmonization for version 1.8. --- .../assets/common/PicturesCategory.svg | 424 ++++++++++ .../startupHints/assets/common/board.png | Bin 0 -> 2105 bytes .../assets/common/eraserArrow.svg | 398 ++++----- .../startupHints/assets/common/favorites.png | Bin 0 -> 1396 bytes .../{images => assets/common}/left.png | Bin .../assets/common/markerArrow.svg | 460 +++++------ .../startupHints/assets/common/penArrow.svg | 572 ++++++------- .../startupHints/assets/common/record.png | Bin 0 -> 1708 bytes .../{images => assets/common}/right.png | Bin .../assets/hint1/openboard-logo.png.bck | Bin 6610 -> 0 bytes ...board-logo.png => openboard-main-logo.png} | Bin .../{menu.png => openboard-menu-icon.png} | Bin ...if1.gif => built-in-applications-demo.gif} | Bin ...t-gif1.gif => video-capture-open-tool.gif} | Bin ....gif => video-capture-save-to-desktop.gif} | Bin ...cast2.png => video-recorder-interface.png} | Bin .../assets/hint12/favorites-add-document.png | Bin 0 -> 71160 bytes ...orites2.png => favorites-library-view.png} | Bin .../startupHints/assets/hint12/favorites.png | Bin 66465 -> 0 bytes ...vorites3.png => recent-documents-view.png} | Bin .../hint2/{arrow.png => board-mode-arrow.png} | Bin ...1.gif => board-mode-background-change.gif} | Bin .../{bo1.png => board-mode-pen-palette.png} | Bin .../hint2/{bo9.png => board-mode-toolbar.png} | Bin .../startupHints/assets/hint3/bureau1.png.bck | Bin 32002 -> 0 bytes ...u-gif1.gif => desktop-mode-annotation.gif} | Bin .../{bureau1.png => desktop-mode-icon.png} | Bin ...u-gif2.gif => desktop-mode-navigation.gif} | Bin ....gif => documents-folder-organization.gif} | Bin ...cument1.png => documents-manager-view.png} | Bin ...cument2.gif => documents-page-actions.gif} | Bin .../{gif2.gif => documents-export-files.gif} | Bin ....png => documents-import-export-panel.png} | Bin .../{gif1.gif => documents-import-files.gif} | Bin ...brary.png => add-tool-to-library-icon.png} | Bin ...p1.png => web-browser-integrated-view.png} | Bin ...pp-gif2.gif => web-create-library-app.gif} | Bin .../hint6/{app2.png => web-library-entry.png} | Bin .../{app-gif1.gif => web-open-website.gif} | Bin ...{app-gif3.gif => web-saved-in-library.gif} | Bin ...if-capture1.gif => board-area-capture.gif} | Bin ...2.png => board-capture-area-selection.png} | Bin ...{caputre3.png => board-capture-result.png} | Bin .../{capture1.png => board-capture-tool.png} | Bin ...ture-gif2.gif => desktop-area-capture.gif} | Bin ...{capture4.png => desktop-capture-tool.png} | Bin .../hint8/documents-import-export-zone.png | Bin 0 -> 44158 bytes ...ure2.png => image-library-folder-view.png} | Bin .../{capture1.png => image-library-open.png} | Bin ...if1.gif => images-folder-organization.gif} | Bin ...image-gif3.gif => images-local-import.gif} | Bin ...-gif2.gif => images-web-search-import.gif} | Bin ...ict.png => categorize-pictures-widget.png} | Bin ...-gif2.gif => interactivity-add-images.gif} | Bin ....png => interactivity-category-editor.png} | Bin ...if3.gif => interactivity-run-exercise.gif} | Bin ...ite1.png => interactivity-widget-list.png} | Bin resources/startupHints/css/basic.css | 101 --- resources/startupHints/css/dark.css | 50 ++ resources/startupHints/css/light.css | 50 ++ resources/startupHints/css/style.css | 492 +++++++++++ resources/startupHints/index.html | 156 +--- resources/startupHints/js/app.js | 445 ++++++++++ resources/startupHints/js/jquery-1.6.2.min.js | 18 - .../js/jquery-ui-1.8.9.custom.min.js | 781 ------------------ resources/startupHints/js/theme-loader.js | 14 + resources/startupHints/locales/de/1.html | 117 ++- resources/startupHints/locales/de/10.html | 145 ++-- resources/startupHints/locales/de/11.html | 135 ++- resources/startupHints/locales/de/12.html | 137 ++- resources/startupHints/locales/de/2.html | 175 ++-- resources/startupHints/locales/de/3.html | 110 ++- resources/startupHints/locales/de/4.html | 117 ++- resources/startupHints/locales/de/5.html | 150 +++- resources/startupHints/locales/de/6.html | 140 +++- resources/startupHints/locales/de/7.html | 152 ++-- resources/startupHints/locales/de/8.html | 144 +++- resources/startupHints/locales/de/9.html | 148 ++-- .../startupHints/locales/de/css/dark.css | 8 - .../startupHints/locales/de/css/light.css | 8 - .../startupHints/locales/de/css/style.css | 36 - resources/startupHints/locales/de/error.html | 35 +- resources/startupHints/locales/en/1.html | 117 ++- resources/startupHints/locales/en/10.html | 145 ++-- resources/startupHints/locales/en/11.html | 136 +-- resources/startupHints/locales/en/12.html | 137 ++- resources/startupHints/locales/en/2.html | 175 ++-- resources/startupHints/locales/en/3.html | 110 ++- resources/startupHints/locales/en/4.html | 117 ++- resources/startupHints/locales/en/5.html | 150 +++- resources/startupHints/locales/en/6.html | 140 +++- resources/startupHints/locales/en/7.html | 152 ++-- resources/startupHints/locales/en/8.html | 144 +++- resources/startupHints/locales/en/9.html | 148 ++-- .../startupHints/locales/en/css/dark.css | 8 - .../startupHints/locales/en/css/light.css | 8 - .../startupHints/locales/en/css/style.css | 36 - resources/startupHints/locales/en/error.html | 35 +- resources/startupHints/locales/fr/1.html | 127 ++- resources/startupHints/locales/fr/10.html | 133 ++- resources/startupHints/locales/fr/11.html | 123 ++- resources/startupHints/locales/fr/12.html | 125 ++- resources/startupHints/locales/fr/2.html | 162 ++-- resources/startupHints/locales/fr/3.html | 98 ++- resources/startupHints/locales/fr/4.html | 101 ++- resources/startupHints/locales/fr/5.html | 138 +++- resources/startupHints/locales/fr/6.html | 128 ++- resources/startupHints/locales/fr/7.html | 140 +++- resources/startupHints/locales/fr/8.html | 132 ++- resources/startupHints/locales/fr/9.html | 134 ++- .../startupHints/locales/fr/css/dark.css | 8 - .../startupHints/locales/fr/css/light.css | 8 - .../startupHints/locales/fr/css/style.css | 36 - resources/startupHints/locales/fr/error.html | 35 +- resources/startupHints/locales/hr/1.html | 117 ++- resources/startupHints/locales/hr/10.html | 144 ++-- resources/startupHints/locales/hr/11.html | 134 ++- resources/startupHints/locales/hr/12.html | 136 ++- resources/startupHints/locales/hr/2.html | 175 ++-- resources/startupHints/locales/hr/3.html | 109 ++- resources/startupHints/locales/hr/4.html | 116 ++- resources/startupHints/locales/hr/5.html | 149 +++- resources/startupHints/locales/hr/6.html | 139 +++- resources/startupHints/locales/hr/7.html | 151 ++-- resources/startupHints/locales/hr/8.html | 143 +++- resources/startupHints/locales/hr/9.html | 147 ++-- .../startupHints/locales/hr/css/dark.css | 8 - .../startupHints/locales/hr/css/light.css | 8 - .../startupHints/locales/hr/css/style.css | 36 - resources/startupHints/locales/hr/error.html | 34 +- resources/startupHints/locales/it/1.html | 117 ++- resources/startupHints/locales/it/10.html | 145 ++-- resources/startupHints/locales/it/11.html | 135 ++- resources/startupHints/locales/it/12.html | 137 ++- resources/startupHints/locales/it/2.html | 175 ++-- resources/startupHints/locales/it/3.html | 110 ++- resources/startupHints/locales/it/4.html | 117 ++- resources/startupHints/locales/it/5.html | 150 ++-- resources/startupHints/locales/it/6.html | 140 +++- resources/startupHints/locales/it/7.html | 152 ++-- resources/startupHints/locales/it/8.html | 144 +++- resources/startupHints/locales/it/9.html | 148 ++-- .../startupHints/locales/it/css/dark.css | 8 - .../startupHints/locales/it/css/light.css | 8 - .../startupHints/locales/it/css/style.css | 36 - resources/startupHints/locales/it/error.html | 34 +- 146 files changed, 7997 insertions(+), 4609 deletions(-) create mode 100644 resources/startupHints/assets/common/PicturesCategory.svg create mode 100644 resources/startupHints/assets/common/board.png create mode 100644 resources/startupHints/assets/common/favorites.png rename resources/startupHints/{images => assets/common}/left.png (100%) create mode 100644 resources/startupHints/assets/common/record.png rename resources/startupHints/{images => assets/common}/right.png (100%) delete mode 100644 resources/startupHints/assets/hint1/openboard-logo.png.bck rename resources/startupHints/assets/hint1/{openboard-logo.png => openboard-main-logo.png} (100%) rename resources/startupHints/assets/hint1/{menu.png => openboard-menu-icon.png} (100%) rename resources/startupHints/assets/hint10/{application-gif1.gif => built-in-applications-demo.gif} (100%) rename resources/startupHints/assets/hint11/{podcast-gif1.gif => video-capture-open-tool.gif} (100%) rename resources/startupHints/assets/hint11/{podcast-gif2.gif => video-capture-save-to-desktop.gif} (100%) rename resources/startupHints/assets/hint11/{podcast2.png => video-recorder-interface.png} (100%) create mode 100644 resources/startupHints/assets/hint12/favorites-add-document.png rename resources/startupHints/assets/hint12/{favorites2.png => favorites-library-view.png} (100%) delete mode 100644 resources/startupHints/assets/hint12/favorites.png rename resources/startupHints/assets/hint12/{favorites3.png => recent-documents-view.png} (100%) rename resources/startupHints/assets/hint2/{arrow.png => board-mode-arrow.png} (100%) rename resources/startupHints/assets/hint2/{bo-gif1.gif => board-mode-background-change.gif} (100%) rename resources/startupHints/assets/hint2/{bo1.png => board-mode-pen-palette.png} (100%) rename resources/startupHints/assets/hint2/{bo9.png => board-mode-toolbar.png} (100%) delete mode 100644 resources/startupHints/assets/hint3/bureau1.png.bck rename resources/startupHints/assets/hint3/{bureau-gif1.gif => desktop-mode-annotation.gif} (100%) rename resources/startupHints/assets/hint3/{bureau1.png => desktop-mode-icon.png} (100%) rename resources/startupHints/assets/hint3/{bureau-gif2.gif => desktop-mode-navigation.gif} (100%) rename resources/startupHints/assets/hint4/{gif-document1.gif => documents-folder-organization.gif} (100%) rename resources/startupHints/assets/hint4/{document1.png => documents-manager-view.png} (100%) rename resources/startupHints/assets/hint4/{gif-document2.gif => documents-page-actions.gif} (100%) rename resources/startupHints/assets/hint5/{gif2.gif => documents-export-files.gif} (100%) rename resources/startupHints/assets/hint5/{img1.png => documents-import-export-panel.png} (100%) rename resources/startupHints/assets/hint5/{gif1.gif => documents-import-files.gif} (100%) rename resources/startupHints/assets/hint6/{addToolToLibrary.png => add-tool-to-library-icon.png} (100%) rename resources/startupHints/assets/hint6/{app1.png => web-browser-integrated-view.png} (100%) rename resources/startupHints/assets/hint6/{app-gif2.gif => web-create-library-app.gif} (100%) rename resources/startupHints/assets/hint6/{app2.png => web-library-entry.png} (100%) rename resources/startupHints/assets/hint6/{app-gif1.gif => web-open-website.gif} (100%) rename resources/startupHints/assets/hint6/{app-gif3.gif => web-saved-in-library.gif} (100%) rename resources/startupHints/assets/hint7/{gif-capture1.gif => board-area-capture.gif} (100%) rename resources/startupHints/assets/hint7/{caputre2.png => board-capture-area-selection.png} (100%) rename resources/startupHints/assets/hint7/{caputre3.png => board-capture-result.png} (100%) rename resources/startupHints/assets/hint7/{capture1.png => board-capture-tool.png} (100%) rename resources/startupHints/assets/hint7/{capture-gif2.gif => desktop-area-capture.gif} (100%) rename resources/startupHints/assets/hint7/{capture4.png => desktop-capture-tool.png} (100%) create mode 100644 resources/startupHints/assets/hint8/documents-import-export-zone.png rename resources/startupHints/assets/hint8/{capture2.png => image-library-folder-view.png} (100%) rename resources/startupHints/assets/hint8/{capture1.png => image-library-open.png} (100%) rename resources/startupHints/assets/hint8/{image-gif1.gif => images-folder-organization.gif} (100%) rename resources/startupHints/assets/hint8/{image-gif3.gif => images-local-import.gif} (100%) rename resources/startupHints/assets/hint8/{image-gif2.gif => images-web-search-import.gif} (100%) rename resources/startupHints/assets/hint9/{cat-pict.png => categorize-pictures-widget.png} (100%) rename resources/startupHints/assets/hint9/{interactivite-gif2.gif => interactivity-add-images.gif} (100%) rename resources/startupHints/assets/hint9/{interactivite3.png => interactivity-category-editor.png} (100%) rename resources/startupHints/assets/hint9/{interactivite-gif3.gif => interactivity-run-exercise.gif} (100%) rename resources/startupHints/assets/hint9/{interactivite1.png => interactivity-widget-list.png} (100%) delete mode 100644 resources/startupHints/css/basic.css create mode 100644 resources/startupHints/css/dark.css create mode 100644 resources/startupHints/css/light.css create mode 100644 resources/startupHints/css/style.css create mode 100644 resources/startupHints/js/app.js delete mode 100644 resources/startupHints/js/jquery-1.6.2.min.js delete mode 100644 resources/startupHints/js/jquery-ui-1.8.9.custom.min.js create mode 100644 resources/startupHints/js/theme-loader.js delete mode 100644 resources/startupHints/locales/de/css/dark.css delete mode 100644 resources/startupHints/locales/de/css/light.css delete mode 100644 resources/startupHints/locales/de/css/style.css delete mode 100644 resources/startupHints/locales/en/css/dark.css delete mode 100644 resources/startupHints/locales/en/css/light.css delete mode 100644 resources/startupHints/locales/en/css/style.css delete mode 100644 resources/startupHints/locales/fr/css/dark.css delete mode 100644 resources/startupHints/locales/fr/css/light.css delete mode 100644 resources/startupHints/locales/fr/css/style.css delete mode 100644 resources/startupHints/locales/hr/css/dark.css delete mode 100644 resources/startupHints/locales/hr/css/light.css delete mode 100644 resources/startupHints/locales/hr/css/style.css delete mode 100644 resources/startupHints/locales/it/css/dark.css delete mode 100644 resources/startupHints/locales/it/css/light.css delete mode 100644 resources/startupHints/locales/it/css/style.css diff --git a/resources/startupHints/assets/common/PicturesCategory.svg b/resources/startupHints/assets/common/PicturesCategory.svg new file mode 100644 index 000000000..1132cadcb --- /dev/null +++ b/resources/startupHints/assets/common/PicturesCategory.svg @@ -0,0 +1,424 @@ + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/startupHints/assets/common/board.png b/resources/startupHints/assets/common/board.png new file mode 100644 index 0000000000000000000000000000000000000000..aca1a036ce6da6fd6b7de18238fa10639a0d7834 GIT binary patch literal 2105 zcmV-92*&q`P)KLZ*U+Jq*2Ca%FW*?*D}Wh8P4Wdr>%DDir|AVW`<_0v`W{0Jt~tjQERe$gHfcfsjC^mhjs^ zW7kJ$=6}uPkrB71b1%3;nBWtY#3f!hVA2h-y;_R zh(kM3_4u)5YlAr$_@mu^Gz$B_fG5}5?f-7H+fQ!7zFqi1dri~o?pXW`Nx$8lZ@XQ3 z9w##akcI1~Vfg?od=6j!2}izxSHFYO5G#RaPFU!R^_gOae>F{a33wB%TcIu$lHRNzSw*Ap2~Y$`T=L|Y zAjHt1ijR-RCyydPVepCAcxI-ilwwJq2LwF8;PWv}6cU%SP@xx z+|NtjSN0qBTlT!2wND`J_v|VAq&;hA?RV`$@5T}VKIc&wBFbn2E+F^(ziuwc+X6r) zuL5O!PrCV>ESW~t*DCeQy&(LO_CL6A4c~7mdd2_%03c&XQcVB=ZI}Q6bB+K2@=gE% zg&qI^ZjJx|v2k`nE zZ>Iqbz*@lmKXLy8b^=>930r`APjLyeRE0z$h7{tz$yQNNm02V)*iUwa-U3uj2(ivv zvH&p>!{_r+pELDH}L1Vemq_u`2}uHpXyqtfy_1-1dIJ;RFszzkH?AW z`i#OahQn%8B;7b0F~hZw4D|D1!>iN;>Zqz-$se5^ z9BMnj$(}PvsSuCrXi^BINR8seft1sPH@>-n6|0_S`N}nPcOId6`!+(S`*D{qWjLB- zM1UfMK+2iVym8YjEUa3=Q-O^HkG0aWV;emue?v8A;&Qoo)Rv7g-85PPIm7S`c>R?; z`|@j?X#bXPKG{wvc$|1f0Y&r6DJ?A}Gt-KyY1d0Is=!27yi1pi4D|DH!y5977ZKRl zz>&5V+P-L{>r@}v^Q)NSE~BKR1fS2xiQp-u5NJY(8EL-AKtDShR#WC4B>Kq1w0^yV zj(uMe>OM=};u<^^%kX$SIGs+cRx1EvEP!d=2Sb-Hu(M$`{^Bsz>+87C^&`8Qb-KEH z$zM`SVfiw=UN26k6SLWjs;Z<)e}e*2O7vKa&R}rt;02|nw}lU14)fX8m+*TBs9s-3 z^6x`*?7c*=>k9VA0^}7hVxG%|Ejt@kQAot&NRx?Ct|o-IXYaoe{`7_vysh~Xdyihh z>aW9ITyf%!O0K0Y%-gU@+W#wn#a!CWS!Ur4jAky&I9~ zC1ZXy=Y#chd^gCxV-YMBf!k(2u7DUFLpi3vovgmTK0=`oH8nMS+WZxf&LPYqf^E@r zcMKm_K#q=~7?b=)sV2%MgrKRZ35UbM@bGYIdgd%4$32g{d>3xFo7~*oNoAj?KxztP zN`YuJhN`Lr0)a_4?ccv2UDp{J8ltJG37gHvg0gZP4hJrmi=3Psj7H;>nX9TwG#X1O zAZ4ltk`j)e_?^d>E+G<$FfuYSNdT>c!xykvEcpF?Y&IJ?IXTRoI~S|fN?Kall;zVj z4U5IX;h&F^lw9utDZ?>6k^RGg!zhZ1uhfghV!3H^Z*MP(qEK5~i3ssn^brrb+WxOjPRI@iZ} j;B#QpgP+lZ0R9;O+1!5~zlGsC00000NkvXXu0mjf-Q?wt literal 0 HcmV?d00001 diff --git a/resources/startupHints/assets/common/eraserArrow.svg b/resources/startupHints/assets/common/eraserArrow.svg index 21e354551..e0a6354ab 100644 --- a/resources/startupHints/assets/common/eraserArrow.svg +++ b/resources/startupHints/assets/common/eraserArrow.svg @@ -1,199 +1,199 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/startupHints/assets/common/favorites.png b/resources/startupHints/assets/common/favorites.png new file mode 100644 index 0000000000000000000000000000000000000000..59637b880c814c41e6d667396504b7497e0f4159 GIT binary patch literal 1396 zcmV-)1&jKLP)>jgdjkm#W5j?3Be>8 z$6t5eyNAVl;~6KmB`1on^mLxyyZ8Km=l|}xGjIdL)(0N5^?}E3B!_<^i}7-=WOx6# z-W29~7uv?)9?A9fORlfqHU{^sI{+qlRjQAaq`Ies30_@S0NbcNBw=Mx27ZH7A3?&( zpl#G1S~mbp?ltM(U6!bZL^b60-DOPfwRHioje)Ha6t_tKufbVxEu{ZpBq(gLje)H< z9RSnwx@_E8k*Jmd*wlrMJ1dx;*KaC-tyf3HkA~&;UEo^Tl|kJ0AmT^Ewq6~%X#jZn zH{`Yl`Xn0c5^rTL3?R4ust+&!##&M?dl1=rH3Wu0?#9b)L(EoGha@QU%f_9c7E}RE zqdLGLx9&iuj^Ag;hQ35(9CaU)EF1?t35DdTj2`S$VDuC-ikU?mIHor#gG%Q>|=YN2OpIWr0r!}69(Rd!!ONe}h zi~ozW$Hg{k&tY;$Oy9jZ*)R&>1_+8sPyoLOCdh=k1l4824$UIc<;G$J5)1JR#4~6- z1FdPeatim;rwh1+LjqvOHXo9p_`KQjR7q~Rze~_{Y|exg1<9U^L+HSCyP+;ycU9Es zarErpn%bIvDcnDCL>9mM*ycmx_r74ZJXw?t_bwIesu;i}&*2TrpsqG)ph zJ@fZzjb~mA_fH%FSOmx*{v>|k1=)O{B$bh+mWu<^B`n!9Q6TA5?^+OFfn*kq=OJl9 z;?R~w&wSWaJM&_=|J2KioA8O(&LtQn6NEFb7mi^~y6083fh#8f9v7)W-(Byl> zu%vSFGmt>RGvImP3-}Iv#Z-FB7&ChP0Df*4J-r?}n_Aqiv|YKE2}=ah3sT5p4tzyQ zktexu*Qye$0>F03^`<+;(AjY9=xHiO9wbaBXbfUN6)ENcw%-Uq6+g^QKC-^gq5;%T zQ5qu~5NGjRK#q4Z!Q!r9r`noyVQ~|7D$@{u(>~hw$L!iRGqeK#$sb^`7LTD}R-8 zG;D@9m5Cygb;7%A13 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/startupHints/assets/common/penArrow.svg b/resources/startupHints/assets/common/penArrow.svg index 0ef25469b..27bc38296 100644 --- a/resources/startupHints/assets/common/penArrow.svg +++ b/resources/startupHints/assets/common/penArrow.svg @@ -1,286 +1,286 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/startupHints/assets/common/record.png b/resources/startupHints/assets/common/record.png new file mode 100644 index 0000000000000000000000000000000000000000..f9903256c1a2bd24cbc47359e7329afa3a592e74 GIT binary patch literal 1708 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 Q+W-In07*qoM6N<$f)N+t`2YX_ diff --git a/resources/startupHints/assets/hint1/openboard-logo.png b/resources/startupHints/assets/hint1/openboard-main-logo.png similarity index 100% rename from resources/startupHints/assets/hint1/openboard-logo.png rename to resources/startupHints/assets/hint1/openboard-main-logo.png diff --git a/resources/startupHints/assets/hint1/menu.png b/resources/startupHints/assets/hint1/openboard-menu-icon.png similarity index 100% rename from resources/startupHints/assets/hint1/menu.png rename to resources/startupHints/assets/hint1/openboard-menu-icon.png diff --git a/resources/startupHints/assets/hint10/application-gif1.gif b/resources/startupHints/assets/hint10/built-in-applications-demo.gif similarity index 100% rename from resources/startupHints/assets/hint10/application-gif1.gif rename to resources/startupHints/assets/hint10/built-in-applications-demo.gif diff --git a/resources/startupHints/assets/hint11/podcast-gif1.gif b/resources/startupHints/assets/hint11/video-capture-open-tool.gif similarity index 100% rename from resources/startupHints/assets/hint11/podcast-gif1.gif rename to resources/startupHints/assets/hint11/video-capture-open-tool.gif diff --git a/resources/startupHints/assets/hint11/podcast-gif2.gif b/resources/startupHints/assets/hint11/video-capture-save-to-desktop.gif similarity index 100% rename from resources/startupHints/assets/hint11/podcast-gif2.gif rename to resources/startupHints/assets/hint11/video-capture-save-to-desktop.gif diff --git a/resources/startupHints/assets/hint11/podcast2.png b/resources/startupHints/assets/hint11/video-recorder-interface.png similarity index 100% rename from resources/startupHints/assets/hint11/podcast2.png rename to resources/startupHints/assets/hint11/video-recorder-interface.png diff --git a/resources/startupHints/assets/hint12/favorites-add-document.png b/resources/startupHints/assets/hint12/favorites-add-document.png new file mode 100644 index 0000000000000000000000000000000000000000..fe65a67a3c2c55ba3543204026217b2dfd65b7e6 GIT binary patch literal 71160 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 literal 0 HcmV?d00001 diff --git a/resources/startupHints/assets/hint12/favorites2.png b/resources/startupHints/assets/hint12/favorites-library-view.png similarity index 100% rename from resources/startupHints/assets/hint12/favorites2.png rename to resources/startupHints/assets/hint12/favorites-library-view.png diff --git a/resources/startupHints/assets/hint12/favorites.png b/resources/startupHints/assets/hint12/favorites.png deleted file mode 100644 index 3a856ad8c09966a61d2f37f68a4e9d2085449b3a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66465 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

b!~aJUN6_q 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 - - - Introduce - - - - - - - -

-
- -
-
-
- -
-
- - + + + + + + Startuphints + + + + + +
+
+ +
+
+ +
+
+ + + + + diff --git a/resources/startupHints/js/app.js b/resources/startupHints/js/app.js new file mode 100644 index 000000000..2f305c491 --- /dev/null +++ b/resources/startupHints/js/app.js @@ -0,0 +1,445 @@ +"use strict"; + +/* + Startup hints runtime model: + 1) This host page controls navigation and title (index shell). + 2) Host theme CSS is applied here (light.css / dark.css). + 3) Each iframe page applies its own theme through theme-loader.js + using the ?theme=... query param. +*/ + +// ─── Config ────────────────────────────────────────────────────────────────── + +var CONFIG = { + language: "en", + localesRoot: "locales", + maxHints: 50 +}; + +var DEBUG = new URLSearchParams(window.location.search).get("debug") === "1"; + +function debugLog() { + if (!DEBUG) return; + var args = Array.prototype.slice.call(arguments); + args.unshift("[startupHints]"); + console.log.apply(console, args); +} + +var THEME_SYNC_RETRY_INTERVAL_MS = 100; +var THEME_SYNC_MAX_ATTEMPTS = 40; + +// ─── State ─────────────────────────────────────────────────────────────────── + +var state = { + currentIndex: 1, + fileCount: 0, + theme: "light" +}; + +// ─── DOM cache ─────────────────────────────────────────────────────────────── + +var dom = { + source: null, + left: null, + right: null, + titleSpan: null +}; + +function cacheDomElements() { + dom.source = document.getElementById("source"); + dom.left = document.getElementById("left"); + dom.right = document.getElementById("right"); + dom.titleSpan = document.querySelector("#title span"); +} + +// ─── URL builders ──────────────────────────────────────────────────────────── + +function buildHintFileUrl(index) { + return CONFIG.localesRoot + "/" + CONFIG.language + "/" + index + ".html"; +} + +function buildHintUrl(index) { + return buildHintFileUrl(index) + "?theme=" + encodeURIComponent(state.theme); +} + +function buildErrorUrl() { + return CONFIG.localesRoot + "/" + CONFIG.language + "/error.html" + + "?theme=" + encodeURIComponent(state.theme); +} + +// ─── Language detection ───────────────────────────────────────────────────── + +function normalizeLanguage(value) { + if (typeof value !== "string") return null; + var trimmed = value.trim(); + if (!trimmed) return null; + + // Accept forms like "de", "de-DE", "de_DE" and keep the base language. + var base = trimmed.split(/[-_]/)[0].toLowerCase(); + return /^[a-z]{2,3}$/.test(base) ? base : null; +} + +function detectLanguageFromUrl() { + var params = new URLSearchParams(window.location.search); + return normalizeLanguage(params.get("lang") || params.get("language")); +} + +function detectLanguageFromSankore() { + if (!window.sankore) return null; + + try { + if (typeof window.sankore.lang === "function") { + return normalizeLanguage(window.sankore.lang()); + } + + return normalizeLanguage(window.sankore.lang); + } catch (e) { + return null; + } +} + +function getCurrentLanguage() { + return detectLanguageFromUrl() + || detectLanguageFromSankore() + || normalizeLanguage(CONFIG.language) + || "en"; +} + +function localeExists(language) { + return requestText(CONFIG.localesRoot + "/" + language + "/1.html") + .then(function() { return true; }) + .catch(function() { return false; }); +} + +async function resolveLanguage(preferredLanguage) { + var candidates = [ + preferredLanguage, + normalizeLanguage(CONFIG.language), + "en" + ].filter(Boolean); + + var seen = Object.create(null); + for (var i = 0; i < candidates.length; i++) { + var candidate = candidates[i]; + if (seen[candidate]) continue; + seen[candidate] = true; + + if (await localeExists(candidate)) return candidate; + } + + return "en"; +} + +// ─── Theme detection ───────────────────────────────────────────────────────── + +function normalizeTheme(value) { + if (value === "dark" || value === "light") return value; + return null; +} + +function detectThemeFromUrl() { + var params = new URLSearchParams(window.location.search); + return normalizeTheme(params.get("theme")); +} + +function detectInitialHintFromUrl() { + var params = new URLSearchParams(window.location.search); + var raw = params.get("hint"); + if (!raw) return null; + + var index = parseInt(raw, 10); + if (!Number.isFinite(index) || index < 1) return null; + return index; +} + +function resolveInitialHintIndex(fileCount) { + var requested = detectInitialHintFromUrl(); + if (!requested) return 1; + if (requested > fileCount) return fileCount; + return requested; +} + +function detectThemeFromSankore() { + if (window.sankore && typeof window.sankore.isDarkMode !== "undefined") { + return window.sankore.isDarkMode ? "dark" : "light"; + } + return null; +} + +function resolveTheme() { + return detectThemeFromUrl() || detectThemeFromSankore() || state.theme || "light"; +} + +// ─── Theme application ─────────────────────────────────────────────────────── + +// Host-only theme stylesheet. +// The iframe theme is handled by theme-loader.js. + +function applyHostThemeStylesheet(theme) { + var safeTheme = normalizeTheme(theme) || "light"; + var themeUrl = new URL("css/" + safeTheme + ".css", window.location.href).href; + var linkId = "ob-theme-css"; + var link = document.getElementById(linkId); + + if (!link) { + link = document.createElement("link"); + link.id = linkId; + link.rel = "stylesheet"; + link.type = "text/css"; + document.head.appendChild(link); + } + + if (link.href !== themeUrl) link.href = themeUrl; +} + +function applyHostTheme(theme) { + var safeTheme = normalizeTheme(theme) || "light"; + document.documentElement.setAttribute("data-theme", safeTheme); + applyHostThemeStylesheet(safeTheme); +} + +// Reload the current iframe page with the updated ?theme value. +function refreshCurrentHintTheme() { + if (!dom.source || state.fileCount < 1) return; + dom.source.src = buildHintUrl(state.currentIndex); +} + +// Sync host + iframe when OpenBoard theme changes. +function bindThemeSync() { + function connectThemeBridge() { + if (!window.sankore + || !window.sankore.themeChanged + || typeof window.sankore.themeChanged.connect !== "function") { + return false; + } + + window.sankore.themeChanged.connect(function(isDark) { + state.theme = isDark ? "dark" : "light"; + applyHostTheme(state.theme); + // The iframe theme is applied by theme-loader.js via ?theme=... + refreshCurrentHintTheme(); + }); + + var current = detectThemeFromSankore(); + if (current && current !== state.theme) { + state.theme = current; + applyHostTheme(state.theme); + } + + return true; + } + + if (connectThemeBridge()) return; + + var attempts = 0; + var timer = setInterval(function() { + if (connectThemeBridge() || ++attempts >= THEME_SYNC_MAX_ATTEMPTS) { + clearInterval(timer); + } + }, THEME_SYNC_RETRY_INTERVAL_MS); +} + +// ─── Navigation ────────────────────────────────────────────────────────────── + +function loadCurrentHint() { + if (!dom.source) return; + state.theme = resolveTheme(); + applyHostTheme(state.theme); + dom.source.src = buildHintUrl(state.currentIndex); + debugLog("loadHint", { + index: state.currentIndex, + fileCount: state.fileCount, + language: CONFIG.language, + theme: state.theme, + src: dom.source.src + }); +} + +function goToNextHint() { + if (state.fileCount < 1) return; + state.currentIndex = state.currentIndex < state.fileCount + ? state.currentIndex + 1 + : 1; + loadCurrentHint(); +} + +function goToPreviousHint() { + if (state.fileCount < 1) return; + state.currentIndex = state.currentIndex > 1 + ? state.currentIndex - 1 + : state.fileCount; + loadCurrentHint(); +} + +function goToHint(index) { + if (state.fileCount < 1) return; + + var target = parseInt(index, 10); + if (!Number.isFinite(target)) return; + + if (target < 1) target = 1; + if (target > state.fileCount) target = state.fileCount; + + state.currentIndex = target; + loadCurrentHint(); +} + +function bindNavigationHandlers() { + if (dom.right) dom.right.addEventListener("click", goToNextHint); + if (dom.left) dom.left.addEventListener("click", goToPreviousHint); + + document.addEventListener("keydown", function(e) { + if (e.key === "ArrowRight") goToNextHint(); + if (e.key === "ArrowLeft") goToPreviousHint(); + }); +} + +// ─── Iframe handlers ───────────────────────────────────────────────────────── + +function bindFrameHandlers() { + if (!dom.source) return; + dom.source.addEventListener("load", setTitle); + dom.source.addEventListener("load", function() { + debugLog("iframeLoaded", { + index: state.currentIndex, + src: dom.source ? dom.source.src : null + }); + }); +} + +// ─── Hint detection ────────────────────────────────────────────────────────── + +// Probes files sequentially until the first missing page is found. +async function detectAvailableHints() { + while (state.fileCount < CONFIG.maxHints) { + try { + await requestText(buildHintFileUrl(state.fileCount + 1)); + state.fileCount++; + } catch (e) { + break; + } + } + + if (state.fileCount === CONFIG.maxHints) { + console.warn("Hint detection reached maxHints limit:", CONFIG.maxHints); + } +} + +// ─── HTTP helper ───────────────────────────────────────────────────────────── + +// Tries fetch first, falls back to XHR for file:// contexts (OpenBoard). +function requestText(url) { + return fetch(url, { method: "GET", cache: "no-store" }) + .then(function(response) { + if (!response.ok) throw new Error("HTTP " + response.status); + return response.text().then(function(text) { + if (isMissingFileResponse(text)) throw new Error("Missing file"); + return text; + }); + }) + .catch(function() { + return new Promise(function(resolve, reject) { + var xhr = new XMLHttpRequest(); + xhr.open("GET", url, true); + xhr.onreadystatechange = function() { + if (xhr.readyState !== 4) return; + var ok = xhr.status >= 200 && xhr.status < 300; + var hasBody = typeof xhr.responseText === "string" && xhr.responseText.length > 0; + var local = xhr.status === 0 && hasBody && !isMissingFileResponse(xhr.responseText); + if (ok || local) resolve(xhr.responseText); + else reject(new Error("HTTP " + xhr.status)); + }; + xhr.onerror = function() { reject(new Error("Network error")); }; + xhr.send(); + }); + }); +} + +function isMissingFileResponse(text) { + if (typeof text !== "string") return true; + return text.indexOf("ERR_FILE_NOT_FOUND") !== -1 + || text.indexOf("404 Not Found") !== -1; +} + +// ─── Title ─────────────────────────────────────────────────────────────────── + +// Called on iframe load to refresh the center label. +function setTitle() { + if (!dom.source || !dom.titleSpan) cacheDomElements(); + if (!dom.source || !dom.titleSpan) return; + + try { + var doc = dom.source.contentWindow.document; + var titleEl = doc.getElementsByTagName("title")[0]; + var pageTitle = titleEl ? titleEl.innerHTML : ""; + dom.titleSpan.textContent = state.currentIndex + "/" + state.fileCount + + (pageTitle ? " : " + pageTitle : ""); + } catch (e) { + dom.titleSpan.textContent = state.currentIndex + "/" + state.fileCount; + } +} + +// ─── Init ──────────────────────────────────────────────────────────────────── + +async function init() { + debugLog("init:start", { + search: window.location.search, + sankorePresent: !!window.sankore + }); + + cacheDomElements(); + bindFrameHandlers(); + + var requestedLanguage = getCurrentLanguage(); + CONFIG.language = await resolveLanguage(requestedLanguage); + debugLog("language:resolved", { + requested: requestedLanguage, + selected: CONFIG.language + }); + + state.theme = resolveTheme(); + applyHostTheme(state.theme); + bindThemeSync(); + debugLog("theme:resolved", { theme: state.theme }); + + await detectAvailableHints(); + debugLog("hints:detected", { fileCount: state.fileCount }); + + if (state.fileCount > 0) { + state.currentIndex = resolveInitialHintIndex(state.fileCount); + loadCurrentHint(); + } else if (dom.source) { + dom.source.src = buildErrorUrl(); + debugLog("hints:none", { errorSrc: dom.source.src }); + } + + bindNavigationHandlers(); + + window.startupHints = window.startupHints || {}; + window.startupHints.goToHint = goToHint; + + debugLog("init:done"); +} + +if (DEBUG) { + window.addEventListener("error", function(event) { + debugLog("window:error", { + message: event.message, + source: event.filename, + line: event.lineno, + column: event.colno + }); + }); + + window.addEventListener("unhandledrejection", function(event) { + debugLog("window:unhandledrejection", { + reason: event.reason && event.reason.message ? event.reason.message : String(event.reason) + }); + }); +} + +document.addEventListener("DOMContentLoaded", function() { + init().catch(function(error) { + console.error("[startupHints] init failed", error); + }); +}); \ No newline at end of file diff --git a/resources/startupHints/js/jquery-1.6.2.min.js b/resources/startupHints/js/jquery-1.6.2.min.js deleted file mode 100644 index e67db7472..000000000 --- a/resources/startupHints/js/jquery-1.6.2.min.js +++ /dev/null @@ -1,18 +0,0 @@ -/*! - * jQuery JavaScript Library v1.6.2 - * http://jquery.com/ - * - * Copyright 2011, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Thu Jun 30 14:16:56 2011 -0400 - */ -(function(a,b){function cv(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cs(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cr(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cq(){cn=b}function cp(){setTimeout(cq,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bx(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bm(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(be,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bl(a){f.nodeName(a,"input")?bk(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bk)}function bk(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bj(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bi(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bh(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function V(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function N(a,b){return(a&&a!=="*"?a+".":"")+b.replace(z,"`").replace(A,"&")}function M(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function K(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function E(){return!0}function D(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z])/ig,x=function(a,b){return b.toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!A){A=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||D.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0},m&&f.extend(p,{position:"absolute",left:-1e3,top:-1e3});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]||i[c]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=w:v&&c!=="className"&&(f.nodeName(a,"form")||u.test(c))&&(i=v)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}},value:{get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return f.prop(a,c)?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.attrHooks.title=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=/\.(.*)$/,y=/^(?:textarea|input|select)$/i,z=/\./g,A=/ /g,B=/[^\w\s.|`]/g,C=function(a){return a.replace(B,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=D;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=D);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),C).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i. -shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},J=function(c){var d=c.target,e,g;if(!!y.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=I(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:J,beforedeactivate:J,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&J.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&J.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",I(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in H)f.event.add(this,c+".specialChange",H[c]);return y.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return y.test(this.nodeName)}},H=f.event.special.change.filters,H.focus=H.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=T.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(V(c[0])||V(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=S.call(arguments);O.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!U[a]?f.unique(e):e,(this.length>1||Q.test(d))&&P.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var X=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,Z=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,$=/<([\w:]+)/,_=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};bf.optgroup=bf.option,bf.tbody=bf.tfoot=bf.colgroup=bf.caption=bf.thead,bf.th=bf.td,f.support.htmlSerialize||(bf._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(X,""):null;if(typeof a=="string"&&!bb.test(a)&&(f.support.leadingWhitespace||!Y.test(a))&&!bf[($.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Z,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j -)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bi(a,d),e=bj(a),g=bj(d);for(h=0;e[h];++h)bi(e[h],g[h])}if(b){bh(a,d);if(c){e=bj(a),g=bj(d);for(h=0;e[h];++h)bh(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!ba.test(k))k=b.createTextNode(k);else{k=k.replace(Z,"<$1>");var l=($.exec(k)||["",""])[1].toLowerCase(),m=bf[l]||bf._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=_.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Y.test(k)&&o.insertBefore(b.createTextNode(Y.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bo.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bn.test(g)?g.replace(bn,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bx(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(by=function(a,c){var d,e,g;c=c.replace(bp,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bz=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bq.test(d)&&br.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bx=by||bz,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bB=/%20/g,bC=/\[\]$/,bD=/\r?\n/g,bE=/#.*$/,bF=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bG=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bH=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bI=/^(?:GET|HEAD)$/,bJ=/^\/\//,bK=/\?/,bL=/)<[^<]*)*<\/script>/gi,bM=/^(?:select|textarea)/i,bN=/\s+/,bO=/([?&])_=[^&]*/,bP=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bQ=f.fn.load,bR={},bS={},bT,bU;try{bT=e.href}catch(bV){bT=c.createElement("a"),bT.href="",bT=bT.href}bU=bP.exec(bT.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bQ)return bQ.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bL,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bM.test(this.nodeName)||bG.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bD,"\r\n")}}):{name:b.name,value:c.replace(bD,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bT,isLocal:bH.test(bU[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bW(bR),ajaxTransport:bW(bS),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?bZ(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=b$(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bF.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bE,"").replace(bJ,bU[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bN),d.crossDomain==null&&(r=bP.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bU[1]&&r[2]==bU[2]&&(r[3]||(r[1]==="http:"?80:443))==(bU[3]||(bU[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bX(bR,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bI.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bK.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bO,"$1_="+x);d.url=y+(y===d.url?(bK.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bX(bS,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bB,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn,co=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cr("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cu.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cu.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cv(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cv(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/resources/startupHints/js/jquery-ui-1.8.9.custom.min.js b/resources/startupHints/js/jquery-ui-1.8.9.custom.min.js deleted file mode 100644 index 145ba1fef..000000000 --- a/resources/startupHints/js/jquery-ui-1.8.9.custom.min.js +++ /dev/null @@ -1,781 +0,0 @@ -/*! - * jQuery UI 1.8.9 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI - */ -(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.9",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106, -NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this, -"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position"); -if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f, -"border"+this+"Width",true))||0;if(m)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h, -d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");if("area"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}}); -c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a); -return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;a.target==this._mouseDownEvent.target&&c.data(a.target,this.widgetName+".preventClickEvent", -true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); -;/* - * jQuery UI Position 1.8.9 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Position - */ -(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY, -left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+= -k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-= -m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left= -d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+= -a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b), -g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery); -;/* - * jQuery UI Draggable 1.8.9 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Draggables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper== -"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b= -this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;return true},_mouseStart:function(a){var b=this.options;this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top- -this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions(); -d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);return true},_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis|| -this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b=false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&& -this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle||!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this== -a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone():this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&&a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]|| -0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0], -this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top- -(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment== -"parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[(a.containment=="document"?0:d(window).scrollLeft())-this.offset.relative.left-this.offset.parent.left,(a.containment=="document"?0:d(window).scrollTop())-this.offset.relative.top-this.offset.parent.top,(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"? -0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){var b=d(a.containment)[0];if(b){a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"), -10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}}else if(a.containment.constructor== -Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop(): -f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,g=a.pageY; -if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.leftthis.containment[2])e=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/ -b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.topthis.containment[3])?g:!(g-this.offset.click.topthis.containment[2])?e:!(e-this.offset.click.left').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")})}, -stop:function(){d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("opacity"))b._opacity=a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable");if(a.scrollParent[0]!= -document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){if(!c.axis||c.axis!="x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY=0;h--){var i=c.snapElements[h].left,k=i+c.snapElements[h].width,j=c.snapElements[h].top,l=j+c.snapElements[h].height;if(i-e=j&&f<=l||h>=j&&h<=l||fl)&&(e>= -i&&e<=k||g>=i&&g<=k||ek);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(), -top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle= -this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne", -nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor== -String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),k=0;k=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,k);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection(); -this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){e(this).removeClass("ui-resizable-autohide");b._handles.show()},function(){if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()}; -if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(), -d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"});this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset= -this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio: -this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis];if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize", -b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height; -f={width:c.size.width-(f?0:c.sizeDiff.width),height:c.size.height-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop", -b);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(l(b.left))this.position.left=b.left;if(l(b.top))this.position.top=b.top;if(l(b.height))this.size.height=b.height;if(l(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(d=="nw"){b.top= -a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,d=l(b.width)&&a.maxWidth&&a.maxWidthb.width,h=l(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height, -k=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&k)b.left=i-a.minWidth;if(d&&k)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+ -a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this, -arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable, -{version:"1.8.9"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize, -function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var k=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:k.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n= -(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(k.css("position"))){c._revertToRelativePosition=true;k.css({position:"absolute",top:"auto",left:"auto"})}k.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType?e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition= -false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a=e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left- -a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize", -b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top", -"Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset, -f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left= -a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+ -a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition,f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&& -e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative", -height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b=e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width= -d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},l=function(b){return!isNaN(parseInt(b,10))}})(jQuery); -;/* - * jQuery UI Selectable 1.8.9 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Selectables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,"selectable-item",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"), -selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e("
")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX, -c.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger("start",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!c.metaKey){b.$element.removeClass("ui-selected");b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting", -c,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){var g=!c.metaKey||!b.$element.hasClass("ui-selected");b.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger("selecting",c,{selecting:b.element}):f._trigger("unselecting",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d= -this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.righti||a.bottomb&&a.rightg&&a.bottom *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){this.containerCache={};this.element.addClass("ui-sortable"); -this.refresh();this.floating=this.items.length?/left|right/.test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a==="disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this, -arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&&!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem= -c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset, -{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment(); -if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start", -a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a);return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute"); -if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0],e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a, -c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset();c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]== -document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var b=this.containers.length- -1;b>=0;b--){this.containers[b]._trigger("deactivate",null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null}); -this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):d(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")},toArray:function(a){var b=this._getItemsAsjQuery(a&& -a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+jg&&b+la[this.floating?"width":"height"]?j:g0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith();if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h= -d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)}); -return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),b=0;b=0;f--)for(var g= -d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h=0;b--){var c=this.items[b],e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b=this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top= -e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f=d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0]; -if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder); -c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out",a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length=== -1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h-f)this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top< -this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.topthis.containment[2])?f:!(f-this.offset.click.left=0;e--)if(d.ui.contains(this.containers[e].element[0], -this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this,this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out", -g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop",a,this._uiHash());for(e=0;e li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"); -a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); -if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var h=d.closest(".ui-accordion-header");a.active=h.length?h:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion", -function(f){return a._keydown(f)}).next().attr("role","tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(f){a._clickHandler.call(a,f,this);f.preventDefault()})},_createIcons:function(){var a=this.options;if(a.icons){c("").addClass("ui-icon "+ -a.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabIndex"); -this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons(); -b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,h=this.headers.index(a.target),f=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:f=this.headers[(h+1)%d];break;case b.LEFT:case b.UP:f=this.headers[(h-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target); -a.preventDefault()}if(f){c(a.target).attr("tabIndex",-1);c(f).attr("tabIndex",0);f.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+ -c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options; -if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){var h=this.active;j=a.next();g=this.active.next();e={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):j,oldContent:g};var f=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(j,g,e,b,f);h.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header); -if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);a.next().addClass("ui-accordion-content-active")}}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var g=this.active.next(), -e={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:g},j=this.active=c([]);this._toggle(j,g,e)}},_toggle:function(a,b,d,h,f){var g=this,e=g.options;g.toShow=a;g.toHide=b;g.data=d;var j=function(){if(g)return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data);g.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&h?{toShow:c([]),toHide:b,complete:j,down:f,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:f,autoHeight:e.autoHeight|| -e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;h=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!h[k]&&!c.easing[k])k="slide";h[k]||(h[k]=function(l){this.slide(l,{easing:k,duration:i||700})});h[k](d)}else{if(e.collapsible&&h)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false", -tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");if(this.toHide.length)this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.9",animations:{slide:function(a,b){a= -c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),h=0,f={},g={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){g[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/);f[i]={value:j[1], -unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(g,{step:function(j,i){if(i.prop=="height")h=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=h*f[i.prop].value+f[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide",paddingTop:"hide", -paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery); -;/* - * jQuery UI Autocomplete 1.8.9 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Autocomplete - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.position.js - */ -(function(d){d.widget("ui.autocomplete",{options:{appendTo:"body",delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,f;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.attr("readonly"))){f=false;var e=d.ui.keyCode; -switch(c.keyCode){case e.PAGE_UP:a._move("previousPage",c);break;case e.PAGE_DOWN:a._move("nextPage",c);break;case e.UP:a._move("previous",c);c.preventDefault();break;case e.DOWN:a._move("next",c);c.preventDefault();break;case e.ENTER:case e.NUMPAD_ENTER:if(a.menu.active){f=true;c.preventDefault()}case e.TAB:if(!a.menu.active)return;a.menu.select(c);break;case e.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!=a.element.val()){a.selectedItem= -null;a.search(null,c)}},a.options.delay);break}}}).bind("keypress.autocomplete",function(c){if(f){f=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)};this.menu=d("
    ").addClass("ui-autocomplete").appendTo(d(this.options.appendTo|| -"body",b)[0]).mousedown(function(c){var e=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(g){g.target!==a.element[0]&&g.target!==e&&!d.ui.contains(e,g.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,e){e=e.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:e})&&/^key/.test(c.originalEvent.type)&&a.element.val(e.value)},selected:function(c,e){var g=e.item.data("item.autocomplete"), -h=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=h;setTimeout(function(){a.previous=h;a.selectedItem=g},1)}false!==a._trigger("select",c,{item:g})&&a.element.val(g.value);a.term=a.element.val();a.close(c);a.selectedItem=g},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup"); -this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&&b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,f;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,e){e(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source=== -"string"){f=this.options.source;this.source=function(c,e){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:f,data:c,dataType:"json",success:function(g,h,i){i===a.xhr&&e(g);a.xhr=null},error:function(g){g===a.xhr&&e([]);a.xhr=null}})}}else this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length").data("item.autocomplete",b).append(d("").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b); -else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},filter:function(a,b){var f=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return f.test(c.label||c.value||c)})}})})(jQuery); -(function(d){d.widget("ui.menu",{_create:function(){var a=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(b){if(d(b.target).closest(".ui-menu-item a").length){b.preventDefault();a.select(b)}});this.refresh()},refresh:function(){var a=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex", --1).mouseenter(function(b){a.activate(b,d(this).parent())}).mouseleave(function(){a.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var f=b.offset().top-this.element.offset().top,c=this.element.attr("scrollTop"),e=this.element.height();if(f<0)this.element.attr("scrollTop",c+f);else f>=e&&this.element.attr("scrollTop",c+f-e+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",a,{item:b})}, -deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id");this._trigger("blur");this.active=null}},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,f){if(this.active){a=this.active[a+"All"](".ui-menu-item").eq(0); -a.length?this.activate(f,a):this.activate(f,this.element.children(b))}else this.activate(f,this.element.children(b))},nextPage:function(a){if(this.hasScroll())if(!this.active||this.last())this.activate(a,this.element.children(".ui-menu-item:first"));else{var b=this.active.offset().top,f=this.element.height(),c=this.element.children(".ui-menu-item").filter(function(){var e=d(this).offset().top-b-f+d(this).height();return e<10&&e>-10});c.length||(c=this.element.children(".ui-menu-item:last"));this.activate(a, -c)}else this.activate(a,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(a){if(this.hasScroll())if(!this.active||this.first())this.activate(a,this.element.children(".ui-menu-item:last"));else{var b=this.active.offset().top,f=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-b+f-d(this).height();return c<10&&c>-10});result.length||(result=this.element.children(".ui-menu-item:first")); -this.activate(a,result)}else this.activate(a,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()").addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary;if(d.primary||d.secondary){b.addClass("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary"));d.primary&&b.prepend("");d.secondary&&b.append("");if(!this.options.text){b.addClass(e?"ui-button-icons-only":"ui-button-icon-only").removeClass("ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary"); -this.hasTitle||b.attr("title",c)}}else b.addClass("ui-button-text-only")}}});a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c);a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass("ui-corner-left").end().filter(":last").addClass("ui-corner-right").end().end()}, -destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");a.Widget.prototype.destroy.call(this)}})})(jQuery); -;/* - * jQuery UI Dialog 1.8.9 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Dialog - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.button.js - * jquery.ui.draggable.js - * jquery.ui.mouse.js - * jquery.ui.position.js - * jquery.ui.resizable.js - */ -(function(c,j){var k={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},l={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&& -c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||" ",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("
    ")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex", --1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("
    ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),h=c('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role", -"button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("").addClass("ui-dialog-title").attr("id",e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose= -b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");a.uiDialog.remove();a.originalTitle&& -a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!==b.uiDialog[0]){e=c(this).css("z-index"); -isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.attr("scrollTop"),scrollLeft:d.element.attr("scrollLeft")};c.ui.dialog.maxZ+=1;d.uiDialog.css("z-index",c.ui.dialog.maxZ); -d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target===f[0]&&e.shiftKey){g.focus(1);return false}}}); -c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("
    ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("
    ").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a,function(){return!(d=true)});if(d){c.each(a,function(f, -h){h=c.isFunction(h)?{click:h,text:f}:h;f=c('').attr(h,true).unbind("click").click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.fn.button&&f.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g= -d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition,originalSize:f.originalSize, -position:f.position,size:f.size}}a=a===j?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize",f,b(h))},stop:function(f, -h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "):[a[0],a[1]];if(b.length=== -1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f);if(g in k)e=true;if(g in -l)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"):e.removeClass("ui-dialog-disabled"); -break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a=this.options,b,d,e= -this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height-b,0));this.uiDialog.is(":data(resizable)")&& -this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.9",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(a){if(this.instances.length=== -0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(), -height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight); -b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a");if(!a.values)a.values=[this._valueMin(),this._valueMin()];if(a.values.length&&a.values.length!==2)a.values=[a.values[0],a.values[0]]}else this.range=d("
    ");this.range.appendTo(this.element).addClass("ui-slider-range");if(a.range==="min"||a.range==="max")this.range.addClass("ui-slider-range-"+a.range);this.range.addClass("ui-widget-header")}d(".ui-slider-handle",this.element).length===0&&d("").appendTo(this.element).addClass("ui-slider-handle"); -if(a.values&&a.values.length)for(;d(".ui-slider-handle",this.element).length").appendTo(this.element).addClass("ui-slider-handle");this.handles=d(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(c){c.preventDefault()}).hover(function(){a.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(a.disabled)d(this).blur(); -else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(c){d(this).data("index.ui-slider-handle",c)});this.handles.keydown(function(c){var e=true,f=d(this).data("index.ui-slider-handle"),h,g,i;if(!b.options.disabled){switch(c.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:e= -false;if(!b._keySliding){b._keySliding=true;d(this).addClass("ui-state-active");h=b._start(c,f);if(h===false)return}break}i=b.options.step;h=b.options.values&&b.options.values.length?(g=b.values(f)):(g=b.value());switch(c.keyCode){case d.ui.keyCode.HOME:g=b._valueMin();break;case d.ui.keyCode.END:g=b._valueMax();break;case d.ui.keyCode.PAGE_UP:g=b._trimAlignValue(h+(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:g=b._trimAlignValue(h-(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(h=== -b._valueMax())return;g=b._trimAlignValue(h+i);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(h===b._valueMin())return;g=b._trimAlignValue(h-i);break}b._slide(c,f,g);return e}}).keyup(function(c){var e=d(this).data("index.ui-slider-handle");if(b._keySliding){b._keySliding=false;b._stop(c,e);b._change(c,e);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider"); -this._mouseDestroy();return this},_mouseCapture:function(b){var a=this.options,c,e,f,h,g;if(a.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:b.pageX,y:b.pageY});e=this._valueMax()-this._valueMin()+1;h=this;this.handles.each(function(i){var j=Math.abs(c-h.values(i));if(e>j){e=j;f=d(this);g=i}});if(a.range===true&&this.values(1)===a.min){g+=1;f=d(this.handles[g])}if(this._start(b, -g)===false)return false;this._mouseSliding=true;h._handleIndex=g;f.addClass("ui-state-active").focus();a=f.offset();this._clickOffset=!d(b.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:b.pageX-a.left-f.width()/2,top:b.pageY-a.top-f.height()/2-(parseInt(f.css("borderTopWidth"),10)||0)-(parseInt(f.css("borderBottomWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(b,g,c);return this._animateOff=true},_mouseStart:function(){return true}, -_mouseDrag:function(b){var a=this._normValueFromMouse({x:b.pageX,y:b.pageY});this._slide(b,this._handleIndex,a);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(b){var a; -if(this.orientation==="horizontal"){a=this.elementSize.width;b=b.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{a=this.elementSize.height;b=b.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}a=b/a;if(a>1)a=1;if(a<0)a=0;if(this.orientation==="vertical")a=1-a;b=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+a*b)},_start:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value= -this.values(a);c.values=this.values()}return this._trigger("start",b,c)},_slide:function(b,a,c){var e;if(this.options.values&&this.options.values.length){e=this.values(a?0:1);if(this.options.values.length===2&&this.options.range===true&&(a===0&&c>e||a===1&&c1){this.options.values[b]=this._trimAlignValue(a);this._refreshValue();this._change(null,b)}if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;e=arguments[0];for(f=0;f=this._valueMax())return this._valueMax();var a=this.options.step>0?this.options.step:1,c=(b-this._valueMin())%a;alignValue=b-c;if(Math.abs(c)*2>=a)alignValue+=c>0?a:-a;return parseFloat(alignValue.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max}, -_refreshValue:function(){var b=this.options.range,a=this.options,c=this,e=!this._animateOff?a.animate:false,f,h={},g,i,j,l;if(this.options.values&&this.options.values.length)this.handles.each(function(k){f=(c.values(k)-c._valueMin())/(c._valueMax()-c._valueMin())*100;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";d(this).stop(1,1)[e?"animate":"css"](h,a.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(k===0)c.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},a.animate); -if(k===1)c.range[e?"animate":"css"]({width:f-g+"%"},{queue:false,duration:a.animate})}else{if(k===0)c.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},a.animate);if(k===1)c.range[e?"animate":"css"]({height:f-g+"%"},{queue:false,duration:a.animate})}g=f});else{i=this.value();j=this._valueMin();l=this._valueMax();f=l!==j?(i-j)/(l-j)*100:0;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";this.handle.stop(1,1)[e?"animate":"css"](h,a.animate);if(b==="min"&&this.orientation==="horizontal")this.range.stop(1, -1)[e?"animate":"css"]({width:f+"%"},a.animate);if(b==="max"&&this.orientation==="horizontal")this.range[e?"animate":"css"]({width:100-f+"%"},{queue:false,duration:a.animate});if(b==="min"&&this.orientation==="vertical")this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},a.animate);if(b==="max"&&this.orientation==="vertical")this.range[e?"animate":"css"]({height:100-f+"%"},{queue:false,duration:a.animate})}}});d.extend(d.ui.slider,{version:"1.8.9"})})(jQuery); -;/* - * jQuery UI Tabs 1.8.9 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Tabs - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"
    ",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"
  • #{label}
  • "},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&& -e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b= -d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]|| -(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"); -this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected= -this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active"); -if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")); -this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+ -g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal", -function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")}; -this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected= --1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier."; -d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e= -d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b, -e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]); -j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove(); -if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null, -this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this}, -load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c, -"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this}, -url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.9"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k')}function E(a,b){d.extend(a,b);for(var c in b)if(b[c]== -null||b[c]==G)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.9"}});var y=(new Date).getTime();d.extend(K.prototype,{markerClassName:"hasDatepicker",log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){E(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase(); -f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:d('
    ')}}, -_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&& -b.append.remove();if(c){b.append=d(''+c+"");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c=="focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('').addClass(this._triggerClass).html(f== -""?c:d("").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker():d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;gh){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a, -c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b), -true);this._updateDatepicker(b);this._updateAlternate(b);b.dpDiv.show()}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+=1;this._dialogInput=d('');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}E(a.settings,e||{}); -b=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass); -this._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup", -this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().removeClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs, -function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().addClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null: -f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true}, -_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!="input")a=d("input",a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);d.datepicker._curInst&&d.datepicker._curInst!=b&&d.datepicker._curInst.dpDiv.stop(true,true);var c=d.datepicker._get(b,"beforeShow");E(b.settings,c?c.apply(a,[a,b]):{});b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value="";if(!d.datepicker._pos){d.datepicker._pos= -d.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b);c=d.datepicker._checkOffset(b, -c,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){d.datepicker._datepickerShowing=true;var i=b.dpDiv.find("iframe.ui-datepicker-cover");if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.effects&& -d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this,c=d.datepicker._getBorders(a.dpDiv);a.dpDiv.empty().append(this._generateHTML(a));var e=a.dpDiv.find("iframe.ui-datepicker-cover");e.length&&e.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()});a.dpDiv.find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout", -function(){d(this).removeClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!=-1&&d(this).removeClass("ui-datepicker-prev-hover");this.className.indexOf("ui-datepicker-next")!=-1&&d(this).removeClass("ui-datepicker-next-hover")}).bind("mouseover",function(){if(!b._isDisabledDatepicker(a.inline?a.dpDiv.parent()[0]:a.input[0])){d(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");d(this).addClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!= --1&&d(this).addClass("ui-datepicker-prev-hover");this.className.indexOf("ui-datepicker-next")!=-1&&d(this).addClass("ui-datepicker-next-hover")}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();c=this._getNumberOfMonths(a);e=c[1];e>1?a.dpDiv.addClass("ui-datepicker-multi-"+e).css("width",17*e+"em"):a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");a.dpDiv[(c[0]!=1||c[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a, -"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input.focus();if(a.yearshtml){var f=a.yearshtml;setTimeout(function(){f===a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml);f=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]}, -_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(),h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e- -g):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b=this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1);)a=a[b?"previousSibling":"nextSibling"];a=d(a).offset();return[a.left,a.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b);this._curInst=null};d.effects&&d.effects[a]? -b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();if(a=this._get(b,"onClose"))a.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")}, -_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"): -0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e._selectingMonthYear= -false;e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_clickMonthYear:function(a){var b=this._getInst(d(a)[0]);b.input&&b._selectingMonthYear&&setTimeout(function(){b.input.focus()},0);b._selectingMonthYear=!b._selectingMonthYear},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay= -d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a);this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a); -else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b= -a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;e=typeof e!="string"?e:(new Date).getFullYear()%100+parseInt(e,10);for(var f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort, -g=(c?c.monthNames:null)||this._defaults.monthNames,j=c=-1,l=-1,u=-1,k=false,o=function(p){(p=z+1-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}w=this._daylightSavingAdjust(new Date(c,j-1,l));if(w.getFullYear()!=c||w.getMonth()+1!=j||w.getDate()!=l)throw"Invalid date";return w},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y", -RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames:null)||this._defaults.monthNames;var i=function(o){(o=k+112?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay= -a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(), -b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),j=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay?new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n= -this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&nn;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a));n=this._canAdjustMonth(a,-1,m,g)?''+n+"":f?"":''+n+"";var r=this._get(a,"nextText");r=!h?r:this.formatDate(r,this._daylightSavingAdjust(new Date(m,g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?''+r+"":f?"":''+r+"";j=this._get(a,"currentText");r=this._get(a,"gotoCurrent")&&a.currentDay?u:b;j=!h?j:this.formatDate(j,r,this._getFormatConfig(a));h=!a.inline?'":"";e=e?'
    '+(c?h:"")+(this._isInRange(a,r)?'":"")+(c?"":h)+"
    ":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;j=this._get(a,"showWeek");r=this._get(a,"dayNames");this._get(a,"dayNamesShort");var s=this._get(a,"dayNamesMin"),z= -this._get(a,"monthNames"),w=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),v=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var L=this._getDefaultDate(a),I="",C=0;C1)switch(D){case 0:x+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]- -1:x+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:x+=" ui-datepicker-group-middle";t="";break}x+='">'}x+='
    '+(/all|left/.test(t)&&C==0?c?f:n:"")+(/all|right/.test(t)&&C==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,k,o,C>0||D>0,z,w)+'
    ';var A=j?'":"";for(t=0;t<7;t++){var q= -(t+h)%7;A+="=5?' class="ui-datepicker-week-end"':"")+'>'+s[q]+""}x+=A+"";A=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay,A);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;A=l?6:Math.ceil((t+A)/7);q=this._daylightSavingAdjust(new Date(m,g,1-t));for(var O=0;O";var P=!j?"":'";for(t=0;t<7;t++){var F= -p?p.apply(a.input?a.input[0]:null,[q]):[true,""],B=q.getMonth()!=g,J=B&&!H||!F[0]||k&&qo;P+='";q.setDate(q.getDate()+1);q=this._daylightSavingAdjust(q)}x+= -P+""}g++;if(g>11){g=0;m++}x+="
    '+this._get(a,"weekHeader")+"
    '+this._get(a,"calculateWeek")(q)+""+(B&&!v?" ":J?''+q.getDate()+"":''+q.getDate()+"")+"
    "+(l?""+(i[0]>0&&D==i[1]-1?'
    ':""):"");M+=x}I+=M}I+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'':"");a._keyEvent=false;return I},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),k='
    ', -o="";if(h||!j)o+=''+i[b]+"";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='"}u||(k+=o+(h||!(j&& -l)?" ":""));a.yearshtml="";if(h||!l)k+=''+c+"";else{g=this._get(a,"yearRange").split(":");var r=(new Date).getFullYear();i=function(s){s=s.match(/c[+-].*/)?c+parseInt(s.substring(1),10):s.match(/[+-].*/)?r+parseInt(s,10):parseInt(s,10);return isNaN(s)?r:s};b=i(g[0]);g=Math.max(b,i(g[1]||""));b=e?Math.max(b,e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(a.yearshtml+='";if(d.browser.mozilla)k+='";else{k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,"yearSuffix");if(u)k+=(h||!(j&&l)?" ":"")+o;k+="
    ";return k},_adjustInstDate:function(a,b,c){var e= -a.drawYear+(c=="Y"?b:0),f=a.drawMonth+(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&ba?a:b},_notifyChange:function(a){var b=this._get(a, -"onChangeMonthYear");if(b)b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a); -c=this._daylightSavingAdjust(new Date(c,e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a, -"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker= -function(a){if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b)); -return this.each(function(){typeof a=="string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new K;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.9";window["DP_jQuery_"+y]=d})(jQuery); -;/* - * jQuery UI Progressbar 1.8.9 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Progressbar - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("
    ").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"); -this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100* -this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.9"})})(jQuery); -;/* - * jQuery UI Effects 1.8.9 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/ - */ -jQuery.effects||function(f,j){function n(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1], -16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return o.transparent;return o[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return n(b)}function p(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle, -a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function q(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d= -a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function m(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor", -"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=n(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var o={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0, -0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211, -211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},r=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b, -d){if(f.isFunction(b)){d=b;b=null}return this.queue("fx",function(){var e=f(this),g=e.attr("style")||" ",h=q(p.call(this)),l,v=e.attr("className");f.each(r,function(w,i){c[i]&&e[i+"Class"](c[i])});l=q(p.call(this));e.attr("className",v);e.animate(u(h,l),a,b,function(){f.each(r,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments)});h=f.queue(this);l=h.splice(h.length-1,1)[0]; -h.splice(1,0,l);f.dequeue(this)})};f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c, -a):f.effects.animateClass.apply(this,[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.9",save:function(c,a){for(var b=0;b").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent", -border:"none",margin:0,padding:0});c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c); -return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)});return d.call(this,b)},_show:f.fn.show,show:function(c){if(m(c))return this._show.apply(this,arguments); -else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(m(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(m(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c), -b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c, -a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c, -a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a== -e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+ -e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery); -;/* - * jQuery UI Effects Fade 1.8.9 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fade - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Fold 1.8.9 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fold - * - * Depends: - * jquery.effects.core.js - */ -(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","bottom","left","right"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1], -10)/100*f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery); -;/* - * jQuery UI Effects Highlight 1.8.9 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Highlight - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&& -this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Pulsate 1.8.9 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Pulsate - * - * Depends: - * jquery.effects.core.js - */ -(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments); -b.dequeue()})})}})(jQuery); -; \ No newline at end of file diff --git a/resources/startupHints/js/theme-loader.js b/resources/startupHints/js/theme-loader.js new file mode 100644 index 000000000..d2fe799cf --- /dev/null +++ b/resources/startupHints/js/theme-loader.js @@ -0,0 +1,14 @@ +// Inject theme stylesheet from URL param (?theme=dark|light) +(function () { + var params = new URLSearchParams(window.location.search); + var theme = params.get("theme"); + if (theme !== "dark" && theme !== "light") { + theme = "light"; + } + + var themeStylesheet = document.createElement("link"); + themeStylesheet.rel = "stylesheet"; + themeStylesheet.type = "text/css"; + themeStylesheet.href = "../../css/" + theme + ".css"; + document.head.appendChild(themeStylesheet); +})(); \ No newline at end of file diff --git a/resources/startupHints/locales/de/1.html b/resources/startupHints/locales/de/1.html index 0c89a4ed3..44735348e 100644 --- a/resources/startupHints/locales/de/1.html +++ b/resources/startupHints/locales/de/1.html @@ -1,32 +1,95 @@ - - + + - - Tipps und Tricks - - - - + + Willkommen + + + - -
    -

    Willkommen bei OpenBoard

    -
    -
    -
    -
    -

    Hier sind einige Tipps und Tricks, die Ihnen helfen sollen, sich mit OpenBoard vertraut zu machen.

    -

    OpenBoard ist ein interaktives Whiteboard, das von Lehrern für Lehrer entwickelt wurde. Es besteht aus vier Modi: dem Boardmodus, dem Desktopmodus, dem Dokumentenmodus und dem Internetmodus.

    -

    Beginnen wir mit dem ersten und wichtigsten: dem Boardmodus.

    -
    -
    - Sie können dieses Fenster jederzeit wieder über die Schaltfläche "Tipps und Tricks" im OpenBoard-Menü (the OpenBoard menu) öffnen. -
    + + +
    + + +

    + Hier sind einige Tipps und Tricks, die Ihnen helfen sollen, sich mit OpenBoard vertraut zu machen. +

    + +

    + OpenBoard ist ein interaktives Whiteboard, das von Lehrern für Lehrer entwickelt wurde. + Es bietet vier Modi ergänzend, um Ihre Verwendungsmöglichkeiten im Unterricht abzudecken. +

    + +
    +

    Die 4 Modi von OpenBoard

    + +
    + +
    +

    Beginnen wir mit dem ersten und wichtigsten: Tafelmodus.

    +
    + + +
    + +
    + +
    + + - diff --git a/resources/startupHints/locales/de/10.html b/resources/startupHints/locales/de/10.html index 7d1aa4fdb..69d41cbbd 100644 --- a/resources/startupHints/locales/de/10.html +++ b/resources/startupHints/locales/de/10.html @@ -1,50 +1,95 @@ - - - - - Applikationen - - - - - - - -
    -

    Applikationen

    -
    -
    -

    OpenBoard bietet verschiedene Apps und Werkzeuge. Sie können auf diese zugreifen, indem Sie auf in der OpenBoard-Bibliothek klicken

    -

    Standard-Apps

    -

    Hier finden Sie geometrische Werkzeuge, einen Taschenrechner, Google Map, einen QR-Code-Generator und vieles mehr! Kombinieren Sie sie, um anregende Lernerfahrungen zu schaffen!

    -
    -

    Erstellen Sie Apps

    -

    Wie im Abschnitt Internetmodus erläutert, können Sie eine App von einer Website aus erstellen, indem Sie den internen Browser verwenden oder eine URL mit Kopieren und Einfügen auf das Board einfügen.

    -

    Damit können Sie Ihren Unterricht mit leistungsstarken Online-Tools aufpeppen, die Sie direkt auf dem Board verwenden können! Hier sind einige Beispiele interessanter Apps (Ziehen Sie sie auf das Board, um sie zu testen!) :

    - - -

    ... und noch viel mehr!

    - - Benötigen Sie einen leistungsfähigeren Taschenrechner als den, der standardmäßig in OpenBoard enthalten ist? Denken Sie daran! Sie können Ihre eigenen Anwendungen erstellen! Ziehen Sie den folgenden Link per Drag & Drop auf Ihr Board: https://ti89-simulator.com/ -
    -
    - -
    - - - + + + + + Anwendungen + + + + + + + + + + +
    + +
    +

    Auf Apps zugreifen

    +

    + OpenBoard bietet verschiedene Apps und Tools. + Finden Sie sie in der Bibliothek, indem Sie auf klicken + Anwendungssymbol. +

    +
    + + +
    +

    Standard-Apps

    +

    + Sie finden geometrische Werkzeuge, einen Taschenrechner, Google Maps, einen QR-Code-Generator und vieles mehr. + Kombinieren Sie sie, um spannende Bildungserlebnisse zu schaffen! +

    + +
    + Beispiel für die Verwendung integrierter Anwendungen +
    Beispiel für die Verwendung der integrierten Anwendungen OpenBoard.
    +
    +
    + + +
    +

    Erstellen Sie Ihre eigenen Apps

    +

    + Wie im Abschnitt erläutert Webmodus, Sie können eine Anwendung von einer Site aus erstellen, + über den internen Browser oder durch Kopieren und Einfügen einer URL auf die Pinnwand. +

    +

    + Dadurch können Sie Ihre Kurse mit leistungsstarken Online-Tools erweitern, die direkt in OpenBoard verwendet werden können. + Hier sind einige interessante Beispiele (ziehen Sie die Links per Drag-and-Drop auf die Pinnwand, um sie zu testen): +

    + + + +

    ...und noch viel mehr!

    + + +
    +
    + +
    + +
    + + + + + diff --git a/resources/startupHints/locales/de/11.html b/resources/startupHints/locales/de/11.html index 0fc78d7d0..66516afae 100644 --- a/resources/startupHints/locales/de/11.html +++ b/resources/startupHints/locales/de/11.html @@ -1,45 +1,90 @@ - - - - - Videoaufnahme - - - - - - - -
    -

    Videoaufnahme

    -
    -
    -

    Nehmen Sie Ihren Kurs auf

    -

    OpenBoard bietet Ihnen die Möglichkeit, Audio- und Videoaufnahmen von Ihrem Unterricht zu machen.

    -

    Dies kann zum Beispiel nützlich sein, um zusätzliche Übungen oder eine Information über einen Videoclip zu teilen oder eine Unterrichtsstunde aufzuzeichnen, um sie mit abwesenden Schülern zu teilen.

    - - Im Boardmodus werden die Symbolleisten und Paletten nicht im Videoclip erscheinen, sodass Sie sich keine Gedanken darüber machen müssen! Dasselbe gilt für den internen Browser, wo nur die aktive Registerkarte erfasst wird. - -

    Sie können auf dieses Tool wie folgt zugreifen:

    -
    - -

    Sie werden folgende Schnittstelle in der rechten unteren Ecke des Boards sehen:

    -
    - -

    Klicken Sie auf die rote Schaltfläche, um die Aufnahme zu starten.

    - - Sie können die Einstellungen anpassen, indem Sie auf klicken. Dort finden Sie Audioeinstellungen (ein Mikrofon auswählen oder keines), Videoeinstellungen (Auflösung der Videoaufnahme) und konfigurierbare Veröffentlichungsoptionen. - -

    Sobald die Aufnahme beendet ist, wird sie gespeichert und ist auf dem Desktop Ihres Computers verfügbar.

    -
    - -
    -
    - -
    - - + + + + + Videoaufnahme + + + + + + + + + + +
    + +
    +

    Zeichnen Sie Ihren Kurs auf

    +

    + OpenBoard ermöglicht Ihnen das Speichern Audio- und die Video Ihres Kurses. + Ideal, um zusätzliche Übungen zu teilen, einen kurzen Erklärclip zu veröffentlichen oder + eine Lehrveranstaltung abwesenden Studierenden zur Verfügung stellen. +

    + + +
    + + +
    +

    Greifen Sie auf das Registrierungstool zu

    +

    Öffnen Sie das Snipping Tool wie unten gezeigt:

    + +
    + Öffnen des Videoaufnahmetools in OpenBoard +
    Schneller Zugriff auf das Registrierungstool über die OpenBoard-Schnittstelle.
    +
    +
    + + +
    +

    Steuerschnittstelle

    +

    Die Schnittstelle erscheint unten rechts in der Tabelle:

    + +
    + Recorder-Schnittstelle (Bedienelemente unten rechts) +
    + +

    Klicken Sie auf roter Knopf um mit der Aufnahme zu beginnen.

    + + +
    + + +
    +

    Beenden Sie das Video und stellen Sie es wieder her

    +

    + Sobald die Aufnahme abgeschlossen ist, wird das Video automatisch abgespielt auf dem Desktop gespeichert Ihres Computers. +

    + +
    + Beenden Sie die Aufnahme und speichern Sie das Video auf dem Desktop +
    Stoppen Sie die Aufnahme und die Videodatei ist auf dem Desktop verfügbar.
    +
    +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/de/12.html b/resources/startupHints/locales/de/12.html index b2973234d..a07b8c7fb 100644 --- a/resources/startupHints/locales/de/12.html +++ b/resources/startupHints/locales/de/12.html @@ -1,43 +1,94 @@ - - - - - Favoriten-Dokumente - - - - - - - -
    -

    Favoriten-Dokumente

    -
    -
    -

    OpenBoard-Dokumente zu Favoriten hinzufügen

    -

    Als neue Funktion in Version 1.7 können Sie OpenBoard-Dokumente zu Ihren Favoriten hinzufügen!

    -

    Gehen Sie dazu in den Dokumentenmodus, wählen Sie ein Dokument aus und klicken Sie auf in der Symbolleiste des Dokumentenmodus.

    - -
    - -

    Schnell von einem Dokument zum anderen wechseln

    -

    Ihre Lieblingsdokumente erscheinen in der OpenBoard-Bibliothek unter
    - Jedes dieser OpenBoard-Dokumente () kann dann per Drag & Drop auf das Board gezogen werden!

    -
    - - Sie können die Suchleiste am unteren Rand der OpenBoard Bibliothek verwenden, um ein Dokument anhand seines Namens zu finden - -

    Zuletzt geöffnete Dokumente

    -

    Jedes geöffnete Dokument wird vorübergehend zu den Favoriten hinzugefügt, sodass Sie während einer Sitzung schnell zwischen ihnen wechseln können, ohne sie explizit als Favoriten markieren zu müssen.

    -
    - Wenn Sie ein kürzlich geöffnetes Dokument dauerhaft zu den Favoriten hinzufügen möchten, können Sie dies über den Ordner Favoriten in der OpenBoard Bibliothek tun: Markieren Sie es und klicken Sie auf -
    -
    - -
    - - + + + + + Lieblingsdokumente + + + + + + + + + + +
    + +
    +

    Fügen Sie OpenBoard Dokumente zu Ihren Favoriten hinzu

    +

    + Eingeführt in die Version 1.7Mit dieser Funktion können Sie Ihre OpenBoard-Dokumente hinzufügen + in Favoriten. +

    +

    + Gehen Sie dazu zu Dokumentenmodus, wählen Sie ein Dokument aus und klicken Sie auf + Symbol „Zu Favoriten hinzufügen“. + in der Symbolleiste. +

    + +
    + Hinzufügen eines OpenBoard-Dokuments zu den Favoriten + +
    +
    + + +
    +

    Wechseln Sie schnell von einem Dokument zum anderen

    +

    + Ihre Lieblingsdokumente werden im angezeigt Bibliothek OpenBoard, unten + Favoriten-Symbol. +

    +

    + Jedes Lieblingsdokument + Dokumentsymbol OpenBoard + können per Drag & Drop direkt auf den Tisch gezogen werden. +

    + +
    + Favoriten in der Bibliothek OpenBoard anzeigen +
    + + + +
    + + +
    +

    Kürzlich geöffnete Dokumente

    +

    + Jedes geöffnete Dokument wird vorübergehend zu den Favoriten hinzugefügt, um schnell von einem zum anderen wechseln zu können + während derselben Sitzung, ohne sie explizit markieren zu müssen. +

    + +
    + Beispiel für kürzlich geöffnete Dokumente in OpenBoard + +
    + + +
    +
    + +
    +
    + + diff --git a/resources/startupHints/locales/de/2.html b/resources/startupHints/locales/de/2.html index 5bd485bcb..c0a566106 100644 --- a/resources/startupHints/locales/de/2.html +++ b/resources/startupHints/locales/de/2.html @@ -1,53 +1,122 @@ - - - - - Board-Modus - - - - - - - -
    -

    Board-Modus

    -
    -
    -

    Die Stiftpalette

    -

    Mit der Stiftpalette haben Sie Zugriff auf die wichtigsten Werkzeuge, wenn Sie an einem Whiteboard arbeiten.

    -
    - -

    Dort finden Sie den Bleistift (), den Radiergummi () und den Textmarker (). OpenBoard bietet außerdem Funktionen, die ein herkömmliches Whiteboard nicht bieten kann :

    -
      -
    •  ist der Selektor. Damit können Sie Objekte auswählen und mit ihnen interagieren.
    • -
    •  ist der magische Finger. Sie können Objekte bewegen oder mit ihnen interagieren, ohne dass Sie sie auswählen müssen.
    • -
    • ist die Hand. Damit können Sie die Seite bewegen. Sehr nützlich, wenn sie mit den Zoomfunktionen kombiniert wird!
    • -
    •  geben Ihnen die Möglichkeit, ein- und auszuzoomen. Wählen Sie einfach den gewünschten Effekt aus und klicken Sie auf die Stelle, auf die Sie ihn anwenden möchten!
    • -
    •  ist ein Laserpointer, der nützlich ist, um auf Elemente auf dem Board zu zeigen, ohne mit diesen zu interagieren.
    • -
    • wird zum einfachen Zeichnen von geraden Linien verwendet.
    • -
    •  ist eine Textbox, die es ermöglicht, mit der Tastatur statt mit einem Bleistift zu schreiben.
    • -
    - - Mit der Maus können Sie den Zoom feiner steuern! Verwenden Sie Strg/Befehl + Mausrad, um genauer hinein-/herauszuzoomen! - -

    Die Werkzeugleiste des Boards

    -

    Mit der Werkzeugleiste können Sie unter anderem die Farbe und Größe des Stifts und Markers ändern.

    -
    - -

    Dort finden Sie auch die Möglichkeit, den Hintergrund des Boards zu ändern, indem Sie auf klicken.

    -
    - -

    Außerdem finden Sie hier Funktionen wie Rückgängigmachen/Wiederherstellen, Erstellen und von Seite zu Seite Navigieren, Löschen des Boards, ...

    - - Sie können spezifischere Elemente des Boards vollständig löschen, indem Sie einen langen Klick auf the erase icon machen. Einige zusätzliche Funktionen erreichen Sie so auch für the new page icon ! -
    -
    - -
    - - + + + + + Tafelmodus + + + + + + + + +
    + +
    +

    Die Stiftpalette

    +

    + Mit der Stiftpalette haben Sie beim Arbeiten an einem Whiteboard Zugriff auf wichtige Werkzeuge. +

    + +
    + OpenBoard Stiftpalette +
    + +

    + Dort finden Sie den Bleistift + Bleistift, + das Zahnfleisch + Radiergummi + und der Textmarker + Textmarker. + OpenBoard bietet außerdem Funktionen, die ein herkömmliches Whiteboard nicht bieten kann: +

    + +
      +
    • + + Wähler : Objekte auswählen und mit ihnen interagieren. +
    • +
    • + + Magischer Finger : Bewegen/Interagieren ohne vorherige Auswahl. +
    • +
    • + + Hand : Seite verschieben (sehr nützlich in Kombination mit Zoom). +
    • +
    • + + + Zoomen / Verkleinern : Klicken Sie auf die Stelle, an der Sie den Effekt anwenden möchten, nachdem Sie ihn ausgewählt haben. +
    • +
    • + + Laserpointer : Zeigen Sie auf Elemente, ohne mit ihnen zu interagieren. +
    • +
    • + + Linie : Einfaches Zeichnen gerader Linien. +
    • +
    • + + Text : Fügen Sie ein Textfeld zum Tippen auf der Tastatur ein. +
    • +
    + + +
    + + +
    +

    Die Tischbar

    +

    + In der Tabellenleiste können Sie die ändern Farbe und/oder die Größe unter anderem Bleistift und Textmarker. +

    + +
    + OpenBoard Tabellenleiste +
    + +

    + Sie können auch die ändern Hintergrund der Tabelle indem Sie auf klicken + Ändern Sie den Hintergrund. +

    + +
    + Beispiel für die Änderung des Tabellenhintergrunds +
    + +

    + Weitere Funktionen stehen zur Verfügung: rückgängig machen/wiederholen, Seiten erstellen, zwischen Seiten navigieren, die Tabelle löschen usw. +

    + + +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/de/3.html b/resources/startupHints/locales/de/3.html index 43413d282..ba2604b29 100644 --- a/resources/startupHints/locales/de/3.html +++ b/resources/startupHints/locales/de/3.html @@ -1,36 +1,74 @@ - - - - - Desktop-Modus - - - - - - - -
    -

    Desktop-Modus

    -
    -
    -

    Mit anderen Apps interagieren

    -

    Wenn Sie den Desktop-Modus verwenden, können Sie mit Ihrem Betriebssystem und anderer Software interagieren, während OpenBoard darüber liegt !

    -

    Klicken Sie einfach auf das folgende Symbol :

    -
    -
    Verwenden Sie den Selektor (), um mit dem Desktop und anderen Anwendungen zu interagieren.
    -

    Apps oder Webseiten annotieren

    -
    Sie können jede Software mit Anmerkungen versehen, indem Sie den Bleistift () oder den Marker () verwenden.
    -
    - - Sie können auf weitere Optionen für the pen, the marker, und the eraser zugreifen, indem Sie sie mit einem langen Klick anklicken oder auf den kleinen schwarzen Pfeil klicken. -
    -
    - -
    - - + + + + + Desktop-Modus + + + + + + + + + +
    + +
    +

    Interagieren Sie mit anderen Apps

    +

    + Der Büromodus ermöglicht Ihnen die Interaktion mit Ihrem Betriebssystem und Ihrer Software, + unter Beibehaltung der OpenBoard-Tools oben. +

    +

    Klicken Sie einfach auf das folgende Symbol:

    + +
    + Symbol zum Aktivieren von Desktop-Modus +
    + +

    + Benutzen Sie die Wähler + Wähler + um mit dem Desktop und anderen Anwendungen zu interagieren. +

    +
    + + +
    +

    Kommentieren Sie Apps oder Websites

    +

    + Sie können jede Software mit Anmerkungen versehen Bleistift + Bleistift + oder die Marker + Marker. +

    + +
    + Kommentieren einer Anwendung in Desktop-Modus +
    Beispiel einer Anmerkung auf einer Webseite.
    +
    + + +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/de/4.html b/resources/startupHints/locales/de/4.html index 37d0e9b0c..20175b7a7 100644 --- a/resources/startupHints/locales/de/4.html +++ b/resources/startupHints/locales/de/4.html @@ -1,38 +1,79 @@ - - - - - Dokumenten-Modus - - - - - - - -
    -

    Dokumenten-Modus

    -
    -
    -

    OpenBoard bietet einen Dokumentenmanager. Sie können darauf zugreifen, indem Sie einfach auf klicken.

    -
    - -

    Legen Sie Ordner an und organisieren Sie Ihre Arbeit

    -

    Sie können einen Ordner erstellen, indem Sie auf "Neuer Ordner" klicken. Benennen Sie ihn und ziehen Sie Ihre Dokumente per Drag & Drop hinein. Auf die gleiche Weise können Sie einen ganzen Ordner in einen anderen verschieben.

    -
    - -

    Seitenverwaltung

    -

    Ein OpenBoard-Dokument kann mehrere Seiten enthalten. Über den Dokumentenmodus können Sie sie duplizieren, in den Papierkorb legen oder in ein anderes Dokument kopieren, neue Seiten aus einem Bildordner erstellen, ...

    -
    - - Beachten Sie, dass die verfügbaren Aktionen je nachdem, was ausgewählt wird, aktualisiert werden. -
    -
    - -
    - - + + + + + Dokumentenmodus + + + + + + + + + +
    + +
    +

    Greifen Sie auf den Dokumentenmanager zu

    +

    + OpenBoard bietet a Dokumentenmanager. Klicken Sie auf + Symbol „Dokumente“. + um es zu öffnen. +

    +
    + Ansicht des Dokumentenmanagers +
    +
    + + +
    +

    Erstellen Sie Ordner und organisieren Sie Ihre Arbeit

    +

    + Erstellen Sie einen Ordner über + Neuer Ordner, + Nennen Sie es dann Drag & Drop Ihre Dokumente darin. + Ebenso können Sie einen ganzen Ordner in einen anderen verschieben. +

    +
    + Dateien erstellen und organisieren +
    Beispiel für das Erstellen und Organisieren von Ordnern.
    +
    +
    + + +
    +

    Seitenverwaltung

    +

    + Ein OpenBoard-Dokument kann enthalten mehrere Seiten. Von Dokumentenmodus aus können Sie: +

    +
      +
    • Doppelte Seiten
    • +
    • Schicken Sie sie in den Papierkorb
    • +
    • Kopieren Sie sie in ein anderes Dokument
    • +
    • Erstellen Sie neue Seiten aus einem Bilderordner
    • +
    +
    + Beispiele für Aktionen auf Seiten +
    Beispiel für den Umgang mit Dokumenten.
    +
    + + +
    +
    + +
    +
    + + diff --git a/resources/startupHints/locales/de/5.html b/resources/startupHints/locales/de/5.html index 8210b0394..5a38dff97 100644 --- a/resources/startupHints/locales/de/5.html +++ b/resources/startupHints/locales/de/5.html @@ -1,45 +1,105 @@ - - - - - Dokumenten-Modus - - - - - - - -
    -

    Dokumenten-Modus

    -
    -
    -

    In diesem Modus finden Sie auch zwei sehr wichtige Funktionen: den Import und den Export.

    -
    - -

    Import

    -

    Sie können PDF-Dateien (.pdf), Bilder (.png, .jpg), OpenBoard-Dokumente (.ubz) oder OpenBoard-Ordner (.ubx) importieren, indem Sie anklicken.

    -
    -

    Beachten Sie, dass Sie auch ein OpenBoard-Dokument (.ubz) importieren können, indem Sie darauf doppelklicken. Dies startet OpenBoard, wenn es nicht bereits gestartet ist, und importiert es (oder schlägt vor, die Datei zu ersetzen, wenn sie bereits vorhanden ist).

    - Sie können auch mehrere Elemente auf einmal importieren, ohne dass Sie immer und immer wieder auf klicken müssen. -

    Export

    -

    Sie können ein OpenBoard-Dokument im PDF- oder UBZ-Format und einen OpenBoard-Ordner im UBX-Format exportieren. So können Sie zum Beispiel : -

      -
    • Die während einer Unterrichtsstunde geleistete Arbeit speichern und sie mit einem abwesenden Schüler teilen.
    • -
    • Es mit anderen Lehrern teilen oder auf einem USB-Stick speichern, um es auf einen anderen Computer zu importieren.
    • -
    • Die Arbeit eines Schülers im PDF-Format importieren, mit Anmerkungen versehen und das mit Anmerkungen versehene Dokument im PDF-Format exportieren, um es an den Schüler zurückzuschicken
    • -
    -

    -
    - - Exportieren Sie alle Ihre Dokumente, indem Sie auf den Stammordner "Meine Dokumente" klicken, bevor Sie auf klicken, um sie im UBX-Format zu exportieren. Sie können sie dann auf einem anderen Computer importieren. Dies ist auch eine gute Möglichkeit, ein Archiv oder eine Sicherungskopie Ihrer gesamten Arbeit zu erstellen! -
    -
    - -
    - - + + + + + + Import und Export + + + + + + + + + + +
    + +
    +

    Importieren und Exportieren

    +

    + In diesem Modus stehen Ihnen zwei wesentliche Funktionen zur Verfügung: Import Und Export. +

    +
    + Import- und Exportbereich in Dokumentenmodus + +
    +
    + + +
    +

    Inhalte importieren

    +

    + Sie können Dateien importieren PDF (.pdf), + des Bilder (.png, .jpg), + des Dokumente OpenBoard (.ubz) oder + OpenBoard Ordner (.ubx), indem Sie auf klicken + Symbol „Importieren“.. + +

    + +
    + Beispiel für den Import von Dateien in OpenBoard +
    Beispiel für den Import von Dateien in OpenBoard.
    +
    + +

    + Sie können auch ein OpenBoard-Dokument importieren (.ubz) In + doppelklicken darauf von Ihrem System. OpenBoard wird bei Bedarf gestartet und + bietet den Import an (oder ersetzt ihn, falls er bereits vorhanden ist). +

    + + +
    + + +
    +

    Exportieren Sie Ihre Dokumente

    +

    + Sie können eine exportieren Dokument OpenBoard im Format PDF Oder UBZ, + und a Ordner OpenBoard im Format UBX. Zum Beispiel : +

    +
      +
    • Zeichnen Sie die während einer Unterrichtsstunde geleistete Arbeit auf und teilen Sie sie mit einem abwesenden Schüler.
    • +
    • Teilen Sie es mit anderen Lehrern oder speichern Sie es auf einem USB-Stick, um es woanders zu importieren.
    • +
    • Importieren Sie die Arbeit eines Schülers als PDF, versehen Sie sie mit Anmerkungen und exportieren Sie dann die kommentierte PDF-Datei zum erneuten Senden.
    • +
    + +
    + Beispiele für den Export von Dokumenten und Ordnern OpenBoard +
    Beispiel für den Export von Dateien aus OpenBoard.
    +
    + + +
    +
    + +
    +
    + + + diff --git a/resources/startupHints/locales/de/6.html b/resources/startupHints/locales/de/6.html index ae3745e84..cc12d021f 100644 --- a/resources/startupHints/locales/de/6.html +++ b/resources/startupHints/locales/de/6.html @@ -1,44 +1,96 @@ - - - - - Internet-Modus - - - - - - - -
    -

    Internet-Modus

    -
    -
    - Der Internetmodus ist ein interner Browser, der einen traditionelleren Browser um einige sehr interessante Funktionen erweitert. -

    Verwendung des internen Browsers

    -

    Mithilfe des internen Browsers haben Sie die Möglichkeit, das Internet zu durchsuchen, ohne OpenBoard zu minimieren oder zu verlassen, mit zusätzlichen Funktionen, die es Ihnen ermöglichen, einen Teil oder den gesamten Bildschirm zu erfassen oder Apps von Websites zu erstellen und sie dem Board hinzuzufügen!

    - -
    - -

    Eine App erstellen

    -

    Sie können eine App von jeder beliebigen Website aus erstellen, um sie dem Board hinzuzufügen und mit ihr zu interagieren, genau wie mit den Standardanwendungen.

    -

    Gehen Sie dazu auf die Website, die Sie erfassen möchten, klicken Sie auf Capture Web Content und bestätigen Sie ihre Erstellung, indem Sie auf "Anwendung erstellen" klicken.

    -
    - -

    Wenn eine Anwendung erstellt wird, wird sie automatisch in der OpenBoard-Bibliothek gespeichert, sodass Sie sie in jedem beliebigen Dokument wiederverwenden können. Sie finden sie unter dem Ordner "Anwendungen" in einem Unterordner namens "Internet".

    - -
    - -

    Verwendung des externen Browsers

    -

    Sie können auch einen externen Browser verwenden, indem Sie die entsprechende Option in den Einstellungen ankreuzen. Wenn Sie auf klicken, wird Ihr bevorzugter Browser dann im Desktopmodus gestartet.

    - Wenn Sie einen externen Browser verwenden, können Sie immer noch eine App von einer Website aus erstellen, indem Sie die URL in der Adresszeile Ihres Browsers kopieren und sie dann einfügen, wenn Sie wieder im Boardmodus sind! -
    -
    - -
    - - + + + + + Webmodus + + + + + + + + + +
    + +
    +

    Der integrierte Browser

    +

    + DER Webmodus ist ein interner Browser von OpenBoard, der zu einem Browser hinzugefügt wird + klassische, sehr praktische Features für den Unterricht. +

    +

    + Es ermöglicht Ihnen, im Internet zu surfen, ohne OpenBoard zu verlassen, um Inhalte (teilweise oder teilweise) zu erfassen + Vollbild) und sogar Apps erstellen von Websites für + Wiederverwendung in Ihren Dokumenten. +

    + +
    + Beispiel für die Verwendung des integrierten Browsers von OpenBoard +
    +
    + + +
    +

    Erstellen Sie eine Anwendung von einer Site

    +

    + Von jeder Site aus können Sie eine erstellen Anwendung um es hinzuzufügen + auf dem Board und interagieren Sie damit wie mit den Standardanwendungen. +

    +

    + Gehen Sie zur gewünschten Seite und klicken Sie auf + Symbol „Zur Bibliothek hinzufügen“. + Anschließend durch Auswählen bestätigen Erstellen Sie eine App. +

    + +
    + Erstellen einer Webanwendung über den integrierten Browser +
    Erstellung einer Anwendung aus dem Webmodus.
    +
    + +

    + Nach der Erstellung wird die Anwendung automatisch im gespeichert + Bibliothek OpenBoard. Sie finden es weiter unten Anwendungen > Web + und kann es in jedem Dokument wiederverwenden. +

    + +
    + Anwendung in Bibliothek, Webordner gespeichert +
    Suchen Sie eine in Ihrer Bibliothek erstellte Anwendung.
    +
    +
    + + +
    + +

    + Sie können die Links in einem öffnen externer Browser durch Überprüfung + die entsprechende Option in den Einstellungen. Klicken Sie auf + Webmodus-Symbol + startet dann Ihren Lieblingsbrowser als Desktop-Modus. +

    + + +
    + +
    + +
    + +
    + + + diff --git a/resources/startupHints/locales/de/7.html b/resources/startupHints/locales/de/7.html index 77209db69..36b706a16 100644 --- a/resources/startupHints/locales/de/7.html +++ b/resources/startupHints/locales/de/7.html @@ -1,50 +1,102 @@ - - - - - Bildschirmaufnahme - - - - - - - -
    -

    Bildschirmaufnahme

    -
    -
    - Eine der grundlegenden, aber wirklich nützlichen Funktionen von OpenBoard ist der Screenshot. Damit können Sie während Ihres Unterrichts einen Schnappschuss von einem beliebigen Zustand des Boards erstellen. -

    Im Boardmodus

    -

    Suchen Sie the screen capture icon in der Stiftpalette, klicken Sie darauf und wählen Sie den Bereich aus, den Sie erfassen möchten. Anschließend werden Ihnen drei Optionen angeboten :

    -
      -
    • Zur aktuellen Seite hinzufügen
    • -
    • Zur neuen Seite hinzufügen
    • -
    • Zur Bibliothek hinzufügen (fügt den Schnappschuss dem Bilder Ordner hinzu, sodass Sie ihn jederzeit wiederverwenden können)
    • -
    - -

    Hier ein Beispiel für den gesamten Prozess :

    -
    - - Sie müssen sich keine Gedanken um die Stiftpalette, die Seitenvorschau oder die Registerkarte für die OpenBoard-Bibliothek machen - sie werden nicht von Ihrem Lasso eingefangen! - -

    Im Desktop-Modus

    -

    Dasselbe können Sie im Desktop-Modus tun, um Ihre Arbeit in anderen Programmen zu erfassen. Wechseln Sie in den Desktop-Modus, indem Sie auf klicken.

    -

    Sie finden zwei Symbole: um den gesamten Bildschirm zu erfassen, und um nur einen Teil davon zu erfassen. Wie im Boardmodus müssen Sie auswählen, wo Sie die Aufnahme hinzufügen möchten

    - -

    Hier eine Illustration des gesamten Prozesses :

    -
    - - -

    Im Internetmodus

    -

    In ähnlicher Weise ist dies auch im Internetmodus möglich, wo Sie eine Teilaufnahme des Bildschirms machen oder den aktiven Tab des Browsers erfassen können, indem Sie anklicken

    -
    -
    - -
    - - + + + + + Screenshot + + + + + + + + + +
    +
    +

    Eine einfache und sehr nützliche Funktion

    +

    + Mit dem Screenshot können Sie einen erstellen sofort der Zustand des Boards (oder Ihres Bildschirms) + während Ihres Kurses, um Inhalte zu archivieren, zu teilen oder wiederzuverwenden. +

    +
    + + +
    +

    Im Tafelmodus

    +

    + Klicken Sie in der Stiftpalette auf + Symbol für den Erfassungsbereich (Tafelmodus), + Wählen Sie dann den zu erfassenden Bereich aus. Sie können dann wählen: +

    +
      +
    • Zur aktuellen Seite hinzufügen
    • +
    • Zu neuer Seite hinzufügen
    • +
    • + Zur Bibliothek hinzufügen — Die Aufnahme wird im Ordner gespeichert Bilder + zur späteren Wiederverwendung. +
    • +
    + +
    + Beispiel für die Erfassung eines Bereichs in Tafelmodus +
    Beispiel für die Einbettung eines Screenshots in OpenBoard.
    +
    + + +
    + + +
    +

    In Desktop-Modus

    +

    + Wechseln Sie zu Desktop-Modus über + Desktop-Modus-Symbol + um andere Software zu erfassen. +

    +

    Es stehen zwei Optionen zur Verfügung:

    +
      +
    • + Symbol für Bildschirmaufnahme + Vollbildaufnahme +
    • +
    • + Symbol für den Erfassungsbereich + Erfassen eines Bereichs +
    • +
    +

    Wahlen Sie wie im Tafelmodus aus, wo die Aufnahme eingefugt werden soll.

    + +
    + Beispiel für die Erfassung in Desktop-Modus +
    Vollständiger oder teilweiser Screenshot in Desktop-Modus.
    +
    +
    + + +
    +

    In Webmodus

    +

    + In Webmodus können Sie einen Bereich erobern des Bildschirms bzw + Aktive Registerkarte erfassen aus dem Browser mit + Symbol für die Registerkarte „Aufnahme“.. +

    +
    +
    + +
    +
    + + + diff --git a/resources/startupHints/locales/de/8.html b/resources/startupHints/locales/de/8.html index 55f84e3de..b661833c5 100644 --- a/resources/startupHints/locales/de/8.html +++ b/resources/startupHints/locales/de/8.html @@ -1,42 +1,102 @@ - - - - - Bilder - - - - - - - -
    -

    Bilder

    -
    -
    - In OpenBoard können Sie auf Bilder auf verschiedene Arten zugreifen. -

    Organisieren Sie Ihren Bilder-Ordner

    -

    Screenshots, die der Bibliothek hinzugefügt wurden, finden Sie im Ordner Bilder :
    Sie können Unterordner erstellen, indem Sie ganz unten in der Bibliothek verwenden. Ziehen Sie dann Ihre Bilder per Drag & Drop in die verschiedenen Ordner, die Sie erstellt haben.

    -
    - - Egal, wo Sie sich in der OpenBoard-Bibliothek befinden, die Bilder, die Sie hinzufügen, werden automatisch innerhalb des Bilder-Ordners platziert , so dass die Bibliothek organisiert bleibt. - -

    Fügen Sie Bilder von Ihrem Computer hinzu

    -

    Sie können auch Bilder von Ihrem Computer hinzufügen, wie hier dargestellt :

    -
    - -

    Fügen Sie Bilder aus Suchmaschinen hinzu

    -

    Schließlich können Sie auch nach lizenzfreien Bildern suchen und diese zum Board hinzufügen, indem Sie die Suchmaschinen im Ordner "Websuche" verwenden:

    -
    - - Anstatt Drag-and-Drop zu verwenden, klicken Sie einfach auf ein Bild, das als Suchergebnis erscheint, um Details zu sehen und Optionen wie Zur Bibliothek hinzufügen zu finden. Nützlich bei der Vorbereitung einer Unterrichtsstunde! -
    -
    - -
    - - + + + + + Bilder + + + + + + + + + +
    +
    +

    Greifen Sie auf Ihre Bilder zu und organisieren Sie sie

    +

    + In OpenBoard können Sie von Ihrem aus auf verschiedene Arten auf Bilder zugreifen und diese hinzufügen Bibliothek. Letzteres befindet sich auf der rechten Seite des Bildschirms. Hier können Sie auch Sounds und Videos speichern und verschiedene Anwendungen finden. +

    +
    + Import- und Exportbereich in Dokumentenmodus +
    Bild der Bibliothek rechts in der Software.
    +
    +
    + + +
    +

    Organisieren Sie Ihren Bilderordner

    +

    + Zur Bibliothek hinzugefügte Screenshots werden im Ordner gruppiert + Symbolbilder. + Sie können erstellen Unterordner über + Neues Ordnersymbol + (unten in der Bibliothek) und ziehen Sie Ihre Bilder dann per Drag & Drop in die verschiedenen erstellten Ordner. +

    + +
    + Organisieren des Bilderordners mit Unterordnern +
    Beispiel für die Organisation und Klassifizierung von Bildern in der Bibliothek.
    +
    + + +
    + + +
    +

    Fügen Sie Bilder von Ihrem Computer hinzu

    +

    + Sie können Ihre eigenen Bilddateien direkt in OpenBoard importieren, wie unten gezeigt: +

    + +
    + Bilder vom Computer hinzufügen +
    Importieren eines lokalen Bildes in OpenBoard.
    +
    +
    + + +
    +

    Fügen Sie Bilder aus dem Internet hinzu

    +

    + Sie können auch nach suchen lizenzfreie Bilder über integrierte Suchmaschinen, + befindet sich im Ordner Websuche + Symbolbilder. +

    + +
    + Hinzufügen von Bildern aus einer integrierten Suchmaschine +
    Beispiel für das Suchen und Hinzufügen von Bildern aus dem Internet.
    +
    + + +
    +
    + +
    + +
    + + + diff --git a/resources/startupHints/locales/de/9.html b/resources/startupHints/locales/de/9.html index 25dc0b8a8..52138850f 100644 --- a/resources/startupHints/locales/de/9.html +++ b/resources/startupHints/locales/de/9.html @@ -1,49 +1,99 @@ - - - - - Interaktivitäten - - - - - - - -
    -

    Interaktivitäten

    -
    -
    - Für jüngere Schülerinnen und Schüler finden Sie eine Reihe von anpassbaren Anwendungen, die speziell auf diese Zielgruppe zugeschnitten sind. -

    Die interaktiven Übungen von OpenBoard

    -

    Mit diesen Interaktivitäten können Sie verschiedene Arten von Übungen erstellen. Dabei kann es sich um Kategorisierung, Kopfrechnen, Auswendiglernen usw. handeln.

    -

    Die Interaktivitäten befinden sich in der OpenBoard-Bibliothek: Klicken Sie auf , um sie zu finden.

    - -

    Beispiele

    -

    Wir werden eine Übung erstellen, die die Interaktivität "Categorize pictures" (übersetzt: Bilder kategorisieren) verwendet:

    - Probieren Sie es aus! Verschieben Sie dieses Fenster auf eine Seite und reproduzieren Sie das Beispiel auf der Pinnwand! -

    Zunächst ziehen Sie die Interaktivität per Drag & Drop auf das Board und klicken auf "Bearbeiten".

    -

    Ändern Sie dann die Namen der Kategorien nach Bedarf :

    -
    - - Sie können Kategorien mithilfe der Symbole + und - hinzufügen oder entfernen. - -

    Fügen Sie dann die entsprechenden Bilder zu jeder Kategorie hinzu.

    -
    - -

    Klicken Sie schließlich auf "Anzeigen", um das Ergebnis zu sehen und die Übung durchzuführen.

    -
    - - Sie können die Übung erneut starten, indem Sie auf das Symbol "Neu laden" klicken. - - -
    -
    - -
    - - + + + + + Interaktivitäten + + + + + + + + + + +
    + +
    +

    Interaktive Übungen, einfach zu personalisieren

    +

    + Für die jüngsten Schüler (und nicht nur) bietet OpenBoard ein Set + vonInteraktivitäten anpassbar: Kategorisierung, mentale Berechnung, Auswendiglernen usw. +

    +

    + Sie sind im zugänglich Bibliothek : klicken Sie auf + Interaktivitätssymbol. +

    +
    + + +
    +

    Beispiel: „Bilder kategorisieren“

    +

    + Lassen Sie uns eine Übung mit Interaktivität erstellen + Katzeegorisieren Bildures (Bilder kategorisieren): + Miniaturbilder kategorisieren. +

    + + + +

    1) Platzieren Sie die Interaktivität und öffnen Sie den Editor

    +

    + Ziehen Sie die Interaktivität per Drag-and-Drop auf das Board und klicken Sie dann Zu ändern. +

    + +

    2) Benennen Sie die Kategorien

    +

    + Benennen Sie die Kategorien nach Bedarf um. Das können Sie auch + hinzufügen Oder LÖSCHEN Kategorien mit den Symbolen „+“ und „−“. +

    + +
    + Bearbeiten von Interaktivitätskategorien +
    Kategorien bearbeiten: Hinzufügen, Löschen, Umbenennen.
    +
    + +

    3) Fügen Sie die Bilder hinzu

    +

    + Fügen Sie Bilder entsprechend jeder Kategorie hinzu (Drag & Drop, Auswahl aus der Bibliothek usw.). +

    + +
    + Bilder zu Kategorien hinzufügen +
    Verknüpfen Sie Bilder mit definierten Kategorien.
    +
    + +

    4) Zeigen Sie die Übung und machen Sie sie

    +

    + Klicken Sie auf Anzeige um die Aktivität im Studentenmodus zu starten. +

    + +
    + Durchführen der Übung „Bilder kategorisieren“. +
    Durchführung der Übung: Verschieben Sie die Bilder in die richtige Kategorie.
    +
    + + +
    +
    + +
    +
    + + diff --git a/resources/startupHints/locales/de/css/dark.css b/resources/startupHints/locales/de/css/dark.css deleted file mode 100644 index 34ded372a..000000000 --- a/resources/startupHints/locales/de/css/dark.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - background-color: #3a3a3a; - color: #e0e0e0; -} - -.title { - color: #8ba3d7; -} diff --git a/resources/startupHints/locales/de/css/light.css b/resources/startupHints/locales/de/css/light.css deleted file mode 100644 index 4e1f81f0e..000000000 --- a/resources/startupHints/locales/de/css/light.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - background-color: #edf2f7; - color: #1f2937; -} - -.title { - color: #5f7faa; -} diff --git a/resources/startupHints/locales/de/css/style.css b/resources/startupHints/locales/de/css/style.css deleted file mode 100644 index de0ecb4d5..000000000 --- a/resources/startupHints/locales/de/css/style.css +++ /dev/null @@ -1,36 +0,0 @@ -*{ - font-family: Arial, Helvetica, sans-serif; -} - -.title -{ - width:100%; - color: #6682b5; - text-align: center; -} - -.file-extension -{ - background: lightgrey; -} - -.image -{ - text-align:center; -} - -.image img -{ - max-width: 600px; -} - -.icon -{ - vertical-align: middle; -} - -.tip -{ - font-style: italic; - font-size: 0.8rem; -} diff --git a/resources/startupHints/locales/de/error.html b/resources/startupHints/locales/de/error.html index 262f89bd3..9d4d207f5 100644 --- a/resources/startupHints/locales/de/error.html +++ b/resources/startupHints/locales/de/error.html @@ -1,15 +1,20 @@ - - - - - Fehler - - - - - -

    Etwas ist schief gelaufen ... -Überprüfen Sie die Existenz Ihrer Tipps im Ordner -/resources/startupHints/ …

    - - + + + + + Fehler + + + + + +
    +

    Fehler beim Laden

    +

    + Etwas ist schief gelaufen. + Überprüfen Sie, ob im Ordner Tipps-Seiten vorhanden sind + /Resources/startupHints/. +

    +
    + + diff --git a/resources/startupHints/locales/en/1.html b/resources/startupHints/locales/en/1.html index 291a1b213..a2841f8c3 100644 --- a/resources/startupHints/locales/en/1.html +++ b/resources/startupHints/locales/en/1.html @@ -1,32 +1,95 @@ - - + + - - Hints and tips - - - - + + Welcome + + + - -
    -

    Welcome to OpenBoard

    -
    -
    -
    -
    -

    Here's some hints and tips in order to help you familiarize with OpenBoard.

    -

    OpenBoard is an interactive whiteboard designed by teachers, for teachers. It comes with 4 modes : Board Mode, Desktop Mode, Documents Mode and Web Mode.

    -

    Let's jump in the first, and most important one : the Board Mode.

    -
    -
    - You can reopen the "Hints and tips" dialog at any time, using the dedicated button on the OpenBoard menu (the OpenBoard menu) -
    + + +
    + + +

    + Here are some tips and tricks to help you get familiar with OpenBoard. +

    + +

    + OpenBoard is an interactive whiteboard designed by teachers, for teachers. + It offers four complementary modes for classroom use. +

    + +
    +

    The 4 modes of OpenBoard

    + +
    + +
    +

    Let's start with the first, and most important: Board Mode.

    +
    + + +
    + +
    + +
    + + - diff --git a/resources/startupHints/locales/en/10.html b/resources/startupHints/locales/en/10.html index 9875372cd..16159f7d6 100644 --- a/resources/startupHints/locales/en/10.html +++ b/resources/startupHints/locales/en/10.html @@ -1,50 +1,95 @@ - - - - - Applications - - - - - - - -
    -

    Applications

    -
    -
    -

    OpenBoard comes with several applications and tools. You can access them by clicking on on the OpenBoard Library

    -

    Default applications

    -

    You'll find geometric tools, a calculator, Google Map, a QR code generator and more ! Combine them to create stimulating lessons !

    -
    -

    Create applications

    -

    Like explained in the Web Mode section, you can create applications from sites, using the internal navigator, or by copy-pasting urls to the Board.

    -

    This way, you can support your lessons with powerful online tools directly on the Board ! Here's some examples of interesting apps to create (Drag and drop them to the Board to test them !) :

    - - -

    ... and much more !

    - - You need a more powerful calculator than the one provided by OpenBoard ? Remember ! You can create your own applications ! Simply drag and drop the following link on the Board : https://ti89-simulator.com/ -
    -
    - -
    - - - + + + + + Applications + + + + + + + + + + +
    + +
    +

    Access apps

    +

    + OpenBoard offers different apps and tools. + Find them in the library by clicking on + Applications icon. +

    +
    + + +
    +

    Default apps

    +

    + You will find geometric tools, a calculator, Google Maps, a QR code generator and much more. + Combine them to create engaging educational experiences! +

    + +
    + Example of using integrated applications +
    Example of using OpenBoard built-in applications.
    +
    +
    + + +
    +

    Create your own apps

    +

    + As explained in section Web Mode, you can create an application from a site, + using the internal browser or by copying and pasting a URL onto the board. +

    +

    + This allows you to enhance your courses with powerful online tools, which can be used directly in OpenBoard. + Here are some interesting examples (drag and drop the links onto the board to test them): +

    + + + +

    ...and much more!

    + + +
    +
    + +
    + +
    + + + + + diff --git a/resources/startupHints/locales/en/11.html b/resources/startupHints/locales/en/11.html index 4dd8746de..ad4627a64 100644 --- a/resources/startupHints/locales/en/11.html +++ b/resources/startupHints/locales/en/11.html @@ -1,46 +1,90 @@ - - - - - Video Capture - - - - - - - -
    -

    Video Capture

    -
    -
    -

    Record your class session

    -

    OpenBoard gives you the ability to make an audio and video capture of your class session.

    -

    This, for example, can be helpful to share additional exercises or information via a video clip, or to record a class session in order to share it with missing students.

    - - In Board mode, the toolbars and palettes won't appear in the video clip, so don't worry about them ! Same in Web Mode, where only the current tab will appear on the capture. - -

    You can open this tool like this :

    -
    - -

    You'll see the following interface appear at the bottom right of the whiteboard :

    -
    - -

    Click on the red button to start recording.

    - - You can adjust settings by clicking on . You'll find audio settings (select a microphone, or none), video settings (resolution of the video capture) and configurable publishing options - -

    Once the capture is done, it will be automatically saved to the computer's desktop

    -
    - -
    -
    - -
    - - - + + + + + Video Capture + + + + + + + + + + +
    + +
    +

    Record your course

    +

    + OpenBoard allows you to save audio and the video of your course. + Ideal for sharing additional exercises, publishing a short explanatory clip or + make a course available to absent students. +

    + + +
    + + +
    +

    Access the registration tool

    +

    Open the Snipping Tool as shown below:

    + +
    + Opening the Video Capture tool in OpenBoard +
    Quick access to the registration tool from the OpenBoard interface.
    +
    +
    + + +
    +

    Control interface

    +

    The interface appears at the bottom right of the Table:

    + +
    + Recorder interface (bottom right controls) +
    + +

    Click on the red button to start recording.

    + + +
    + + +
    +

    Finish and recover the video

    +

    + Once recording is completed, the video is automatically saved to desktop of your computer. +

    + +
    + End recording and save the video to the Desktop +
    Stop recording and video file available on Desktop.
    +
    +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/en/12.html b/resources/startupHints/locales/en/12.html index 831c78a02..53b93fece 100644 --- a/resources/startupHints/locales/en/12.html +++ b/resources/startupHints/locales/en/12.html @@ -1,43 +1,94 @@ - - - - - Favorite Documents - - - - - - - -
    -

    Favorite Documents

    -
    -
    -

    Add OpenBoard documents to favorites

    -

    Coming with OpenBoard 1.7, you can add OpenBoard documents to your favorites !

    -

    To do so, go to Documents Mode, select a document and click on in the Documents toolbar.

    - -
    - -

    Quickly switch between documents

    -

    Your favorite documents will appear in the OpenBoard Library, under
    - Each OpenBoard document () can then be dragged and dropped to the Board !

    -
    - - You can use the search bar at the bottom of the OpenBoard Library to quickly find a document by its name - -

    Recently open documents

    -

    Every document you open is temporary added to the favorites so you can switch between each one of them during a session, without the need for them to be explicitely marked as favorites.

    -
    - If you want to permanently add a recently open document in your favorites, you can do so via the OpenBoard Library : select it and click on -
    -
    - -
    - - + + + + + Favorite documents + + + + + + + + + + +
    + +
    +

    Add OpenBoard documents to favorites

    +

    + Introduced into the version 1.7, this functionality allows you to add your OpenBoard documents + in favorites. +

    +

    + To do this, go to Documents Mode, select a document and click + Add to Favorites icon + in the toolbar. +

    + +
    + Adding a OpenBoard document to favorites + +
    +
    + + +
    +

    Quickly move from one document to another

    +

    + Your favorite documents appear in the library OpenBoard, below + Favorites Icon. +

    +

    + Each favorite document + Document Icon OpenBoard + can be dragged and dropped directly onto the Table. +

    + +
    + Viewing Favorites in Library OpenBoard +
    + + + +
    + + +
    +

    Recently opened documents

    +

    + Each open document is temporarily added to favorites, to quickly switch from one to another + during the same session, without having to explicitly mark them. +

    + +
    + Example of recently opened documents in OpenBoard + +
    + + +
    +
    + +
    +
    + + diff --git a/resources/startupHints/locales/en/2.html b/resources/startupHints/locales/en/2.html index c701e461c..b3deb104f 100644 --- a/resources/startupHints/locales/en/2.html +++ b/resources/startupHints/locales/en/2.html @@ -1,53 +1,122 @@ - - - - - Board Mode - - - - - - - -
    -

    Board Mode

    -
    -
    -

    The Stylus palette

    -

    The Stylus palette gives you access to essential tools when working on a whiteboard.

    -
    - -

    Here you'll find the pen (), the eraser () and the marker (). OpenBoard also provides other features a classical whiterboard can't provide :

    -
      -
    • is the selector. With it, you can select objects and interact with them.
    • -
    • is the magic finger. You can move objects or interact with them without the need for them to be selected.
    • -
    • is the hand. You can move through the page with it. Very useful when combined with the zoom features !
    • -
    • give you the possibility to zoom in and out. Just select the one you want and click on the page, where you want to apply the zoom !
    • -
    • is a laser pointer, useful to point out elements on board without interacting with them.
    • -
    • is used to draw straight lines easily.
    • -
    • is a textbox tool, to write text using the keyboard instead of the pen.
    • -
    - - You can have a finer control of the zoom with the mouse ! Use Ctrl/Cmd + the mouse wheel to zoom in/out more precisely ! - -

    The Board toolbar

    -

    The Board toolbar gives you the possibility to change pen's or marker's color and size, among other things.

    -
    - -

    You'll also find the ability to change the board's background, by clicking on

    -
    - -

    You'll also find buttons to undo/redo actions, create and navigate through pages, clear the entire whiteboard, ...

    - - You can clear more precise parts of the board, by long clicking on the erase icon. Some hidden features on the erase icon too ! -
    -
    - -
    - - + + + + + Board Mode + + + + + + + + +
    + +
    +

    The stylus palette

    +

    + The stylus palette gives you access to essential tools when working on a whiteboard. +

    + +
    + OpenBoard stylus palette +
    + +

    + There you will find the pencil + Pencil, + the ereaser + Eraser + and the highlighter + Highlighter. + OpenBoard also provides features that a traditional whiteboard cannot: +

    + +
      +
    • + + Selector : select and interact with objects. +
    • +
    • + + Magic Finger : move/interact without selecting first. +
    • +
    • + + Hand : move the page (very useful combined with zoom). +
    • +
    • + + + Zoom / Zoom out : Click where to apply the effect after selecting it. +
    • +
    • + + Laser pointer : point at elements without interacting with them. +
    • +
    • + + Line : draw straight lines easily. +
    • +
    • + + Text : insert a text box for typing on the keyboard. +
    • +
    + + +
    + + +
    +

    The table bar

    +

    + The table bar allows you to change the color and/or the size pencil and highlighter, among other things. +

    + +
    + OpenBoard table bar +
    + +

    + You can also change the background of the table by clicking on + Change the background. +

    + +
    + Example of changing table background +
    + +

    + Other functions are available: undo/redo, create pages, navigate between pages, clear the table, etc. +

    + + +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/en/3.html b/resources/startupHints/locales/en/3.html index 47e9e3672..889ebe1af 100644 --- a/resources/startupHints/locales/en/3.html +++ b/resources/startupHints/locales/en/3.html @@ -1,36 +1,74 @@ - - - - - Desktop Mode - - - - - - - -
    -

    Desktop Mode

    -
    -
    -

    Interacting with other softwares

    -

    Using Desktop mode, you can interact with your entire computer and other softwares, while keeping OpenBoard as an overlay !

    -

    Just click on the following icon :

    -
    -
    Use the selector () to interact with the desktop and other softwares.
    -

    Make annotations on top of an application or a website

    -
    You can add annotations on top of any software, using the pen () or the marker ().
    -
    - - You can access to more options for the pen, the marker and the eraser by doing a long click on them, or by clicking on the small black arrow. -
    -
    - -
    - - + + + + + Desktop Mode + + + + + + + + + +
    + +
    +

    Interact with other apps

    +

    + The Office mode allows you to interact with your operating system and software, + while retaining the OpenBoard tools on top. +

    +

    Simply click on the following icon:

    + +
    + Icon to activate Desktop Mode +
    + +

    + Use the selector + Selector + to interact with the desktop and other applications. +

    +
    + + +
    +

    Annotate apps or websites

    +

    + You can annotate any software with the pencil + Pencil + or the marker + Marker. +

    + +
    + Annotating an application in Desktop Mode +
    Example of annotation on a web page.
    +
    + + +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/en/4.html b/resources/startupHints/locales/en/4.html index f7fc4a577..36cb2bd5c 100644 --- a/resources/startupHints/locales/en/4.html +++ b/resources/startupHints/locales/en/4.html @@ -1,38 +1,79 @@ - - - - - Documents Mode - - - - - - - -
    -

    Documents Mode

    -
    -
    -

    OpenBoard comes with a documents handler. You can access it by simply clicking on

    -
    - -

    Create folders and organize your work

    -

    You can create a folder by clicking on the "New Folder" icon. Name it, and drag and drop your documents in. The same way, you can move an entire folder in another one.

    -
    - -

    Handle pages

    -

    An OpenBoard document can contain multiple pages. You can duplicate them, move them to trash or to another document, create new ones from folders of images, ...

    -
    - - Note that available actions are updated according to what is selected -
    -
    - -
    - - + + + + + Documents Mode + + + + + + + + + +
    + +
    +

    Access the document manager

    +

    + OpenBoard offers a document manager. Click on + Documents icon + to open it. +

    +
    + Document manager view +
    +
    + + +
    +

    Create folders and organize your work

    +

    + Create a folder via + New folder, + name it, then drag and drop your documents inside. + Likewise, you can move an entire folder to another. +

    +
    + Creating and organizing files +
    Example of creating and organizing folders.
    +
    +
    + + +
    +

    Page management

    +

    + A OpenBoard document can contain several pages. From Documents Mode, you can: +

    +
      +
    • Duplicate pages
    • +
    • Send them to the trash
    • +
    • Copy them to another document
    • +
    • Create new pages from an images folder
    • +
    +
    + Examples of actions on pages +
    Example of document handling.
    +
    + + +
    +
    + +
    +
    + + diff --git a/resources/startupHints/locales/en/5.html b/resources/startupHints/locales/en/5.html index 9c4335bfd..c4b08ad5a 100644 --- a/resources/startupHints/locales/en/5.html +++ b/resources/startupHints/locales/en/5.html @@ -1,45 +1,105 @@ - - - - - Documents Mode - - - - - - - -
    -

    Documents Mode

    -
    -
    -

    You'll also find in this mode two very important features : Import and Export.

    -
    - -

    Import

    -

    You can import PDF files (.pdf), images (.png, .jpg), OpenBoard documents (.ubz) or OpenBoard folders (.ubx), by clicking on

    -
    -

    Note that you can also import an OpenBoard document (.ubz) by double-clicking on it. It will launch OpenBoard if not already launched, and import it (or ask for replacement if it already exists).

    - You can also import multiple elements at a time, without having to click on again and again. -

    Export

    -

    You can export an OpenBoard document to PDF or UBZ, and an OpenBoard folder to UBX. Thus, you can, for example : -

      -
    • Save the work done during a class session and share it with a missing student
    • -
    • Share it with other teachers, or store it on an USB device and open it on another computer
    • -
    • Import a student's homework in the PDF format, annotate it, and export the annotated PDF to send it back to the student
    • -
    -

    -
    - - Export all your documents by selecting the "My documents" folder before clicking on the export button, to export it as a UBX file, and then import it on another computer. It's also a good way to make a backup of your work ! -
    -
    - -
    - - + + + + + + Import and export + + + + + + + + + + +
    + +
    +

    Import & Export

    +

    + In this mode, you have two essential features: import And export. +

    +
    + Import and export area in Documents Mode + +
    +
    + + +
    +

    Import content

    +

    + You can import files PDF (.pdf), + of the pictures (.png, .jpg), + of the documents OpenBoard (.ubz) or + OpenBoard folders (.ubx) by clicking on + Import icon. + +

    + +
    + Example of importing files into OpenBoard +
    Example of importing files into OpenBoard.
    +
    + +

    + You can also import a OpenBoard document (.ubz) in + double-click on it from your system. OpenBoard will launch if necessary and + will offer to import (or replace if it already exists). +

    + + +
    + + +
    +

    Export your documents

    +

    + You can export a document OpenBoard in format PDF Or UBZ, + and a folder OpenBoard in format UBX. For example : +

    +
      +
    • Record the work done during a lesson and share it with an absent student.
    • +
    • Share with other teachers, or save to a USB key to import elsewhere.
    • +
    • Import a student's work as a PDF, annotate it, then export the annotated PDF for resend.
    • +
    + +
    + Examples of exporting documents and folders OpenBoard +
    Example of exporting files from OpenBoard.
    +
    + + +
    +
    + +
    +
    + + + diff --git a/resources/startupHints/locales/en/6.html b/resources/startupHints/locales/en/6.html index 7067f41ba..40790c69c 100644 --- a/resources/startupHints/locales/en/6.html +++ b/resources/startupHints/locales/en/6.html @@ -1,44 +1,96 @@ - - - - - Web Mode - - - - - - - -
    -

    Web Mode

    -
    -
    - The Web Mode is an internal navigator that adds some cool features to a more standard one. -

    Use the internal navigator

    -

    Using the internal navigator, you'll be able to browse the Internet without the need for reducing or exiting OpenBoard, with some additional features giving the ability to capture part of the screen or create applications from sites, and add them to the whiteboard !

    - -
    - -

    Create an application

    -

    You can create an application from any site, in order to add it to the board and interact with it like with default applications.

    -

    To do so, go to the website you want to capture, click on Capture Web Content and confirm the creation by clicking on "Create an application".

    -
    - -

    When an application is created, it is automatically saved in the OpenBoard library, so you can use it in any document. You'll find them on the applications folder, under a dedicated one called "Web".

    - -
    - -

    Use an external navigator

    -

    You can also choose to use an external navigator, by checking the corresponding option in the preferences. Clicking on the Web icon will then launch your favorite navigator in Desktop Mode.

    - Using an external navigator, you will still be able to create applications from a site, by copying the URL in the address bar of your navigator, coming back to Board, and pasting it ! -
    -
    - -
    - - + + + + + Web Mode + + + + + + + + + +
    + +
    +

    The integrated browser

    +

    + THE Web Mode is a browser internal to OpenBoard which adds to a browser + classic, very practical features for the classroom. +

    +

    + It allows you to browse the Internet without leaving OpenBoard, to capture content (partial or + full screen) and even create apps from websites for + reuse in your documents. +

    + +
    + Example of using the built-in browser of OpenBoard +
    +
    + + +
    +

    Create an application from a site

    +

    + From any site, you can generate a application to add it + on the board and interact with it as with the default applications. +

    +

    + Go to the desired site, click on + Add to Library icon + then confirm by selecting Create an app. +

    + +
    + Creating a web application from the built-in browser +
    Creation of an application from web mode.
    +
    + +

    + Once created, the application is automatically saved in the + library OpenBoard. You will find it under Applications > Web + and can reuse it in any document. +

    + +
    + Application saved in library, web folder +
    Find an application created in your library.
    +
    +
    + + +
    + +

    + You can choose to open the links in a external browser by checking + the corresponding option in the preferences. Click on + Web Mode icon + will then launch your favorite browser as Desktop Mode. +

    + + +
    + +
    + +
    + +
    + + + diff --git a/resources/startupHints/locales/en/7.html b/resources/startupHints/locales/en/7.html index 9f415622c..dca846742 100644 --- a/resources/startupHints/locales/en/7.html +++ b/resources/startupHints/locales/en/7.html @@ -1,50 +1,102 @@ - - - - - Screen Capture - - - - - - - -
    -

    Screen Capture

    -
    -
    - One of the simplest but really useful features of OpenBoard is screen capture. With it, you can create a snapshot of any particular state of the Board, during your class session. -

    In Board Mode

    -

    Search forthe screen capture icon in the Stylus palette, click on it and select the area to capture. Then, you'll have three options :

    -
      -
    • Add to current page
    • -
    • Add in a new page
    • -
    • Add to library(adds the capture to the Pictures folder, so you can reuse it at any time)
    • -
    - -

    Here's an example of the whole process :

    -
    - - You don't have to worry about the Stylus palette, the Board's thumbnails view or the OpenBoard Library, they won't be captured by your lasso ! - -

    In Desktop Mode

    -

    You can do the same thing in Desktop Mode, to capture your work on other softwares. Go to Desktop Mode by clicking on

    -

    You'll find two icons : to capture the whole screen, and to capture just a part of it. Like in Board Mode, you'll have to choose where to drop the capture you made

    - -

    Here's an illustration of the whole process

    -
    - - -

    In Web Mode

    -

    Again, the same process is available in Web Mode, where you will be able to capture just a part of the screen, or capture the current tab with

    -
    -
    - -
    - - + + + + + Screenshot + + + + + + + + + +
    +
    +

    A simple and very useful feature

    +

    + Screenshot allows you to create a instant the state of the board (or your screen) + during your course, to archive, share or reuse content. +

    +
    + + +
    +

    In Board Mode

    +

    + In the Pen palette, click + Capture Area Icon (Board Mode), + then select the area to capture. You can then choose: +

    +
      +
    • Add to current page
    • +
    • Add to new page
    • +
    • + Add to library — the capture is saved in the folder Pictures + for later reuse. +
    • +
    + +
    + Example of capturing an area in Board Mode +
    Example of embedding a screenshot in OpenBoard.
    +
    + + +
    + + +
    +

    In Desktop Mode

    +

    + Switch to Desktop Mode via + Desktop Mode icon + to capture other software. +

    +

    Two options are available:

    +
      +
    • + Screen Capture icon + Full screen capture +
    • +
    • + Capture area icon + Capturing an area +
    • +
    +

    As in Board Mode, choose where to add the capture.

    + +
    + Example of capture in Desktop Mode +
    Full or partial screenshot in Desktop Mode.
    +
    +
    + + +
    +

    In Web Mode

    +

    + In Web Mode you can capture an area of the screen or + capture active tab from the browser with + Capture tab icon. +

    +
    +
    + +
    +
    + + + diff --git a/resources/startupHints/locales/en/8.html b/resources/startupHints/locales/en/8.html index c0bdac95b..d4a3c2a78 100644 --- a/resources/startupHints/locales/en/8.html +++ b/resources/startupHints/locales/en/8.html @@ -1,42 +1,102 @@ - - - - - Images - - - - - - - -
    -

    Images

    -
    -
    - In OpenBoard, you can have access to images in several ways. -

    Organize your Pictures folder

    -

    Screen captures added to the Library are saved to the Pictures folder :
    You can create folders using at the bottom of the Library. Then, drag and drop your images in the different folders you created.

    -
    - - No matter where you are in the OpenBoard Library, images you add will be automatically placed inside the Pictures folder, to keep things organized. - -

    Add images from your computer

    -

    You can also add images directly from your computer, like illustrated below :

    -
    - -

    Add images from the search engines

    -

    Last but not least, you can search and add to your board royalty free images, using the search engines located in the Web Search folder :

    -
    - - Instead of using drag and drop, just click on one of the images returned by your search, to see details about the image, and find an option to add it to the Library, without adding it to your current document. Useful when preparing a lesson ! -
    -
    - -
    - - + + + + + Pictures + + + + + + + + + +
    +
    +

    Access and organize your images

    +

    + In OpenBoard you can access and add images in different ways from your library. The latter is located on the right of the screen. This is also where you can store sounds, videos and find different applications. +

    +
    + Import and export area in Documents Mode +
    Image of the library located on the right in the software.
    +
    +
    + + +
    +

    Organize your Pictures folder

    +

    + Screenshots added to the library are grouped in the folder + Icon Images. + You can create subfolders via + New folder icon + (at the bottom of the library), then drag and drop your images into the different folders created. +

    + +
    + Organizing the Pictures folder with subfolders +
    Example of organizing and classifying images in the library.
    +
    + + +
    + + +
    +

    Add images from your computer

    +

    + You can import your own image files directly into OpenBoard, as shown below: +

    + +
    + Adding images from the computer +
    Importing a local image into OpenBoard.
    +
    +
    + + +
    +

    Add images from the web

    +

    + You can also search for royalty free images via integrated search engines, + located in the folder Web Search + Icon Images. +

    + +
    + Adding images from an integrated search engine +
    Example of finding and adding images from the web.
    +
    + + +
    +
    + +
    + +
    + + + diff --git a/resources/startupHints/locales/en/9.html b/resources/startupHints/locales/en/9.html index caf0e3b36..c0b5935a4 100644 --- a/resources/startupHints/locales/en/9.html +++ b/resources/startupHints/locales/en/9.html @@ -1,49 +1,99 @@ - - - - - Interactivities - - - - - - - -
    -

    Interactivities

    -
    -
    - For younger students, you'll find a dedicated set of customizable applications. -

    Interactive exercices of OpenBoard

    -

    Using these interactivities, you can create different kinds of custom exercices. These can be about categorization, calculation, memorization, and so on.

    -

    Interactivites are located in the OpenBoard Library : click on to find them.

    - -

    Example

    -

    As an example, we'll create an exercise using the "Categorize pictures" interactivity :

    - Try it ! Move this dialog on a side and reproduce the example on the Board ! -

    First, drag and drop the interactivity on your board, and click on "Edit"

    -

    Then, change the name of the categories to your needs :

    -
    - - You can add or delete categories using the + and - icons - -

    Then, add the images you want in the corresponding category.

    -
    - -

    Finally, Click on "Display" to show the result and do the exercise.

    -
    - - You can restart the exercise using the "Reload" icon. - - -
    -
    - -
    - - + + + + + Interactivities + + + + + + + + + + +
    + +
    +

    Interactive exercises, easy to personalize

    +

    + For the youngest students (and not only), OpenBoard provides a set + ofinteractivities customizable: categorization, mental calculation, memorization, etc. +

    +

    + They are accessible in the library : click on + Interactivities Icon. +

    +
    + + +
    +

    Example: “Categorize Pictures”

    +

    + Let’s create an exercise with interactivity + categorize pictures (categorize images): + Thumbnail Categorize Pictures. +

    + + + +

    1) Place interactivity and open the editor

    +

    + Drag and drop the interactivity onto the Board, then click To modify. +

    + +

    2) Name the categories

    +

    + Rename the categories as needed. You can also + add Or DELETE categories with “+” and “−” icons. +

    + +
    + Editing interactivity categories +
    Editing categories: addition, deletion, renaming.
    +
    + +

    3) Add the images

    +

    + Add images corresponding to each category (drag and drop, selection from library, etc.). +

    + +
    + Adding images to categories +
    Associate images with defined categories.
    +
    + +

    4) Show and do the exercise

    +

    + Click on Display to start the activity in student mode. +

    + +
    + Performing the Categorize Pictures exercise +
    Execution of the exercise: move the images into the correct category.
    +
    + + +
    +
    + +
    +
    + + diff --git a/resources/startupHints/locales/en/css/dark.css b/resources/startupHints/locales/en/css/dark.css deleted file mode 100644 index 34ded372a..000000000 --- a/resources/startupHints/locales/en/css/dark.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - background-color: #3a3a3a; - color: #e0e0e0; -} - -.title { - color: #8ba3d7; -} diff --git a/resources/startupHints/locales/en/css/light.css b/resources/startupHints/locales/en/css/light.css deleted file mode 100644 index 4e1f81f0e..000000000 --- a/resources/startupHints/locales/en/css/light.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - background-color: #edf2f7; - color: #1f2937; -} - -.title { - color: #5f7faa; -} diff --git a/resources/startupHints/locales/en/css/style.css b/resources/startupHints/locales/en/css/style.css deleted file mode 100644 index de0ecb4d5..000000000 --- a/resources/startupHints/locales/en/css/style.css +++ /dev/null @@ -1,36 +0,0 @@ -*{ - font-family: Arial, Helvetica, sans-serif; -} - -.title -{ - width:100%; - color: #6682b5; - text-align: center; -} - -.file-extension -{ - background: lightgrey; -} - -.image -{ - text-align:center; -} - -.image img -{ - max-width: 600px; -} - -.icon -{ - vertical-align: middle; -} - -.tip -{ - font-style: italic; - font-size: 0.8rem; -} diff --git a/resources/startupHints/locales/en/error.html b/resources/startupHints/locales/en/error.html index a456d7cdb..2e4c100ee 100644 --- a/resources/startupHints/locales/en/error.html +++ b/resources/startupHints/locales/en/error.html @@ -1,15 +1,20 @@ - - - - - erreur - - - - - -

    Quelque chose s'est mal passé ... -Vérifier l'existence de vos conseils dans le dossier -/Resources/startupHints/ …

    - - + + + + + Error + + + + + +
    +

    Loading error

    +

    + Something went wrong. + Check the presence of tips pages in the folder + /Resources/startupHints/. +

    +
    + + diff --git a/resources/startupHints/locales/fr/1.html b/resources/startupHints/locales/fr/1.html index a9526a6c0..6bf6bebde 100644 --- a/resources/startupHints/locales/fr/1.html +++ b/resources/startupHints/locales/fr/1.html @@ -1,32 +1,95 @@ - - - - - Trucs et astuces - - - - - - - -
    -

    Bienvenue sur OpenBoard

    -
    -
    -
    -
    -

    Voici quelques trucs et astuces pour vous aider à vous familiariser avec OpenBoard.

    -

    OpenBoard est un tableau blanc interactif pensé par des enseignants, pour des enseignants. Il est composé de 4 modes : le mode Tableau, le mode Bureau, le mode Documents et le mode Web.

    -

    Commençons par le premier, et le plus important : le mode Tableau.

    -
    -
    - Vous pouvez réouvrir à tout moment cette fenêtre via le bouton "Trucs et astuces" dans le menu OpenBoard (the OpenBoard menu) -
    - - - + + + + + Bienvenue + + + + + + + +
    + + +

    + Voici quelques trucs et astuces pour vous aider à vous familiariser avec OpenBoard. +

    + +

    + OpenBoard est un tableau blanc interactif pensé par des enseignants, pour des enseignants. + Il propose quatre modes complémentaires pour couvrir vos usages en classe. +

    + +
    +

    Les 4 modes d’OpenBoard

    + +
    + +
    +

    Commençons par le premier, et le plus important : le mode Tableau.

    +
    + + +
    + +
    + +
    + + + + diff --git a/resources/startupHints/locales/fr/10.html b/resources/startupHints/locales/fr/10.html index 263709d6a..203e6fc84 100644 --- a/resources/startupHints/locales/fr/10.html +++ b/resources/startupHints/locales/fr/10.html @@ -1,50 +1,95 @@ - - + + - - Applications - - - - + + Applications + + + + -
    -

    Applications

    -
    -
    -

    OpenBoard propose différentes applications et outils. Vous pouvez y accéder en cliquant sur dans la bibliothèque OpenBoard

    -

    Applications par défaut

    -

    Vous y trouverez des outils géométriques, une calculatrice, Google Maps, un générateur de code QR et bien plus ! Combinez-les pour créer des expériences pédagogiques stimulantes !

    -
    -

    Créez des applications

    -

    Comme expliqué dans la section Mode Web, vous pouvez créer une application depuis un site, en utilisant le navigateur interne, ou en copiant-collant une URL sur le tableau.

    -

    Grâce à cela, vous pouvez agrémenter vos cours avec des outils en ligne puissants, utilisables directement sur le tableau ! Voici quelques illustrations d'applications intéressantes (Glissez-déposez les sur le tableau pour les tester !) :

    - - -

    ... et bien plus !

    - - Vous avez besoin d'une calculatrice plus puissante que celle fournie par défaut dans OpenBoard ? Souvenez-vous ! Vous pouvez créer vos propres applications ! Glissez-déposez le lien suivant sur votre tableau : https://ti89-simulator.com/ -
    -
    - -
    - + + + +
    + +
    +

    Accéder aux applications

    +

    + OpenBoard propose différentes applications et outils. + Retrouvez-les dans la bibliothèque en cliquant sur + Icône Applications. +

    +
    + + +
    +

    Applications par défaut

    +

    + Vous y trouverez des outils géométriques, une calculatrice, Google Maps, un générateur de QR codes et bien plus. + Combinez-les pour créer des expériences pédagogiques stimulantes ! +

    + +
    + Exemple d’utilisation des applications intégrées +
    Exemple d’utilisation des applications intégrées d’OpenBoard.
    +
    +
    + + +
    +

    Créez vos propres applications

    +

    + Comme expliqué dans la section Mode Web, vous pouvez créer une application à partir d’un site, + en utilisant le navigateur interne ou en copiant-collant une URL sur le tableau. +

    +

    + Cela vous permet d’agrémenter vos cours avec des outils en ligne puissants, utilisables directement dans OpenBoard. + Voici quelques exemples intéressants (glissez-déposez les liens sur le tableau pour les tester) : +

    + + + +

    ... et bien plus encore !

    + + +
    +
    + +
    + +
    + + + diff --git a/resources/startupHints/locales/fr/11.html b/resources/startupHints/locales/fr/11.html index 701630fdb..b94572e5d 100644 --- a/resources/startupHints/locales/fr/11.html +++ b/resources/startupHints/locales/fr/11.html @@ -1,45 +1,90 @@ - - + + - - Capture Vidéo - - - - + + Capture Vidéo + + + + -
    -

    Capture Vidéo

    -
    -
    -

    Enregistrez votre cours

    -

    OpenBoard vous offre la possibilité de faire une capture audio et vidéo de votre cours.

    -

    Cela peut, par exemple, être utile pour partager des exercices additionnels ou une information via un clip vidéo, ou encore enregistrer un cours afin de le partager avec des élèves absents.

    - - En mode tableau, les barres d'outils et palettes n'apparaîtront pas dans le clip vidéo, donc vous n'avez pas à vous en soucier ! Idem avec le navigateur interne, où seul l'onglet actif sera capturé. - -

    Vous pouvez accéder à cet outil comme ceci :

    -
    - -

    Vous verrez apparaître l'interface suivante en bas à droite du tableau :

    -
    - -

    Cliquez sur le bouton rouge pour commencer l'enregistrement.

    - - Vous pouvez ajuster les paramètres en cliquant sur . Vous y trouverez des paramètres audio (sélectionner un micro, ou aucun), des paramètres vidéo (résolution de la capture vidéo) et des options de publication configurables - -

    Une fois l'enregistrement terminé, la capture sera sauvegardée et disponible sur le bureau de votre ordinateur

    -
    - -
    -
    - -
    + + + +
    + +
    +

    Enregistrez votre cours

    +

    + OpenBoard permet d’enregistrer l’audio et la vidéo de votre cours. + Idéal pour partager des exercices additionnels, publier un court clip explicatif ou + mettre un cours à disposition des élèves absents. +

    + + +
    + + +
    +

    Accéder à l’outil d’enregistrement

    +

    Ouvrez l’outil de capture comme illustré ci-dessous :

    + +
    + Ouverture de l’outil Capture Vidéo dans OpenBoard +
    Accès rapide à l’outil d’enregistrement depuis l’interface d’OpenBoard.
    +
    +
    + + +
    +

    Interface de contrôle

    +

    L’interface apparaît en bas à droite du Tableau :

    + +
    + Interface de l’enregistreur (contrôles en bas à droite) +
    + +

    Cliquez sur le bouton rouge pour lancer l’enregistrement.

    + + +
    + + +
    +

    Terminer et récupérer la vidéo

    +

    + Une fois l’enregistrement terminé, la vidéo est automatiquement enregistrée sur le Bureau de votre ordinateur. +

    + +
    + Fin d’enregistrement et sauvegarde de la vidéo sur le Bureau +
    Arrêt de l’enregistrement et fichier vidéo disponible sur le Bureau.
    +
    +
    +
    + +
    + +
    diff --git a/resources/startupHints/locales/fr/12.html b/resources/startupHints/locales/fr/12.html index eb5bb7035..8a536de55 100644 --- a/resources/startupHints/locales/fr/12.html +++ b/resources/startupHints/locales/fr/12.html @@ -1,43 +1,94 @@ - - + + - - Documents favoris - - - - + + Documents favoris + + + + -
    -

    Documents favoris

    -
    -
    -

    Ajouter des documents OpenBoard aux favoris

    -

    Nouvelle fonctionnalité de la version 1.7, vous pouvez ajouter des documents OpenBoard à vos favoris !

    -

    Pour ce faire, allez en mode Documents, sélectionnez un document et cliquez sur dans la la barre d'outils du mode Documents.

    - -
    - -

    Passez rapidement d'un document à l'autre

    -

    Vos documents favoris apparaîtront dans la bibliothèque OpenBoard, sous
    - Chacun de ces documents OpenBoard () peut ensuite être glissé-déposé sur le tableau !

    -
    - - Vous pouvez utiliser la barre de recherche située en bas de la bibliothèque OpenBoard pour retrouver un document à partir de son nom - -

    Documents récemment ouverts

    -

    Chaque document ouvert sera ajouté temporairement aux favoris afin que vous puissiez passer rapidement de l'un à l'autre durant une même session, sans qu'il soit nécessaire de les marquer explicitement comme favoris.

    -
    - Si vous voulez ajouter de façon permanente un document récemment ouvert aux favoris, vous pouvez le faire via le dossier Favoris de la bibliothèque OpenBoard : sélectionnez-le et cliquez sur -
    -
    - -
    + + + +
    + +
    +

    Ajouter des documents OpenBoard aux favoris

    +

    + Introduite dans la version 1.7, cette fonctionnalité permet d’ajouter vos documents OpenBoard + en favoris. +

    +

    + Pour cela, passez en Mode Documents, sélectionnez un document et cliquez sur + Icône Ajouter aux favoris + dans la barre d’outils. +

    + +
    + Ajout d’un document OpenBoard aux favoris + +
    +
    + + +
    +

    Passer rapidement d’un document à l’autre

    +

    + Vos documents favoris apparaissent dans la bibliothèque OpenBoard, sous + Icône Favoris. +

    +

    + Chaque document favori + Icône Document OpenBoard + peut être glissé-déposé directement sur le Tableau. +

    + +
    + Affichage des favoris dans la bibliothèque OpenBoard +
    + + + +
    + + +
    +

    Documents récemment ouverts

    +

    + Chaque document ouvert est ajouté temporairement aux favoris, pour passer rapidement de l’un à l’autre + au cours d’une même session, sans devoir les marquer explicitement. +

    + +
    + Exemple de documents récemment ouverts dans OpenBoard + +
    + + +
    +
    + +
    +
    diff --git a/resources/startupHints/locales/fr/2.html b/resources/startupHints/locales/fr/2.html index 980d85e65..2e937325a 100644 --- a/resources/startupHints/locales/fr/2.html +++ b/resources/startupHints/locales/fr/2.html @@ -1,52 +1,122 @@ - - + + - - Mode Tableau - - - - + + Mode Tableau + + + -
    -

    Mode Tableau

    -
    -
    -

    La palette des stylets

    -

    La palette des stylets vous donne accès à des outils essentiels quand on travaille sur un tableau blanc.

    -
    - -

    Vous y trouverez le crayon (), la gomme () et le surligneur (). OpenBoard fournit également des fonctionnalités qu'un tableau blanc classique ne peut pas fournir :

    -
      -
    • est le sélecteur. Avec, vous pouvez sélectionner et interagir avec des objets.
    • -
    • est le doigt magique. Vous pouvez déplacer des objets ou interagir avec eux sans qu'il soit nécessaire de les sélectionner.
    • -
    • est la main. Vous pouvez déplacer la page avec. Très utile quand combinée avec les fonctionnalités de zoom !
    • -
    • vous donnent la possibilité de zoomer et dézoomer. Sélectionnez simplement l'effet désiré, et cliquer à l'endroit où vous souhaitez l'appliquer !
    • -
    • est un pointeur laser, utile pour pointer des éléments sur le tableau sans interagir avec ces derniers.
    • -
    • est utilisé pour tracer des droites facilement.
    • -
    • est une boîte de texte, permettant d'écrire au clavier plutôt qu'au crayon.
    • -
    - - Vous pouvez avoir un contrôle plus fin du zoom avec la souris ! Utilisez Ctrl/Cmd + la molette de la souris afin de zoomer/dézoomer avec plus de précision ! -

    La barre du tableau

    -

    La barre du tableau vous permet de changer la couleur et/ou la taille du crayon et marqueur, entre autres choses.

    -
    - -

    Vous y trouverez également la possibilité de changer le fond du tableau en cliquant sur

    -
    - -

    Vous y trouverez aussi des fonctionnalités comme annuler/rétablir, créer et naviguer de pages en pages, effacer le tableau, ...

    - - Vous pouvez effacer entièrement des éléments plus spécifiques du tableau, en faisant un clic long sur the erase icon. Quelques fonctionnalités supplémentaires accessibles également pour the erase icon ! -
    -
    - -
    + + +
    + +
    +

    La palette des stylets

    +

    + La palette des stylets vous donne accès à des outils essentiels quand on travaille sur un tableau blanc. +

    + +
    + Palette des stylets d’OpenBoard +
    + +

    + Vous y trouverez le crayon + Crayon, + la gomme + Gomme + et le surligneur + Surligneur. + OpenBoard fournit également des fonctionnalités qu’un tableau blanc classique ne peut pas proposer : +

    + +
      +
    • + + Sélecteur : sélectionnez et interagissez avec les objets. +
    • +
    • + + Doigt magique : déplacez/interagissez sans sélectionner au préalable. +
    • +
    • + + Main : déplacez la page (très utile combiné au zoom). +
    • +
    • + + + Zoom / Dézoom : cliquez où appliquer l’effet après l’avoir sélectionné. +
    • +
    • + + Pointeur laser : pointez des éléments sans interagir avec eux. +
    • +
    • + + Ligne : tracez des droites facilement. +
    • +
    • + + Texte : insérez une zone de texte pour taper au clavier. +
    • +
    + + +
    + + +
    +

    La barre du tableau

    +

    + La barre du tableau vous permet de changer la couleur et/ou la taille du crayon et du surligneur, entre autres choses. +

    + +
    + Barre du tableau d’OpenBoard +
    + +

    + Vous pouvez aussi changer le fond du tableau en cliquant sur + Changer le fond. +

    + +
    + Exemple de changement de fond du tableau +
    + +

    + D’autres fonctions sont disponibles : annuler/rétablir, créer des pages, naviguer entre les pages, effacer le tableau, etc. +

    + + +
    +
    + +
    + +
    diff --git a/resources/startupHints/locales/fr/3.html b/resources/startupHints/locales/fr/3.html index 848c2c4f3..256a75d69 100644 --- a/resources/startupHints/locales/fr/3.html +++ b/resources/startupHints/locales/fr/3.html @@ -1,36 +1,74 @@ - - + + - - Mode Bureau - - - - + + Mode Bureau + + + + -
    -

    Mode Bureau

    -
    -
    -

    Interagir avec d'autres applications

    -

    En utilisant le mode Bureau, vous pouvez interagir avec votre système d'exploitation et d'autres logiciels, tout en conservant OpenBoard par dessus !

    -

    Cliquez simplement sur l'icône suivante :

    -
    -
    Utilisez le sélecteur () pour interagir avec le bureau et les autres applications.
    -

    Annoter des applications ou des sites web

    -
    Vous pouvez annoter n'importe quel logiciel, en utilisant le crayon () ou le marqueur ().
    -
    - - Vous pouvez accéder à plus d'options pour the pen, the marker et the eraser en faisant en clic long sur eux, ou en cliquant sur la petite flèche noire. -
    -
    - -
    + + +
    + +
    +

    Interagir avec d’autres applications

    +

    + Le mode Bureau vous permet d’interagir avec votre système d’exploitation et vos logiciels, + tout en conservant les outils d’OpenBoard par-dessus. +

    +

    Cliquez simplement sur l’icône suivante :

    + +
    + Icône pour activer le Mode Bureau +
    + +

    + Utilisez le sélecteur + Sélecteur + pour interagir avec le bureau et les autres applications. +

    +
    + + +
    +

    Annoter des applications ou des sites web

    +

    + Vous pouvez annoter n’importe quel logiciel avec le crayon + Crayon + ou le marqueur + Marqueur. +

    + +
    + Annotation d’une application en Mode Bureau +
    Exemple d'annotation sur une page internet.
    +
    + + +
    +
    + +
    + +
    diff --git a/resources/startupHints/locales/fr/4.html b/resources/startupHints/locales/fr/4.html index afb0f2906..2dc8ec7fe 100644 --- a/resources/startupHints/locales/fr/4.html +++ b/resources/startupHints/locales/fr/4.html @@ -1,38 +1,79 @@ - - + + - - Mode Documents - - - - + + Mode Documents + + + + -
    -

    Mode Documents

    -
    -
    -

    OpenBoard propose un gestionnaire de documents. Vous pouvez y accéder en cliquant simplement sur

    -
    - -

    Créez des dossiers et organisez votre travail

    -

    Vous pouvez créer un dossier en cliquant sur . Nommez-le, et glissez-déposez y vos documents. De la même façon, vous pouvez déplacer un dossier entier à l'intérieur d'un autre.

    -
    + + +
    + +
    +

    Accéder au gestionnaire de documents

    +

    + OpenBoard propose un gestionnaire de documents. Cliquez sur + Icône Documents + pour l’ouvrir. +

    +
    + Vue du gestionnaire de documents +
    +
    + + +
    +

    Créez des dossiers et organisez votre travail

    +

    + Créez un dossier via + Nouveau dossier, + nommez-le, puis glissez-déposez vos documents à l’intérieur. + De la même façon, vous pouvez déplacer un dossier entier dans un autre. +

    +
    + Création et organisation de dossiers +
    Exemple de création et d'organisation de dossiers.
    +
    +
    + + +
    +

    Gestion des pages

    +

    + Un document OpenBoard peut contenir plusieurs pages. Depuis le Mode Documents, vous pouvez : +

    +
      +
    • Dupliquer des pages
    • +
    • Les envoyer à la corbeille
    • +
    • Les copier vers un autre document
    • +
    • Créer de nouvelles pages à partir d’un dossier d’images
    • +
    +
    + Exemples d’actions sur les pages +
    Exemple de manipulation de documents.
    +
    -

    Gestion des pages

    -

    Un document OpenBoard peut contenir plusieurs pages. Via le mode Documents, vous pouvez les dupliquer, les mettre à la corbeille ou les copier vers un autre document, en créer de nouvelles à partir d'un dossier d'images, ...

    -
    - - À noter que les actions disponibles sont mises à jour en fonction de ce qui est sélectionné. -
    -
    + + +
    - +
    +
    diff --git a/resources/startupHints/locales/fr/5.html b/resources/startupHints/locales/fr/5.html index c0ae7a888..93eb11579 100644 --- a/resources/startupHints/locales/fr/5.html +++ b/resources/startupHints/locales/fr/5.html @@ -1,45 +1,105 @@ - - + + + - - Mode Documents - - - - + + Importer et exporter + + + + -
    -

    Mode Documents

    -
    -
    -

    Vous trouverez également dans ce mode deux fonctionnalités très importantes : l'import et l'export.

    -
    - -

    Import

    -

    Vous pouvez importer des fichiers PDF (.pdf), des images (.png, .jpg), des documents OpenBoard (.ubz) ou des dossiers OpenBoard (.ubx), en cliquant sur

    -
    -

    À noter que vous pouvez aussi importer un document OpenBoard (.ubz) en double-cliquant dessus. Cela lancera OpenBoard s'il n'est pas déjà lancé, et l'importera (ou proposera un remplacement du fichier si déjà existant).

    - Vous pouvez également importer plusieurs éléments à la fois, sans qu'il soit nécessaire de cliquer sur encore et encore. -

    Export

    -

    Vous pouvez exporter un document OpenBoard au format PDF ou UBZ, et un dossier OpenBoard au format UBX. Ainsi, vous pouvez, par exemple : -

      -
    • Enregistrer le travail fait durant un cours, et le partager avec un élève absent.
    • -
    • Le partager avec d'autres enseignants, ou le sauvegarder sur une clé USB pour l'importer sur un autre ordinateur.
    • -
    • Importer le travail d'un élève au format PDF, l'annoter, et exporter le document annoté au format PDF pour le renvoyer à l'élève
    • -
    -

    -
    - - Exporter tous vos documents en cliquant sur le dossier racine "Mes Documents", avant de cliquer sur , pour les exporter au format UBX. Vous pourrez alors les importer sur un autre ordinateur. C'est aussi un bon moyen d'effectuer une archive ou une sauvegarde de tout votre travail ! -
    -
    - -
    + + + +
    + +
    +

    Import & Export

    +

    + Dans ce mode, vous disposez de deux fonctionnalités essentielles : l’import et l’export. +

    +
    + Zone d’import et d’export dans le Mode Documents + +
    +
    + + +
    +

    Importer des contenus

    +

    + Vous pouvez importer des fichiers PDF (.pdf), + des images (.png, .jpg), + des documents OpenBoard (.ubz) ou des + dossiers OpenBoard (.ubx) en cliquant sur + Icône Importer. + +

    + +
    + Exemple d’import de fichiers dans OpenBoard +
    Exemple d'importation de fichiers dans OpenBoard.
    +
    + +

    + Vous pouvez aussi importer un document OpenBoard (.ubz) en + double-cliquant dessus depuis votre système. OpenBoard se lancera si nécessaire et + vous proposera d’importer (ou de remplacer s’il existe déjà). +

    + + +
    + + +
    +

    Exporter vos documents

    +

    + Vous pouvez exporter un document OpenBoard au format PDF ou UBZ, + et un dossier OpenBoard au format UBX. Par exemple : +

    +
      +
    • Enregistrer le travail fait durant un cours et le partager à un élève absent.
    • +
    • Partager à d’autres enseignants, ou sauvegarder sur une clé USB pour l’importer ailleurs.
    • +
    • Importer le travail d’un élève en PDF, l’annoter, puis exporter le PDF annoté pour le renvoyer.
    • +
    + +
    + Exemples d’export de documents et dossiers OpenBoard +
    Exemple d'exportation de fichiers depuis OpenBoard.
    +
    + + +
    +
    + +
    +
    + diff --git a/resources/startupHints/locales/fr/6.html b/resources/startupHints/locales/fr/6.html index a4919cb4c..21a9cd726 100644 --- a/resources/startupHints/locales/fr/6.html +++ b/resources/startupHints/locales/fr/6.html @@ -1,44 +1,96 @@ - - + + - - Mode Web - - - - + + Mode Web + + + + -
    -

    Mode Web

    -
    -
    - Le mode Web est un navigateur interne qui ajoute à un navigateur plus traditionnel des fonctionnalités très intéressantes. -

    Utilisation du navigateur interne

    -

    En utilisant le navigateur interne, vous aurez la possibilité de parcourir Internet sans le besoin de réduire ou quitter OpenBoard, avec des fonctionnalités supplémentaires vous permettant d'effectuer une capture partielle ou entière de l'écran, ou encore créer des applications à partir de sites, et les ajouter au tableau !

    - -
    - -

    Créer une application

    -

    Vous pouvez créer une application à partir de n'importe quel site, afin de l'ajouter au tableau et interagir avec, comme avec les applications par défaut.

    -

    Pour ce faire, allez sur le site web que vous souhaitez capturer, cliquez sur Capture Web Content et confirmez sa création en cliquant sur "Créer une application".

    -
    - -

    Quand une application est créée, elle est automatiquement sauvegardée dans la bibliothèque OpenBoard, afin que vous puissiez la réutiliser dans n'importe quel document. Vous les retrouverez sous le dossier Applications, dans un sous-dossier appelé "Web"

    - -
    - -

    Utilisation du navigateur externe

    -

    Vous pouvez également choisir d'utiliser un navigateur externe, en cochant l'option correspondante dans les préférences. Cliquer sur lancera alors votre navigateur préféré en mode Bureau.

    - En utilisant un navigateur externe, vous pourrez toujours créer une application depuis un site, en copiant l'URL située dans la barre d'adresse de votre navigateur, puis en la collant une fois de retour dans le mode Tableau ! -
    -
    - -
    + + +
    + +
    +

    Le navigateur intégré

    +

    + Le Mode Web est un navigateur interne à OpenBoard qui ajoute à un navigateur + classique des fonctionnalités très pratiques pour la classe. +

    +

    + Il permet de parcourir Internet sans quitter OpenBoard, de capturer des contenus (partiels ou + plein écran) et même de créer des applications à partir de sites web pour les + réutiliser dans vos documents. +

    + +
    + Exemple d’utilisation du navigateur intégré d’OpenBoard +
    +
    + + +
    +

    Créer une application à partir d’un site

    +

    + Depuis n’importe quel site, vous pouvez générer une application pour l’ajouter + au tableau et interagir avec elle comme avec les applications par défaut. +

    +

    + Rendez-vous sur le site souhaité, cliquez sur + Icône Ajouter à la bibliothèque + puis confirmez en sélectionnant Créer une application. +

    + +
    + Création d’une application Web depuis le navigateur intégré +
    Création d'une application depuis le mode web.
    +
    + +

    + Une fois créée, l’application est automatiquement sauvegardée dans la + bibliothèque OpenBoard. Vous la retrouverez sous Applications > Web + et pourrez la réutiliser dans n’importe quel document. +

    + +
    + Application enregistrée dans la bibliothèque, dossier Web +
    Retrouver une application créée dans sa bibliothèque.
    +
    +
    + + +
    + +

    + Vous pouvez choisir d’ouvrir les liens dans un navigateur externe en cochant + l’option correspondante dans les préférences. Cliquer sur + Icône Mode Web + lancera alors votre navigateur favori en Mode Bureau. +

    + + +
    + +
    + +
    + +
    + diff --git a/resources/startupHints/locales/fr/7.html b/resources/startupHints/locales/fr/7.html index 56fb927c3..453d15b6b 100644 --- a/resources/startupHints/locales/fr/7.html +++ b/resources/startupHints/locales/fr/7.html @@ -1,50 +1,102 @@ - - + + - - Capture d'écran - - - - + + Capture d’écran + + + + -
    -

    Capture d'écran

    -
    -
    - Une des fonctionnalités basiques mais vraiment utiles d'OpenBoard est la capture d'écran. Avec, vous pouvez créer un instantané d'un état quelconque du tableau, pendant votre cours. -

    En mode Tableau

    -

    Cherchez the screen capture icon dans la palette des stylets, cliquez dessus et sélectionnez la zone à capturer. Ensuite, trois options vous seront proposées :

    -
      -
    • Ajouter à la page courante
    • -
    • Ajouter à la nouvelle page
    • -
    • Ajouter à la bibliothèque(ajoute la capture au dossier Images, afin que vous puissiez la réutiliser à tout moment)
    • -
    - -

    Voici un exemple du processus complet :

    -
    - - Vous n'avez pas à vous inquiéter de la palette des stylets, de l'onglet d'aperçu des pages ou de celui de la bibliothèque OpenBoard, ils ne seront pas capturés par votre lasso ! - -

    En mode Bureau

    -

    Vous pouvez faire la même chose en mode Bureau, pour capturer votre travail sur d'autres logiciels. Passez en mode Bureau en cliquant sur

    -

    Vous trouverez deux icônes : pour capturer l'ensemble de l'écran, et pour n'en capturer qu'une partie. Comme en mode Tableau, vous devrez choisir où ajouter la capture

    - -

    Voici une illustration du processus complet :

    -
    - - -

    En mode Web

    -

    De la même façon, il est possible de faire ceci en mode Web, où vous pourrez effectuer une capture partielle de l'écran, ou capturer l'onglet actif du navigateur en cliquant sur

    -
    -
    - -
    + + +
    +
    +

    Une fonctionnalité simple et très utile

    +

    + La capture d’écran vous permet de créer un instantané de l’état du tableau (ou de votre écran) + pendant votre cours, pour archiver, partager ou réutiliser le contenu. +

    +
    + + +
    +

    En Mode Tableau

    +

    + Dans la palette des stylets, cliquez sur + Icône Capture zone (Mode Tableau), + puis sélectionnez la zone à capturer. Vous pourrez ensuite choisir : +

    +
      +
    • Ajouter à la page courante
    • +
    • Ajouter à une nouvelle page
    • +
    • + Ajouter à la bibliothèque — la capture est enregistrée dans le dossier Images + pour réutilisation ultérieure. +
    • +
    + +
    + Exemple de capture d’une zone en Mode Tableau +
    Exemple d'intégration d'une capture d'écran à OpenBoard.
    +
    + + +
    + + +
    +

    En Mode Bureau

    +

    + Passez en Mode Bureau via + Icône Mode Bureau + pour capturer d’autres logiciels. +

    +

    Deux options sont disponibles :

    +
      +
    • + Icône Capture écran + Capture de l’écran entier +
    • +
    • + Icône Capture zone + Capture d’une zone +
    • +
    +

    Comme en Mode Tableau, choisissez où ajouter la capture.

    + +
    + Exemple de capture en Mode Bureau +
    Capture d’écran complet ou partiel en Mode Bureau.
    +
    +
    + + +
    +

    En Mode Web

    +

    + En Mode Web, vous pouvez capturer une zone de l’écran ou + capturer l’onglet actif du navigateur avec + Icône Capture onglet. +

    +
    +
    + +
    +
    + diff --git a/resources/startupHints/locales/fr/8.html b/resources/startupHints/locales/fr/8.html index a9679ead9..d48032119 100644 --- a/resources/startupHints/locales/fr/8.html +++ b/resources/startupHints/locales/fr/8.html @@ -1,42 +1,102 @@ - - + + - - Images - - - - + + Images + + + + -
    -

    Images

    -
    -
    - Dans OpenBoard, vous pouvez accéder à des images de plusieurs façons. -

    Organisez votre dossier Images

    -

    Les captures d'écran ajoutées à la bibliothèque sont trouvables dans le dossier Images :
    Vous pouvez créer des sous-dossiers en utilisant tout en bas de la Bibliothèque. Ensuite, glissez-déposez vos images dans les différents dossiers que vous avez créés.

    -
    - - Peu importe où vous vous situez dans la bibliothèque OpenBoard, les images que vous ajouterez seront automatiquement placées à l'intérieur du dossier , permettant ainsi de maintenir la bibliothèque organisée. - -

    Ajoutez des images depuis votre ordinateur

    -

    Vous pouvez également ajouter des images depuis votre ordinateur, comme illustré ici :

    -
    - -

    Ajoutez des images à partir des moteurs de recherche

    -

    Enfin, vous pouvez chercher et ajouter au tableau des images libres de droit, en utilisant les moteurs de recherche situés dans le dossier "Recherche Web" :

    -
    - - Au lieu d'utiliser le glisser-déposer, cliquez simplement sur une image apparaissant en résultat de recherche, pour en voir les détails et y trouver des options telles que Ajouter à la bibliothèque. Utile lors de la préparation d'un cours ! -
    -
    - -
    + + +
    +
    +

    Accéder et organiser vos images

    +

    + Dans OpenBoard, vous pouvez accéder et ajouter des images de différentes façons depuis votre bibliothèque. Cette dernière se situe à droite de l'écran. C'est également ici que vous pouvez stocker des sons, vidéos et trouver différentes applications. +

    +
    + Zone d’import et d’export dans le Mode Documents +
    Image de la bibliothèque située à droite dans le logiciel.
    +
    +
    + + +
    +

    Organisez votre dossier Images

    +

    + Les captures d’écran ajoutées à la bibliothèque sont regroupées dans le dossier + Icône Images. + Vous pouvez créer des sous-dossiers via + Icône Nouveau dossier + (en bas de la bibliothèque), puis glisser-déposer vos images dans les différents dossiers créés. +

    + +
    + Organisation du dossier Images avec sous-dossiers +
    Exemple d’organisation et de classement d’images dans la bibliothèque.
    +
    + + +
    + + +
    +

    Ajoutez des images depuis votre ordinateur

    +

    + Vous pouvez importer vos propres fichiers image directement dans OpenBoard, comme illustré ci-dessous : +

    + +
    + Ajout d’images depuis l’ordinateur +
    Import d’une image locale dans OpenBoard.
    +
    +
    + + +
    +

    Ajoutez des images depuis le Web

    +

    + Vous pouvez également rechercher des images libres de droit via les moteurs de recherche intégrés, + situés dans le dossier Recherche Web + Icône Images. +

    + +
    + Ajout d’images depuis un moteur de recherche intégré +
    Exemple de recherche et d’ajout d’images depuis le Web.
    +
    + + +
    +
    + +
    + +
    + diff --git a/resources/startupHints/locales/fr/9.html b/resources/startupHints/locales/fr/9.html index d3a501394..d40c27113 100644 --- a/resources/startupHints/locales/fr/9.html +++ b/resources/startupHints/locales/fr/9.html @@ -1,47 +1,99 @@ - - + + - - Interactivités - - - - + + Interactivités + + + + -
    -

    Interactivités

    -
    -
    - Pour les plus jeunes élèves, vous trouverez un ensemble d'applications personnalisables qui leur sont dédiées. -

    Les exercices interactifs d'OpenBoard

    -

    Avec ces interactivités, vous pouvez créer différents types d'exercices. Il peut s'agir de catégorisation, calcul mental, mémorisation, etc.

    -

    Les interactivités sont situées dans la bibliothèque OpenBoard : cliquez sur pour les trouver.

    - -

    Exemple

    -

    Nous allons créer un exercice utilisant l'interactivité "Categorize pictures" (traduction : Catégorisez des images) :

    - Essayez ! Déplacez cette fenêtre sur un côté et reproduisez l'exemple sur le Tableau ! -

    Tout d'abord, glissez-déposez l'interactivité sur le tableau, et cliquez sur "Modifier"

    -

    Ensuite, changez les noms des catégories selon vos besoins :

    -
    - - Vous pouvez ajouter ou supprimer des catégories en utilisant les icônes + et - - -

    Ensuite, ajoutez les images correspondant à chaque catégorie.

    -
    - -

    Enfin, cliquez sur "Afficher" pour voir le résultat et faire l'exercice.

    -
    - - Vous pouvez relancer l'exercice en cliquant sur l'icône "Recharger". -
    -
    - -
    + + + +
    + +
    +

    Des exercices interactifs, simples à personnaliser

    +

    + Pour les plus jeunes élèves (et pas seulement), OpenBoard fournit un ensemble + d’interactivités personnalisables : catégorisation, calcul mental, mémorisation, etc. +

    +

    + Elles sont accessibles dans la bibliothèque : cliquez sur + Icône Interactivités. +

    +
    + + +
    +

    Exemple : « Categorize Pictures »

    +

    + Créons un exercice avec l’interactivité + Categorize pictures (catégoriser des images) : + Vignette Categorize Pictures. +

    + + + +

    1) Placer l’interactivité et ouvrir l’éditeur

    +

    + Glissez-déposez l’interactivité sur le Tableau, puis cliquez sur Modifier. +

    + +

    2) Nommer les catégories

    +

    + Renommez les catégories selon vos besoins. Vous pouvez aussi + ajouter ou supprimer des catégories avec les icônes « + » et « − ». +

    + +
    + Édition des catégories de l’interactivité +
    Édition des catégories : ajout, suppression, renommage.
    +
    + +

    3) Ajouter les images

    +

    + Ajoutez les images correspondant à chaque catégorie (glisser-déposer, sélection depuis la bibliothèque, etc.). +

    + +
    + Ajout d’images aux catégories +
    Associer des images aux catégories définies.
    +
    + +

    4) Afficher et faire l’exercice

    +

    + Cliquez sur Afficher pour lancer l’activité en mode élève. +

    + +
    + Exécution de l’exercice Categorize Pictures +
    Exécution de l’exercice : déplacer les images dans la bonne catégorie.
    +
    + + +
    +
    + +
    +
    diff --git a/resources/startupHints/locales/fr/css/dark.css b/resources/startupHints/locales/fr/css/dark.css deleted file mode 100644 index 34ded372a..000000000 --- a/resources/startupHints/locales/fr/css/dark.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - background-color: #3a3a3a; - color: #e0e0e0; -} - -.title { - color: #8ba3d7; -} diff --git a/resources/startupHints/locales/fr/css/light.css b/resources/startupHints/locales/fr/css/light.css deleted file mode 100644 index 4e1f81f0e..000000000 --- a/resources/startupHints/locales/fr/css/light.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - background-color: #edf2f7; - color: #1f2937; -} - -.title { - color: #5f7faa; -} diff --git a/resources/startupHints/locales/fr/css/style.css b/resources/startupHints/locales/fr/css/style.css deleted file mode 100644 index de0ecb4d5..000000000 --- a/resources/startupHints/locales/fr/css/style.css +++ /dev/null @@ -1,36 +0,0 @@ -*{ - font-family: Arial, Helvetica, sans-serif; -} - -.title -{ - width:100%; - color: #6682b5; - text-align: center; -} - -.file-extension -{ - background: lightgrey; -} - -.image -{ - text-align:center; -} - -.image img -{ - max-width: 600px; -} - -.icon -{ - vertical-align: middle; -} - -.tip -{ - font-style: italic; - font-size: 0.8rem; -} diff --git a/resources/startupHints/locales/fr/error.html b/resources/startupHints/locales/fr/error.html index a456d7cdb..a24888b69 100644 --- a/resources/startupHints/locales/fr/error.html +++ b/resources/startupHints/locales/fr/error.html @@ -1,15 +1,20 @@ - - - - - erreur - - - - - -

    Quelque chose s'est mal passé ... -Vérifier l'existence de vos conseils dans le dossier -/Resources/startupHints/ …

    - - + + + + + Erreur + + + + + +
    +

    Erreur de chargement

    +

    + Quelque chose s'est mal passé. + Vérifiez la présence des pages d'astuces dans le dossier + /Resources/startupHints/. +

    +
    + + diff --git a/resources/startupHints/locales/hr/1.html b/resources/startupHints/locales/hr/1.html index 44eed3250..ff6e6f57c 100644 --- a/resources/startupHints/locales/hr/1.html +++ b/resources/startupHints/locales/hr/1.html @@ -1,32 +1,95 @@ - - + + - - Savjeti - - - - + + Dobrodošli + + + - -
    -

    Dobro došao, dobro došla u OpenBoard

    -
    -
    -
    -
    -

    Ovdje se nalaze savjeti koji pomažu naučiti koristiti OpenBoard.

    -

    OpenBoard je interaktivna ploča koju su dizajnirali učitelji za učitelje. Postoje četiri modusa:ploča, radna površina, dokumenti i web.

    -

    Krenimo s prvim i najvažnijim: modus ploče.

    -
    -
    - Dijalog „Savjeti” možeš otvoriti u bilo kojem trenutku pomoću gumba (the OpenBoard menu) u OpenBoard izborniku -
    + + +
    + + +

    + Evo nekoliko savjeta i trikova koji će vam pomoći da se upoznate s OpenBoard. +

    + +

    + OpenBoard je interaktivna ploča koju su dizajnirali učitelji za učitelje. + Nudi cetiri nacina koji pokrivaju najcesce potrebe u nastavi. +

    + +
    +

    4 načina OpenBoard

    + +
    + +
    +

    Počnimo s prvim i najvažnijim: Nacin Ploca.

    +
    + + +
    + +
    + +
    + + - diff --git a/resources/startupHints/locales/hr/10.html b/resources/startupHints/locales/hr/10.html index 68cd1afc4..64f75e070 100644 --- a/resources/startupHints/locales/hr/10.html +++ b/resources/startupHints/locales/hr/10.html @@ -1,49 +1,95 @@ - - - - Programi - - - - - - - -
    -

    Programi

    -
    -
    -

    OpenBoard pruža nekoliko programa i alata. Možeš im pristupiti pritiskom na u OpenBoard biblioteci

    -

    Standardni programi

    -

    Pronaći ćeš geometrijske alate, kalkulator, Google kartu, generator QR koda i još više! Kombiniraj ih za stvaranje poticajnih nastava!

    -
    -

    Stvaranje programa

    -

    Kao što je objašnjeno u odjeljku Web modusa, programi s web stranica se mogu izraditi koristeći interni navigator ili kopiranjem i umetanjem URL adresa na ploču.

    -

    Na ovaj način možeš podržati svoju nastavu moćnim online alatima izravno na ploči! Primjeri zanimljivih programa koje se mogu stvoriti (povuci i ispusti ih na ploču za testiranje!):

    - - -

    … i još puno više!

    - - Trebaš moćniji kalkulator od onog koji nudi OpenBoard? Misli na to da možeš stvoriti vlastite programe! Jednostavno povuci i ispusti sljedeću poveznicu na ploču: https://ti89-simulator.com/ -
    -
    - -
    - - - + + + + + Prijave + + + + + + + + + + +
    + +
    +

    Pristup aplikacijama

    +

    + OpenBoard nudi drugačije aplikacije i alate. + Pronađite ih u knjižnici klikom na + Ikona aplikacija. +

    +
    + + +
    +

    Zadane aplikacije

    +

    + Pronaći ćete geometrijske alate, kalkulator, Google karte, generator QR koda i još mnogo toga. + Kombinirajte ih kako biste stvorili privlačna obrazovna iskustva! +

    + +
    + Primjer korištenja integriranih aplikacija +
    Primjer korištenja ugrađenih aplikacija OpenBoard.
    +
    +
    + + +
    +

    Izradite vlastite aplikacije

    +

    + Kao što je objašnjeno u odjeljku Nacin Web, možete izraditi aplikaciju sa stranice, + pomoću internog preglednika ili kopiranjem i lijepljenjem URL-a na ploču. +

    +

    + To vam omogućuje da poboljšate svoje tečajeve moćnim online alatima, koji se mogu koristiti izravno u OpenBoard. + Evo nekoliko zanimljivih primjera (povucite i ispustite veze na ploču da ih testirate): +

    + + + +

    ...i mnogo više!

    + + +
    +
    + +
    + +
    + + + + + diff --git a/resources/startupHints/locales/hr/11.html b/resources/startupHints/locales/hr/11.html index a16f22e42..04aa87f4d 100644 --- a/resources/startupHints/locales/hr/11.html +++ b/resources/startupHints/locales/hr/11.html @@ -1,44 +1,90 @@ - - - - Snimanje videa - - - - - - - -
    -

    Snimanje videa

    -
    -
    -

    Snimanje nastave

    -

    OpenBoard omogućuje snimanja videa nastave.

    -

    Vrlo korisno za dijeljenje dodatnih vježbi ili informacija putem videa ili za snimanje nastave za učenike koji nisu prisutni.

    - - U modusu ploče se alatne trake i palete neće vidjeti u videu! Isto vrijedi i za web modus, gdje će se na snimci vidjeti samo trenutačna kartica. - -

    Otvori ovaj alat ovako:

    -
    - -

    U donjem desnom kutu ploče će se pojaviti sljedeće sučelje:

    -
    - -

    Pritisni crveni gumb za pokretanje snimanja.

    - - Postavke se mogu prilagoditi pritiskom na . Tamo se nalaze postavke za zvuk (odaberi mikrofon ili ništa), postavke za video (razlučivost videa) i opcije za objavljivanje - -

    Nakon što je snimanje gotovo, snimka će se automatski spremiti na radnu površinu računala

    -
    - -
    -
    - -
    - - + + + + + Video snimanje + + + + + + + + + + +
    + +
    +

    Snimite svoj tečaj

    +

    + OpenBoard vam omogućuje spremanje audio i video vašeg tečaja. + Idealno za dijeljenje dodatnih vježbi, objavljivanje kratkog isječka s objašnjenjem ili + učiniti tečaj dostupnim odsutnim studentima. +

    + + +
    + + +
    +

    Pristupite alatu za registraciju

    +

    Otvorite alat za izrezivanje kao što je prikazano u nastavku:

    + +
    + Otvaranje alata za video snimanje u OpenBoard +
    Brzi pristup alatu za registraciju sa sučelja OpenBoard.
    +
    +
    + + +
    +

    Upravljačko sučelje

    +

    Sučelje se pojavljuje u donjem desnom kutu tablice:

    + +
    + Sučelje snimača (kontrole dolje desno) +
    + +

    Kliknite na crveni gumb za početak snimanja.

    + + +
    + + +
    +

    Završite i oporavite videozapis

    +

    + Nakon što je snimanje završeno, video se automatski pokreće spremljeno na radnu površinu vašeg računala. +

    + +
    + Završite snimanje i spremite video na radnu površinu +
    Zaustavite snimanje i video datoteka dostupna na radnoj površini.
    +
    +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/hr/12.html b/resources/startupHints/locales/hr/12.html index 077f10287..28c0523ae 100644 --- a/resources/startupHints/locales/hr/12.html +++ b/resources/startupHints/locales/hr/12.html @@ -1,42 +1,94 @@ - - - - Favoriti - - - - - - - -
    -

    Favoriti

    -
    -
    -

    Dodavanje OpenBoard dokumenata u favorite

    -

    OpenBoard verzija 1.7 omogućuje dodavanje OpenBoard dokumenata u favorite!

    -

    Idi u modus dokumenata, odaberi jedan dokument i pritisni na u alatnoj traci dokumenata.

    - -
    - -

    Brzo prebacivanje s jednog dokumenta na drugi

    -

    Omiljeni dokumenti će se pojaviti u OpenBoard biblioteci pod
    - Svaki OpenBoard dokument () se može povući i ispustiti na ploču!

    -
    - - Koristi traku za pretraživanje na dnu OpenBoard biblioteke za brzo pronalaženje dokumenta na osnovi imena - -

    Nedavno otvoreni dokumenti

    -

    Svaki dokument koji se otvori privremeno se dodaje u favorite za brzo prebacivanje između dokumenata, bez da moraju biti izričito označeni kao favoriti.

    -
    - Ako nedavno otvoreni dokument želiš trajno dodati u favorite, to možeš obaviti putem OpenBoard biblioteke: odaberi ga i pritisni na -
    -
    - -
    - - + + + + + Omiljeni dokumenti + + + + + + + + + + +
    + +
    +

    Dodajte OpenBoard dokumenata u favorite

    +

    + Uveden u verzija 1.7, ova vam funkcija omogućuje dodavanje vaših OpenBoard dokumenata + u favoriti. +

    +

    + Da biste to učinili, idite na Nacin Dokumenti, odaberite dokument i kliknite + Ikona Dodaj u favorite + na alatnoj traci. +

    + +
    + Dodavanje OpenBoard dokumenta u favorite + +
    +
    + + +
    +

    Brzo prijeđite s jednog dokumenta na drugi

    +

    + Vaši omiljeni dokumenti pojavljuju se u knjižnica OpenBoard, u nastavku + Ikona favorita. +

    +

    + Svaki omiljeni dokument + Ikona dokumenta OpenBoard + može se povući i ispustiti izravno na stol. +

    + +
    + Pregledavanje favorita u biblioteci OpenBoard +
    + + + +
    + + +
    +

    Nedavno otvoreni dokumenti

    +

    + Svaki otvoreni dokument privremeno se dodaje u favorite, radi brzog prebacivanja s jednog na drugi + tijekom iste sesije, bez potrebe da ih izričito označite. +

    + +
    + Primjer nedavno otvorenih dokumenata u OpenBoard + +
    + + +
    +
    + +
    +
    + + diff --git a/resources/startupHints/locales/hr/2.html b/resources/startupHints/locales/hr/2.html index 8fbf1f853..831628e93 100644 --- a/resources/startupHints/locales/hr/2.html +++ b/resources/startupHints/locales/hr/2.html @@ -1,53 +1,122 @@ - - - - Modus ploče - - - - - - - -
    -

    Modus ploče

    -
    -
    -

    Paleta alata

    -

    Paleta alata sadrži osnovne alate za rad na ploči.

    -
    - -

    Sadrži pisaljku (), gumicu () i marker (). OpenBoard također sadrži daljnje funkcije koje klasična ploča ne pruža:

    -
      -
    • je selektor. Omogućuje biranje objekata kao i interakciju s njima.
    • -
    • je čarobni prst. Omogućuje pomicanje objekata ili interakciju s njima bez da se moraju odabrati.
    • -
    • je ruka. Omogućuje kretanje po stranici. Vrlo korisno u kombinaciji sa zumiranjem!
    • -
    • omogućuje zumiranje. Odaberi vrstu zumiranja i pritisni stranicu na koju želiš primijeniti zumiranje!
    • -
    • je laserski pokazivač. Koristno za označavanje elemenata na ploči bez interakcije s njima.
    • -
    • se koristi za jednostavno crtanje ravnih crta.
    • -
    • je alat za pisanje teksta pomoću tipkovnice umjesto pisaljke.
    • -
    - - Zumiranje možeš preciznije odrediti pomoću miša! Koristi Ctrl/Cmd + kotačić miša za preciznije zumiranje! - - -

    Alatna traka ploče

    -

    Alatna traka ploče omogućuje pored ostalog mijenjanje boje i debljine pisaljke ili markera.

    -
    - -

    Omogućuje mijenjanje pozadine ploče pritiskom na

    -
    - -

    Sadrži gumbe za poništavanje/ponavljanje radnji, stvaranje i kretanje po stranicama, brisanje cijele ploče …

    - - Dijelove ploče možeš preciznije obrisati dugim pritiskom na the erase icon. Neke skrivene funkcije i na the erase icon! -
    -
    - -
    - - + + + + + Nacin Ploca + + + + + + + + +
    + +
    +

    Paleta olovki

    +

    + Paleta olovki vam daje pristup osnovnim alatima kada radite na bijeloj ploči. +

    + +
    + OpenBoard paleta stilusa +
    + +

    + Tamo ćete pronaći olovku + Olovka, + guma + Gumica za brisanje + i highlighter + Highlighter. + OpenBoard također pruža značajke koje tradicionalna pametna ploča ne može: +

    + +
      +
    • + + Selektor : odabir i interakcija s objektima. +
    • +
    • + + Čarobni prst : pomicanje/interakcija bez prethodnog odabira. +
    • +
    • + + Ruka : pomicanje stranice (vrlo korisno u kombinaciji sa zumiranjem). +
    • +
    • + + + Zumiraj / Smanji : Kliknite gdje želite primijeniti efekt nakon što ga odaberete. +
    • +
    • + + Laserski pokazivač : pokažite na elemente bez interakcije s njima. +
    • +
    • + + Linija : lako crtajte ravne linije. +
    • +
    • + + Tekst : umetnite tekstualni okvir za tipkanje na tipkovnici. +
    • +
    + + +
    + + +
    +

    Stolna traka

    +

    + Traka tablice omogućuje vam promjenu boja i/ili veličina između ostalog olovka i highlighter. +

    + +
    + OpenBoard traka tablice +
    + +

    + Također možete promijeniti pozadina stola klikom na + Promjena pozadine. +

    + +
    + Primjer mijenjanja pozadine stola +
    + +

    + Dostupne su i druge funkcije: poništiti/ponoviti, stvarati stranice, kretati se između stranica, čistiti tablicu itd. +

    + + +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/hr/3.html b/resources/startupHints/locales/hr/3.html index fe94a11f8..e23f1e462 100644 --- a/resources/startupHints/locales/hr/3.html +++ b/resources/startupHints/locales/hr/3.html @@ -1,35 +1,74 @@ - - - - Modus radne površine - - - - - - - -
    -

    Modus radne površine

    -
    -
    -

    Interakcija s drugim programima

    -

    Modus radne površine omogućuje interakciju s računalom i drugim programima, zadržavajući OpenBoard u prednjem planu!

    -

    Jednostavno pritisni sljedeću ikonu:

    -
    -
    Koristi selektor () za interakciju s radnom površinom i drugim programima.
    -

    Dodavanje pribilješki programu ili web stranici

    -
    Pribilješke se mogu dodati bilo kojem programu koristeći pisaljku () ili marker ().
    -
    - - Pristupi daljnjim opcijama za the pen, the marker i the eraser dugim pritiskom na ikonu ili pritiskom na malu crnu strelicu. -
    -
    - -
    - - + + + + + Nacin Radna Povrsina + + + + + + + + + +
    + +
    +

    Interakcija s drugim aplikacijama

    +

    + Opcija Uredski način rada omogućuje vam interakciju s vašim operativnim sustavom i softverom, + zadržavajući OpenBoard alate na vrhu. +

    +

    Jednostavno kliknite na sljedeću ikonu:

    + +
    + Ikona za aktiviranje Nacin Radna Povrsina +
    + +

    + Koristite selektor + Selektor + za interakciju s radnom površinom i drugim aplikacijama. +

    +
    + + +
    +

    Označite aplikacije ili web stranice

    +

    + Možete označiti bilo koji softver s olovka + Olovka + ili marker + Marker. +

    + +
    + Označavanje aplikacije u Nacin Radna Povrsina +
    Primjer anotacije na web stranici.
    +
    + + +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/hr/4.html b/resources/startupHints/locales/hr/4.html index 1ec341090..36fb32411 100644 --- a/resources/startupHints/locales/hr/4.html +++ b/resources/startupHints/locales/hr/4.html @@ -1,37 +1,79 @@ - - - - Modus dokumenata - - - - - - - -
    -

    Modus dokumenata

    -
    -
    -

    OpenBoard sadrži sustav za upravljanje dokumentima. Jednostavno pritisni

    -
    - -

    Stvaranje mape i organiziranje rada

    -

    Mapa se može stvoriti pritiskom na ikonu „Nova mapa”. Upiši ime za mapu te povuci i ispusti dokumente u mapu. Tehnika povuci i ispusti se može koristiti i za premještanje cijele mape u jednu drugu mapu.

    -
    - -

    Bartanje stranicama

    -

    OpenBoard dokument može sadržati više stranica. Mogu se duplicirati, premjestiti u smeće ili u jedan drugi dokument. Nove stranice se mogu stvoriti i iz mapa sa slikama, …

    -
    - - Imaj na umu da se dostupne radnje aktualiziraju prema onome što je odabrano -
    -
    - -
    - - + + + + + Nacin Dokumenti + + + + + + + + + +
    + +
    +

    Pristupite upravitelju dokumenata

    +

    + OpenBoard nudi a upravitelj dokumenata. Kliknite na + Ikona dokumenata + da ga otvorim. +

    +
    + Pogled upravitelja dokumenata +
    +
    + + +
    +

    Stvorite mape i organizirajte svoj rad

    +

    + Stvorite mapu putem + Nova mapa, + ime, onda povuci i ispusti svoje dokumente unutra. + Isto tako, možete premjestiti cijelu mapu u drugu. +

    +
    + Stvaranje i organiziranje datoteka +
    Primjer izrade i organiziranja mapa.
    +
    +
    + + +
    +

    Upravljanje stranicama

    +

    + Dokument OpenBoard može sadržavati nekoliko stranica. Iz Nacin Dokumenti možete: +

    +
      +
    • Duplicirane stranice
    • +
    • Pošaljite ih u smeće
    • +
    • Kopirajte ih u drugi dokument
    • +
    • Stvorite nove stranice iz mape slika
    • +
    +
    + Primjeri akcija na stranicama +
    Primjer obrade dokumenata.
    +
    + + +
    +
    + +
    +
    + + diff --git a/resources/startupHints/locales/hr/5.html b/resources/startupHints/locales/hr/5.html index 8def374ba..70188ab92 100644 --- a/resources/startupHints/locales/hr/5.html +++ b/resources/startupHints/locales/hr/5.html @@ -1,44 +1,105 @@ - - - - Modus dokumenata - - - - - - - -
    -

    Modus dokumenata

    -
    -
    -

    U ovom se modusu nalaze dvije važne funkcije: uvoz i izvoz.

    -
    - -

    Uvoz

    -

    Omogućuje uvoz PDF datoteka (.pdf), slika (.png, .jpg), OpenBoard dokumenata (.ubz) ili OpenBoard mapa (.ubx) pritiskom na

    -
    -

    OpenBoard dokument (.ubz) se može otvoriti i dvostrukim pritiskom na dokument. Ako OpenBoard još nije pokrenut, program će se pokrenuti i dokument će se uvesti (ili će se zatražiti zamjena ako već postoji).

    - Također je moguće uvesti više elemenata odjednom, bez potrebe za višestrukim pritiskom na . -

    Izvoz

    -

    Omogućuje izvoz OpenBoard dokumenta u PDF ili UBZ format kao i izvoz OpenBoard mape u UBX format. Na taj način je moguće: -

      -
    • Spremiti rad obavljen tijekom predavanja i dijeliti ga s učenicima koji nisu prisutni
    • -
    • Dijeliti ga s drugim učiteljima ili ga spremiti na USB uređaj i otvoriti ga na jednom drugom računalu
    • -
    • Uvesti domaću zadaću učenika u PDF formatu, dodati pribilješku te izvesti i učeniku poslati komentirani PDF
    • -
    -

    -
    - - Izvezi sve tvoje dokumente biranjem mape „Moji dokumenti” prije pritiskanja gumba za izvoz kako bi se izvezli kao UBX datoteke, a zatim ih uvezi na jednom drugom računalu. To je također dobar način za spremanje sigurnosne kopije tvog rada! -
    -
    - -
    - - + + + + + + Uvoz i izvoz + + + + + + + + + + +
    + +
    +

    Uvoz i izvoz

    +

    + U ovom načinu rada imate dvije bitne značajke: uvoz I izvoz. +

    +
    + Područje uvoza i izvoza u Nacin Dokumenti + +
    +
    + + +
    +

    Uvoz sadržaja

    +

    + Možete uvesti datoteke PDF (.pdf), + od slike (.png, .jpg), + od dokumenti OpenBoard (.ubz) ili + OpenBoard mapa (.ubx) klikom na + Ikona uvoza. + +

    + +
    + Primjer uvoza datoteka u OpenBoard +
    Primjer uvoza datoteka u OpenBoard.
    +
    + +

    + Također možete uvesti OpenBoard dokument (.ubz) u + dupli klik na njemu iz vašeg sustava. OpenBoard pokrenut će se ako je potrebno i + će ponuditi uvoz (ili zamjenu ako već postoji). +

    + + +
    + + +
    +

    Izvezite svoje dokumente

    +

    + Možete izvesti a dokument OpenBoard u formatu PDF Ili UBZ, + i a mapa OpenBoard u formatu UBX. Na primjer: +

    +
      +
    • Zabilježite rad obavljen tijekom lekcije i podijelite ga s odsutnim učenikom.
    • +
    • Podijelite s drugim učiteljima ili spremite na USB ključ za uvoz na drugo mjesto.
    • +
    • Uvezite studentov rad kao PDF, označite ga, zatim izvezite komentirani PDF za ponovno slanje.
    • +
    + +
    + Primjeri izvoza dokumenata i mapa OpenBoard +
    Primjer izvoza datoteka iz OpenBoard.
    +
    + + +
    +
    + +
    +
    + + + diff --git a/resources/startupHints/locales/hr/6.html b/resources/startupHints/locales/hr/6.html index 6bda41029..cac5678bd 100644 --- a/resources/startupHints/locales/hr/6.html +++ b/resources/startupHints/locales/hr/6.html @@ -1,43 +1,96 @@ - - - - Web modus - - - - - - - -
    -

    Web modus

    -
    -
    - Web modus je interni navigator s dodatnim funkcijama. -

    Korištenje internog navigatora

    -

    Interni navigator omogućuje pregledavanje interneta bez potrebe za smanjivanjem prozora ili zatvaranjem OpenBoarda. Pored toga omogućuje snimanja dijela ekrana ili stvaranje programa iz web stranica koje se mogu dodati na ploču!

    - -
    - -

    Stvaranje programa

    -

    Program se može stvoriti s bilo kojeg mjesta i dodati na ploču te s njom interagirati kao sa standardnim programima.

    -

    Otvori web stranicu koju želiš snimiti, pritisni na Capture Web Content te potvrdi izradu pritiskom na „Stvori program”.

    -
    - -

    Kad je program stvoren, on se automatski sprema u OpenBoard biblioteku, tako da se može koristiti u bilo kojem dokumentu. Programi se nalaze u mapi s programima koja se zove „Web”.

    - -
    - -

    Korištenje eksternog navigatora

    -

    Označavanjem odgovarajuće opcije u postavkama može se koristiti i eksterni navigator. Tada će se pritiskom na web ikonu pokrenuti favorizirani navigator u modusu radne površine.

    - Koristeći eksterni navigator, i dalje ćeš moći stvarati programe s web stranice. Kopiraj URL-adresu u adresnu traku navigatora, vrati se na ploču i umetni je! -
    -
    - -
    - - + + + + + Nacin Web + + + + + + + + + +
    + +
    +

    Integrirani preglednik

    +

    + THE Nacin Web je interni preglednik za OpenBoard koji dodaje pregledniku + klasične, vrlo praktične značajke za učionicu. +

    +

    + Omogućuje vam pregledavanje interneta bez napuštanja OpenBoard, za snimanje sadržaja (djelomičnog ili + preko cijelog zaslona) i čak stvarati aplikacije s web stranica za + ponovno koristiti u svojim dokumentima. +

    + +
    + Primjer korištenja ugrađenog preglednika OpenBoard +
    +
    + + +
    +

    Napravite aplikaciju sa stranice

    +

    + S bilo kojeg mjesta možete generirati a primjena dodati ga + na ploči i komunicirati s njim kao sa zadanim aplikacijama. +

    +

    + Idite na željenu stranicu, kliknite na + Ikona Dodaj u knjižnicu + zatim potvrdite odabirom Napravite aplikaciju. +

    + +
    + Izrada web aplikacije iz ugrađenog preglednika +
    Izrada aplikacije iz web moda.
    +
    + +

    + Jednom kreirana aplikacija se automatski sprema u + knjižnica OpenBoard. Naći ćete ga ispod Aplikacije > Web + i može ga ponovno koristiti u bilo kojem dokumentu. +

    + +
    + Aplikacija spremljena u biblioteku, web mapu +
    Pronađite aplikaciju stvorenu u svojoj knjižnici.
    +
    +
    + + +
    + +

    + Možete izabrati da otvorite veze u a vanjski preglednik provjerom + odgovarajuću opciju u postavkama. Kliknite na + Nacin Web ikona + će zatim pokrenuti vaš omiljeni preglednik kao Nacin Radna Povrsina. +

    + + +
    + +
    + +
    + +
    + + + diff --git a/resources/startupHints/locales/hr/7.html b/resources/startupHints/locales/hr/7.html index 7a8a99bc8..cfcbe9ec0 100644 --- a/resources/startupHints/locales/hr/7.html +++ b/resources/startupHints/locales/hr/7.html @@ -1,49 +1,102 @@ - - - - Snimanje ekrana - - - - - - - -
    -

    Snimanje ekrana

    -
    -
    - Jedna od najjednostavnijih ali vrlo korisnih OpenBoard funkcija je snimanje ekrana, što omogućuje snimanje bilo kojeg određenog stanja ploče tijekom nastave. -

    U modusu ploče

    -

    Tražithe screen capture icon u paleti alata. Pritisni ikonu i odaberi područje za snimanje. Nakon toga postoje tri mogućnosti:

    -
      -
    • Dodaj u trenutačnu stranicu
    • -
    • Dodaj u novu stranicu
    • -
    • Dodaj u biblioteku(dodaje snimku u mapu „Slike” kako bi se mogla ponovo koristiti u bilo kojem trenutku)
    • -
    - -

    Primjer cijelog postupka:

    -
    - - Paleta alata, prikaz minijatura te OpenBoard biblioteka se neće snimiti pri odabiru sadržaja! - -

    U modusu radne površine

    -

    Za snimanje vlastitog rada u drugim programima, isto se može obaviti u modusu radne površine. Prijeđi u modus radne površine pritiskom na

    -

    Prikazat će se dvije ikone: za snimanje cijelog ekrana i za snimanje dijelova ekrana. Kao u modusu ploče, morat ćeš odabrati mjesto za ispuštanje snimke

    - -

    Prikaz cijelog postupka

    -
    - - -

    U web modusu

    -

    Isti postupak je dostupan u web modusu, gdje ja moguće snimiti dio ekrana ili trenutačnu karticu pomoću

    -
    -
    - -
    - - + + + + + Snimka zaslona + + + + + + + + + +
    +
    +

    Jednostavna i vrlo korisna značajka

    +

    + Snimka zaslona omogućuje vam stvaranje a trenutak stanje ploče (ili vašeg zaslona) + tijekom tečaja, za arhiviranje, dijeljenje ili ponovno korištenje sadržaja. +

    +
    + + +
    +

    U Nacin Ploca

    +

    + U paleti olovke kliknite + Ikona područja snimanja (Nacin Ploca), + zatim odaberite područje za snimanje. Zatim možete odabrati: +

    +
      +
    • Dodaj trenutnoj stranici
    • +
    • Dodaj na novu stranicu
    • +
    • + Dodaj u knjižnicu — snimak se sprema u mapu Slike + za kasniju ponovnu upotrebu. +
    • +
    + +
    + Primjer snimanja područja u Nacin Ploca +
    Primjer ugradnje snimke zaslona u OpenBoard.
    +
    + + +
    + + +
    +

    U Nacin Radna Povrsina

    +

    + Prebacite se na Nacin Radna Povrsina putem + Nacin Radna Povrsina ikona + za snimanje drugog softvera. +

    +

    Dostupne su dvije opcije:

    +
      +
    • + Ikona snimanja zaslona + Snimanje cijelog zaslona +
    • +
    • + Ikona područja snimanja + Snimanje područja +
    • +
    +

    Kao u Nacin Ploca, odaberite gdje ćete dodati snimanje.

    + +
    + Primjer snimanja u Nacin Radna Povrsina +
    Cijeli ili djelomični snimak zaslona u Nacin Radna Povrsina.
    +
    +
    + + +
    +

    U Nacin Web

    +

    + U Nacin Web možete uhvatiti područje ekrana ili + snimi aktivnu karticu iz preglednika sa + Ikona kartice za snimanje. +

    +
    +
    + +
    +
    + + + diff --git a/resources/startupHints/locales/hr/8.html b/resources/startupHints/locales/hr/8.html index d55ad7908..4caa1a76e 100644 --- a/resources/startupHints/locales/hr/8.html +++ b/resources/startupHints/locales/hr/8.html @@ -1,41 +1,102 @@ - - - - Slike - - - - - - - -
    -

    Slike

    -
    -
    - OpenBoard omogućuje pristup slikama na nekoliko načina. -

    Organiziranje mape „Slike”

    -

    Snimke ekrana koje se dodaju u biblioteku spremaju se u mapu „Slike”:
    Mape se mogu stvoriti koristeći na dnu biblioteke. Zatim povuci i ispusti slike u stvorene mape.

    -
    - - Bez obzira gdje se nalaziš u OpenBoard biblioteci, slike koje dodaš će se automatski smjestiti u mapu „Slike”. - -

    Dodavanje slika iz računala

    -

    Prikaz dodavanja slika koja su spremljena na računalu:

    -
    - -

    Dodavanje slika iz tražilica

    -

    Besplatne slike možeš tražiti i dodati na ploču koristeći tražilice koje se nalaze u mapi „Web pretraga”:

    -
    - - Umjesto korištenja tehnike povuci i ispusti, jednostavno pritisni sliku koju je pronašla tražilica za prikaz detalja slike i pronađi opciju za dodavanje slike u biblioteku, bez dodavanja slike u trenutačni dokument. Korisno za pripremanje nastave! -
    -
    - -
    - - + + + + + Slike + + + + + + + + + +
    +
    +

    Pristupite svojim slikama i organizirajte ih

    +

    + U OpenBoard možete pristupiti i dodavati slike na različite načine od svojih knjižnica. Potonji se nalazi na desnoj strani ekrana. Ovdje također možete pohraniti zvukove, video zapise i pronaći različite aplikacije. +

    +
    + Područje uvoza i izvoza u Nacin Dokumenti +
    Slika knjižnice koja se nalazi desno u softveru.
    +
    +
    + + +
    +

    Organizirajte svoju mapu Slike

    +

    + Snimke zaslona dodane u biblioteku grupirane su u mapi + Slike ikona. + Možete stvarati podmape preko + Nova ikona mape + (na dnu biblioteke), zatim povucite i ispustite svoje slike u različite stvorene mape. +

    + +
    + Organiziranje mape Slike s podmapama +
    Primjer organizacije i klasifikacije slika u knjižnici.
    +
    + + +
    + + +
    +

    Dodajte slike sa svog računala

    +

    + Možete uvesti vlastite slikovne datoteke izravno u OpenBoard, kao što je prikazano u nastavku: +

    + +
    + Dodavanje slika s računala +
    Uvoz lokalne slike u OpenBoard.
    +
    +
    + + +
    +

    Dodajte slike s weba

    +

    + Također možete tražiti slike bez naknade putem integriranih tražilica, + koji se nalazi u mapi Web pretraživanje + Slike ikona. +

    + +
    + Dodavanje slika iz integrirane tražilice +
    Primjer pronalaženja i dodavanja slika s weba.
    +
    + + +
    +
    + +
    + +
    + + + diff --git a/resources/startupHints/locales/hr/9.html b/resources/startupHints/locales/hr/9.html index ab8576bcf..6fa8d5ba4 100644 --- a/resources/startupHints/locales/hr/9.html +++ b/resources/startupHints/locales/hr/9.html @@ -1,48 +1,99 @@ - - - - Interaktivnosti - - - - - - - -
    -

    Interaktivnosti

    -
    -
    - Za mlađe učenike postoji poseban skup prilagođenih programa. -

    Interaktivna vježba za OpenBoard

    -

    Pomoću ovih interaktivnosti mogu se izraditi različite vrste prilagođenih vježbi. To se može odnositi na kategorizaciju, računanje, pamćenje i tako dalje.

    -

    Interaktivnosti se nalaze u OpenBoard biblioteci: pronađi ih pritiskom na .

    - -

    Primjer

    -

    Kao primjer ćemo izraditi vježbu koristeći interaktivnost „Kategoriziraj sliku”:

    - Probaj! Pomakni ovaj dijalog na stranu i reproduciraj primjer na ploči! -

    Najprije povuci i ispusti interaktivnost na tvoju ploču i pritisni „Uredi”

    -

    Zatim promijeni imena kategorija prema svojim potrebama:

    -
    - - Kategorije možeš dodati ili izbrisati pomoću ikona + i - - -

    Zatim dodaj željene slike u odgovarajuću kategoriju.

    -
    - -

    Na kraju pritisni „Prikaz” za prikaz rezultata i izvođenje vježbe.

    -
    - - Vježbu možeš ponovo pokrenuti pomoću ikone „Učitaj ponovo”. - - -
    -
    - -
    - - + + + + + Interaktivnosti + + + + + + + + + + +
    + +
    +

    Interaktivne vježbe, jednostavne za personalizaciju

    +

    + Za najmlađe učenike (i ne samo), OpenBoard nudi set + odinteraktivnosti prilagodljiv: kategorizacija, mentalno računanje, pamćenje itd. +

    +

    + Dostupni su u knjižnica : kliknite na + Ikona interaktivnosti. +

    +
    + + +
    +

    Primjer: “Kategoriziraj slike”

    +

    + Kreirajmo vježbu s interaktivnošću + mačkaegorizirati slikaures (kategoriziraj slike): + Thumbnail Kategorizirajte slike. +

    + + + +

    1) Postavite interaktivnost i otvorite uređivač

    +

    + Povucite i ispustite interaktivnost na ploču, zatim kliknite Za izmjenu. +

    + +

    2) Imenujte kategorije

    +

    + Preimenujte kategorije prema potrebi. Možete također + dodati Ili IZBRISATI kategorije s ikonama "+" i "−". +

    + +
    + Uređivanje kategorija interaktivnosti +
    Uređivanje kategorija: dodavanje, brisanje, preimenovanje.
    +
    + +

    3) Dodajte slike

    +

    + Dodajte slike koje odgovaraju svakoj kategoriji (povuci i ispusti, odabir iz biblioteke itd.). +

    + +
    + Dodavanje slika u kategorije +
    Povežite slike s definiranim kategorijama.
    +
    + +

    4) Pokažite i napravite vježbu

    +

    + Kliknite na Prikaz za pokretanje aktivnosti u studentskom načinu rada. +

    + +
    + Izvođenje vježbe Kategoriziraj slike +
    Izvođenje vježbe: premjestite slike u odgovarajuću kategoriju.
    +
    + + +
    +
    + +
    +
    + + diff --git a/resources/startupHints/locales/hr/css/dark.css b/resources/startupHints/locales/hr/css/dark.css deleted file mode 100644 index 34ded372a..000000000 --- a/resources/startupHints/locales/hr/css/dark.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - background-color: #3a3a3a; - color: #e0e0e0; -} - -.title { - color: #8ba3d7; -} diff --git a/resources/startupHints/locales/hr/css/light.css b/resources/startupHints/locales/hr/css/light.css deleted file mode 100644 index 4e1f81f0e..000000000 --- a/resources/startupHints/locales/hr/css/light.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - background-color: #edf2f7; - color: #1f2937; -} - -.title { - color: #5f7faa; -} diff --git a/resources/startupHints/locales/hr/css/style.css b/resources/startupHints/locales/hr/css/style.css deleted file mode 100644 index de0ecb4d5..000000000 --- a/resources/startupHints/locales/hr/css/style.css +++ /dev/null @@ -1,36 +0,0 @@ -*{ - font-family: Arial, Helvetica, sans-serif; -} - -.title -{ - width:100%; - color: #6682b5; - text-align: center; -} - -.file-extension -{ - background: lightgrey; -} - -.image -{ - text-align:center; -} - -.image img -{ - max-width: 600px; -} - -.icon -{ - vertical-align: middle; -} - -.tip -{ - font-style: italic; - font-size: 0.8rem; -} diff --git a/resources/startupHints/locales/hr/error.html b/resources/startupHints/locales/hr/error.html index b5ad0101c..1c01b9e20 100644 --- a/resources/startupHints/locales/hr/error.html +++ b/resources/startupHints/locales/hr/error.html @@ -1,14 +1,20 @@ - - - - erreur - - - - - -

    Dogodila se greška … -Provjeri postojanje savjeta u datoteci -/Resources/startupHints/ …

    - - + + + + + Greška + + + + + +
    +

    Greška pri učitavanju

    +

    + Nešto nije u redu. + Provjerite prisutnost stranica sa savjetima u mapi + /Resursi/startupHints/. +

    +
    + + diff --git a/resources/startupHints/locales/it/1.html b/resources/startupHints/locales/it/1.html index 54e811ba3..1cb2f4404 100644 --- a/resources/startupHints/locales/it/1.html +++ b/resources/startupHints/locales/it/1.html @@ -1,32 +1,95 @@ - - + + - - Suggerimenti e consigli - - - - + + Benvenuto + + + - -
    -

    Benvenuti in OpenBoard

    -
    -
    -
    -
    -

    Ecco alcuni suggerimenti per aiutarti a familiarizzare con OpenBoard.

    -

    OpenBoard è una lavagna interattiva progettata da insegnanti, per insegnanti. Dispone di 4 modalità: Modalità Lavagna, Modalità Desktop, Modalità Documenti e Modalità Web.

    -

    Iniziamo con la prima e più importante: la Modalità Lavagna.

    -
    -
    - Puoi riaprire il dialogo "Suggerimenti e consigli" in qualsiasi momento, utilizzando il pulsante dedicato nel menu di OpenBoard (il menu di OpenBoard) -
    + + +
    + + +

    + Ecco alcuni suggerimenti per aiutarti a familiarizzare con OpenBoard. +

    + +

    + OpenBoard e una lavagna interattiva progettata da insegnanti, per insegnanti. + Offre quattro modalità complementari per coprire i tuoi usi in classe. +

    + +
    +

    Le 4 modalita di OpenBoard

    + +
    + +
    +

    Prima di tutto, e cosa più importante: Modalita Lavagna.

    +
    + + +
    + +
    + +
    + + - diff --git a/resources/startupHints/locales/it/10.html b/resources/startupHints/locales/it/10.html index dc63883da..cf2854aa8 100644 --- a/resources/startupHints/locales/it/10.html +++ b/resources/startupHints/locales/it/10.html @@ -1,50 +1,95 @@ - - - - Applicazioni - - - - - - - -
    -

    Applicazioni

    -
    -
    -

    OpenBoard dispone di diverse applicazioni e strumenti. Puoi accedervi cliccando su nella Libreria di OpenBoard

    -

    Applicazioni predefinite

    -

    Troverai strumenti geometrici, una calcolatrice, Google Map, un generatore di codici QR e altro ancora! Combinali per creare lezioni stimolanti!

    -
    -

    Crea applicazioni

    -

    Come spiegato nella sezione Modalità Web, puoi creare applicazioni da siti web, utilizzando il navigatore interno, o copiando e incollando gli URL sulla lavagna.

    -

    In questo modo, puoi supportare le tue lezioni con potenti strumenti online direttamente sulla lavagna! Ecco alcuni esempi di app interessanti da creare (Trascinale sulla lavagna per testarle!):

    - - -

    ... e molto altro ancora!

    - - Hai bisogno di una calcolatrice più potente di quella fornita da OpenBoard? Ricorda! Puoi creare le tue applicazioni! Trascina semplicemente il seguente link sulla lavagna: https://ti89-simulator.com/ -
    -
    - -
    - - - - + + + + + Applicazioni + + + + + + + + + + +
    + +
    +

    Accedere alle applicazioni

    +

    + OpenBoard offre diverse applicazioni e strumenti. + Le trovi nella libreria facendo clic su + Icona Applicazioni. +

    +
    + + +
    +

    Applicazioni predefinite

    +

    + Troverai strumenti geometrici, una calcolatrice, Google Maps, un generatore di QR code e molto altro. + Combinali per creare esperienze didattiche coinvolgenti. +

    + +
    + Esempio di utilizzo delle applicazioni integrate +
    Esempio di utilizzo delle applicazioni integrate di OpenBoard.
    +
    +
    + + +
    +

    Crea le tue applicazioni

    +

    + Come spiegato nella sezione Modalita Web, puoi creare un'applicazione da un sito, + usando il browser interno oppure copiando e incollando un URL sulla lavagna. +

    +

    + Questo ti permette di arricchire le lezioni con strumenti online efficaci, utilizzabili direttamente in OpenBoard. + Ecco alcuni esempi interessanti (trascina i link sulla lavagna per provarli): +

    + + + +

    ... e molto altro!

    + + +
    +
    + +
    + +
    + + + + + diff --git a/resources/startupHints/locales/it/11.html b/resources/startupHints/locales/it/11.html index 059441372..88ccac629 100644 --- a/resources/startupHints/locales/it/11.html +++ b/resources/startupHints/locales/it/11.html @@ -1,45 +1,90 @@ - - - - Registrazione Video - - - - - - - -
    -

    Registrazione Video

    -
    -
    -

    Registra la tua lezione

    -

    OpenBoard ti offre la possibilità di registrare un audio e video della tua lezione.

    -

    Questo può essere utile, ad esempio, per condividere esercizi o informazioni aggiuntive tramite un video clip o per registrare una lezione al fine di condividerla con gli studenti assenti.

    - - In modalità Lavagna, le barre degli strumenti e le palette non appariranno nel video clip, quindi non preoccuparti di esse! Lo stesso vale in modalità Web, dove apparirà solo la scheda corrente nella registrazione. - -

    Puoi aprire questo strumento in questo modo:

    -
    - -

    Vedrai apparire l'interfaccia seguente in basso a destra sulla lavagna bianca:

    -
    - -

    Fai clic sul pulsante rosso per avviare la registrazione.

    - - Puoi regolare le impostazioni facendo clic su . Troverai impostazioni audio (seleziona un microfono o nessuno), impostazioni video (risoluzione della registrazione video) e opzioni di pubblicazione configurabili. - -

    Una volta completata la registrazione, verrà automaticamente salvata sul desktop del computer.

    -
    - -
    -
    - -
    - - - + + + + + Cattura video + + + + + + + + + + +
    + +
    +

    Registra la tua lezione

    +

    + OpenBoard permette di registrare audio e video della tua lezione. + Ideale per condividere esercizi aggiuntivi, pubblicare un breve video esplicativo + o mettere una lezione a disposizione degli studenti assenti. +

    + + +
    + + +
    +

    Accedere allo strumento di registrazione

    +

    Apri lo strumento di cattura come mostrato qui sotto:

    + +
    + Apertura dello strumento Cattura video in OpenBoard +
    Accesso rapido allo strumento di registrazione dall'interfaccia di OpenBoard.
    +
    +
    + + +
    +

    Interfaccia di controllo

    +

    L'interfaccia appare in basso a destra della lavagna:

    + +
    + Interfaccia del registratore (controlli in basso a destra) +
    + +

    Fai clic sul pulsante rosso per avviare la registrazione.

    + + +
    + + +
    +

    Terminare e recuperare il video

    +

    + Una volta terminata la registrazione, il video viene automaticamente salvato sul Desktop del tuo computer. +

    + +
    + Fine registrazione e salvataggio del video sul Desktop +
    Arresto della registrazione e file video disponibile sul Desktop.
    +
    +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/it/12.html b/resources/startupHints/locales/it/12.html index a70c76dd9..26e7a7a3d 100644 --- a/resources/startupHints/locales/it/12.html +++ b/resources/startupHints/locales/it/12.html @@ -1,43 +1,94 @@ - - - - Documenti Preferiti - - - - - - - -
    -

    Documenti Preferiti

    -
    -
    -

    Aggiungi documenti OpenBoard ai preferiti

    -

    Con OpenBoard 1.7, puoi aggiungere documenti OpenBoard ai tuoi preferiti!

    -

    Per farlo, vai alla Modalità Documenti, seleziona un documento e clicca su nella barra degli strumenti dei Documenti.

    - -
    - -

    Cambia rapidamente tra i documenti

    -

    I tuoi documenti preferiti appariranno nella Libreria OpenBoard, sotto
    - Ogni documento OpenBoard () può quindi essere trascinato sulla Lavagna!

    -
    - - Puoi utilizzare la barra di ricerca in fondo alla Libreria OpenBoard per trovare rapidamente un documento per il suo nome - -

    Documenti aperti di recente

    -

    Ogni documento che apri viene temporaneamente aggiunto ai preferiti, in modo da poter passare tra ognuno di essi durante una sessione, senza la necessità di contrassegnarli esplicitamente come preferiti.

    -
    - Se desideri aggiungere permanentemente un documento aperto di recente tra i tuoi preferiti, puoi farlo tramite la Libreria OpenBoard: selezionalo e clicca su -
    -
    - -
    - - - + + + + + Documenti preferiti + + + + + + + + + + +
    + +
    +

    Aggiungere documenti OpenBoard ai preferiti

    +

    + Introdotta nella versione 1.7, questa funzionalita permette di aggiungere i tuoi documenti OpenBoard + ai preferiti. +

    +

    + Per farlo, passa alla modalita Documenti, seleziona un documento e fai clic su + Icona Aggiungi ai preferiti + nella barra degli strumenti. +

    + +
    + Aggiunta di un documento OpenBoard ai preferiti + +
    +
    + + +
    +

    Passare rapidamente da un documento all'altro

    +

    + I documenti preferiti appaiono nella libreria OpenBoard, sotto + Icona Preferiti. +

    +

    + Ogni documento preferito + Icona Documento OpenBoard + puo essere trascinato direttamente sulla lavagna. +

    + +
    + Visualizzazione dei preferiti nella libreria OpenBoard +
    + + + +
    + + +
    +

    Documenti aperti di recente

    +

    + Ogni documento aperto viene aggiunto temporaneamente ai preferiti, per passare rapidamente da uno all'altro + durante la stessa sessione, senza doverli contrassegnare esplicitamente. +

    + +
    + Esempio di documenti aperti di recente in OpenBoard + +
    + + +
    +
    + +
    +
    + + diff --git a/resources/startupHints/locales/it/2.html b/resources/startupHints/locales/it/2.html index 1536900a7..be85591de 100644 --- a/resources/startupHints/locales/it/2.html +++ b/resources/startupHints/locales/it/2.html @@ -1,53 +1,122 @@ - - - - Modalità Lavagna - - - - - - - -
    -

    Modalità Lavagna

    -
    -
    -

    La palette della penna

    -

    La palette della penna ti offre accesso agli strumenti essenziali quando lavori su una lavagna.

    -
    - -

    Qui troverai la penna (), la gomma () e il marcatore (). OpenBoard offre anche altre funzionalità che una lavagna classica non può fornire:

    -
      -
    • è il selettore. Con esso, puoi selezionare oggetti e interagire con essi.
    • -
    • è il dito magico. Puoi spostare gli oggetti o interagire con essi senza la necessità di selezionarli.
    • -
    • è la mano. Puoi muoverti sulla pagina con essa. Molto utile quando combinata con le funzioni di zoom!
    • -
    • ti danno la possibilità di ingrandire e rimpicciolire. Scegli semplicemente quello che desideri e fai clic sulla pagina dove vuoi applicare lo zoom!
    • -
    • è un puntatore laser, utile per evidenziare elementi sulla lavagna senza interagire con essi.
    • -
    • è utilizzato per disegnare linee rette facilmente.
    • -
    • è uno strumento di testo, per scrivere un testo utilizzando la tastiera invece della penna.
    • -
    - - Puoi avere un controllo più preciso dello zoom con il mouse! Usa Ctrl/Cmd + la rotellina del mouse per ingrandire/ridurre con maggiore precisione! - -

    La barra degli strumenti della lavagna

    -

    La barra degli strumenti della lavagna ti offre la possibilità di cambiare colore e dimensione della penna o del marcatore, tra altre cose.

    -
    - -

    Troverai anche la possibilità di cambiare lo sfondo della lavagna, cliccando su

    -
    - -

    Troverai anche pulsanti per annullare/ripristinare azioni, creare e navigare tra le pagine, cancellare l'intera lavagna, ...

    - - Puoi cancellare parti più precise della lavagna facendo clic prolungato su l'icona per cancellare. Alcune funzioni nascoste anche su l'icona per cancellare! -
    -
    - -
    - - - + + + + + Modalita Lavagna + + + + + + + + +
    + +
    +

    La tavolozza dello stilo

    +

    + La tavolozza dello stilo consente di accedere agli strumenti essenziali quando si lavora su una lavagna. +

    + +
    + OpenBoard tavolozza dello stilo +
    + +

    + Lì troverai la matita + Matita, + la gomma + Gomma per cancellare + e l'evidenziatore + Evidenziatore. + OpenBoard fornisce inoltre funzionalità che una lavagna tradizionale non può: +

    + +
      +
    • + + Selettore : seleziona e interagisci con gli oggetti. +
    • +
    • + + Dito magico : muoversi/interagire senza prima selezionare. +
    • +
    • + + Mano : sposta la pagina (molto utile abbinato allo zoom). +
    • +
    • + + + Zoom/Rimpicciolisci : fare clic su dove applicare l'effetto dopo averlo selezionato. +
    • +
    • + + Puntatore laser : punta agli elementi senza interagire con essi. +
    • +
    • + + Linea : traccia facilmente linee rette. +
    • +
    • + + Testo : inserisce una casella di testo per la digitazione da tastiera. +
    • +
    + + +
    + + +
    +

    Il tavolo-bar

    +

    + La barra della tabella consente di modificare il colore e/o il misurare matita ed evidenziatore, tra le altre cose. +

    + +
    + OpenBoard barra della tabella +
    + +

    + Puoi anche modificare il file sfondo del tavolo cliccando su + Cambia lo sfondo. +

    + +
    + Esempio di modifica dello sfondo del tavolo +
    + +

    + Sono disponibili altre funzioni: annullare/rifare, creare pagine, navigare tra le pagine, cancellare la tabella, ecc. +

    + + +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/it/3.html b/resources/startupHints/locales/it/3.html index fd141ba58..4874db0b0 100644 --- a/resources/startupHints/locales/it/3.html +++ b/resources/startupHints/locales/it/3.html @@ -1,36 +1,74 @@ - - - - Modalità Desktop - - - - - - - -
    -

    Modalità Desktop

    -
    -
    -

    Interagire con altri software

    -

    Utilizzando la Modalità Desktop, puoi interagire con l'intero computer e altri software, mantenendo OpenBoard come sovrapposizione!

    -

    Basta cliccare sull'icona seguente:

    -
    -
    Usa il selettore () per interagire con il desktop e altri software.
    -

    Fare annotazioni sopra un'applicazione o un sito web

    -
    Puoi aggiungere annotazioni sopra qualsiasi software, utilizzando la penna () o il marcatore ().
    -
    - - Puoi accedere a ulteriori opzioni per la penna, il marcatore e la gomma facendo un clic prolungato su di essi o facendo clic sulla piccola freccia nera. -
    -
    - -
    - - - + + + + + Modalita Desktop + + + + + + + + + +
    + +
    +

    Interagire con altre applicazioni

    +

    + La modalita Desktop ti permette di interagire con il sistema operativo e le tue applicazioni, + mantenendo gli strumenti di OpenBoard sempre in primo piano. +

    +

    Fai semplicemente clic sull'icona seguente:

    + +
    + Icona per attivare la modalita Desktop +
    + +

    + Usa il selettore + Selettore + per interagire con il desktop e con le altre applicazioni. +

    +
    + + +
    +

    Annotare applicazioni o siti web

    +

    + Puoi annotare qualsiasi software con la penna + Penna + o con l'evidenziatore + Evidenziatore. +

    + +
    + Annotazione di un'applicazione in modalita Desktop +
    Esempio di annotazione su una pagina web.
    +
    + + +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/it/4.html b/resources/startupHints/locales/it/4.html index 867d8ec1f..2c498f229 100644 --- a/resources/startupHints/locales/it/4.html +++ b/resources/startupHints/locales/it/4.html @@ -1,38 +1,79 @@ - - - - Modalità Documenti - - - - - - - -
    -

    Modalità Documenti

    -
    -
    -

    OpenBoard dispone di un gestore documenti. Puoi accedervi semplicemente facendo clic su

    -
    - -

    Crea cartelle e organizza il tuo lavoro

    -

    Puoi creare una cartella cliccando sull'icona "Nuova Cartella". Assegnale un nome e trascina i tuoi documenti all'interno. Allo stesso modo, puoi spostare un'intera cartella in un'altra.

    -
    - -

    Gestisci le pagine

    -

    Un documento OpenBoard può contenere molte pagine. Puoi duplicarle, spostarle nel cestino o in un altro documento, crearne di nuove da cartelle di immagini, ...

    -
    - - Tieni presente che le azioni disponibili vengono aggiornate in base a ciò che è selezionato -
    -
    - -
    - - - + + + + + Modalita Documenti + + + + + + + + + +
    + +
    +

    Accedere al gestore documenti

    +

    + OpenBoard offre un gestore documenti. Fai clic su + Icona Documenti + per aprirlo. +

    +
    + Vista del gestore documenti +
    +
    + + +
    +

    Crea cartelle e organizza il tuo lavoro

    +

    + Crea una cartella tramite + Nuova cartella, + assegnale un nome, poi trascina e rilascia i documenti al suo interno. + Allo stesso modo puoi spostare un'intera cartella dentro un'altra. +

    +
    + Creazione e organizzazione di cartelle +
    Esempio di creazione e organizzazione delle cartelle.
    +
    +
    + + +
    +

    Gestione delle pagine

    +

    + Un documento OpenBoard puo contenere piu pagine. Dalla modalita Documenti puoi: +

    +
      +
    • Duplicare pagine
    • +
    • Inviarle nel cestino
    • +
    • Copiarle in un altro documento
    • +
    • Creare nuove pagine a partire da una cartella di immagini
    • +
    +
    + Esempi di azioni sulle pagine +
    Esempio di gestione dei documenti.
    +
    + + +
    +
    + +
    +
    + + diff --git a/resources/startupHints/locales/it/5.html b/resources/startupHints/locales/it/5.html index 18b5dc4ec..61a3184c4 100644 --- a/resources/startupHints/locales/it/5.html +++ b/resources/startupHints/locales/it/5.html @@ -1,46 +1,104 @@ - - - - - Modalità Documenti - - - - - - - -
    -

    Modalità Documenti

    -
    -
    -

    In questa modalità troverai anche due funzionalità molto importanti: Importa ed Esporta.

    -
    - -

    Importa

    -

    Puoi importare file PDF (.pdf), immagini (.png, .jpg), documenti OpenBoard (.ubz) o cartelle OpenBoard (.ubx) cliccando su

    -
    -

    Nota che puoi anche importare un documento OpenBoard (.ubz) facendo doppio clic su di esso. Si aprirà OpenBoard se non è già aperto e lo importerà (o chiederà di sostituirlo se esiste già).

    - Puoi anche importare più elementi contemporaneamente, senza dover fare clic su nuovamente e nuovamente. -

    Esporta

    -

    Puoi esportare un documento OpenBoard in formato PDF o UBZ e una cartella OpenBoard in formato UBX. Pertanto, puoi, ad esempio: -

      -
    • Salvare il lavoro svolto durante una sessione di classe e condividerlo con uno studente assente
    • -
    • Condividerlo con altri insegnanti o archiviarlo su un dispositivo USB e aprirlo su un altro computer
    • -
    • Importare i compiti di uno studente in formato PDF, annotarli e esportare il PDF annotato per restituirlo allo studente
    • -
    -

    -
    - - Esporta tutti i tuoi documenti selezionando la cartella "I miei documenti" prima di fare clic sul pulsante di esportazione, per esportarla come file UBX, e quindi importala su un altro computer. È anche un buon modo per fare un backup del tuo lavoro! -
    -
    - -
    - - - + + + + + Importare ed esportare + + + + + + + + + + +
    + +
    +

    Import & Export

    +

    + In questa modalita hai due funzionalita essenziali: importazione ed esportazione. +

    +
    + Area di importazione ed esportazione nella modalita Documenti + +
    +
    + + +
    +

    Importare contenuti

    +

    + Puoi importare file PDF (.pdf), + immagini (.png, .jpg), + documenti OpenBoard (.ubz) o + cartelle OpenBoard (.ubx) facendo clic su + Icona Importa. + +

    + +
    + Esempio di importazione file in OpenBoard +
    Esempio di importazione di file in OpenBoard.
    +
    + +

    + Puoi anche importare un documento OpenBoard (.ubz) + facendo doppio clic dal tuo sistema. OpenBoard si avviera, se necessario, + e ti proporra di importarlo (o sostituirlo se esiste gia). +

    + + +
    + + +
    +

    Esportare i tuoi documenti

    +

    + Puoi esportare un documento OpenBoard in formato PDF o UBZ, + e una cartella OpenBoard in formato UBX. Ad esempio: +

    +
      +
    • Salvare il lavoro svolto durante una lezione e condividerlo con uno studente assente.
    • +
    • Condividerlo con altri insegnanti o salvarlo su una chiavetta USB per importarlo altrove.
    • +
    • Importare il lavoro di uno studente in PDF, annotarlo ed esportare il PDF annotato per rimandarlo.
    • +
    + +
    + Esempi di esportazione di documenti e cartelle OpenBoard +
    Esempio di esportazione di file da OpenBoard.
    +
    + + +
    +
    + +
    +
    + + + diff --git a/resources/startupHints/locales/it/6.html b/resources/startupHints/locales/it/6.html index d9700dbb7..cc6d85b91 100644 --- a/resources/startupHints/locales/it/6.html +++ b/resources/startupHints/locales/it/6.html @@ -1,45 +1,95 @@ - - - - - Modalità Web - - - - - - - -
    -

    Modalità Web

    -
    -
    - La Modalità Web è un browser interno che aggiunge alcune funzionalità interessanti a uno più standard. -

    Usa il browser interno

    -

    Utilizzando il browser interno, sarai in grado di navigare su Internet senza la necessità di ridurre o uscire da OpenBoard, con alcune funzionalità aggiuntive che ti consentiranno di catturare parte dello schermo o creare applicazioni dai siti web e aggiungerle alla lavagna!

    - -
    - -

    Crea un'applicazione

    -

    Puoi creare un'applicazione da qualsiasi sito web, in modo da aggiungerla alla lavagna e interagire con essa come con le applicazioni predefinite.

    -

    Per farlo, vai al sito web che desideri catturare, fai clic su Cattura contenuto web e conferma la creazione cliccando su "Crea un'applicazione".

    -
    - -

    Quando un'applicazione viene creata, viene automaticamente salvata nella libreria di OpenBoard, in modo da poterla utilizzare in qualsiasi documento. Le troverai nella cartella delle applicazioni, sotto una dedicata chiamata "Web".

    - -
    - -

    Usa un browser esterno

    -

    Puoi anche scegliere di utilizzare un browser esterno, selezionando l'opzione corrispondente nelle preferenze. Cliccando sull'icona Web lancerà il tuo browser preferito in Modalità Desktop.

    - Usando un browser esterno, sarai comunque in grado di creare applicazioni da un sito web, copiando l'URL nella barra degli indirizzi del tuo browser, tornando su Board e incollandolo! -
    -
    - -
    - - - + + + + + Modalita Web + + + + + + + + + +
    + +
    +

    Il browser integrato

    +

    + La modalita Web e un browser interno di OpenBoard che aggiunge, rispetto a un browser + tradizionale, funzioni molto utili per la didattica. +

    +

    + Permette di navigare su Internet senza uscire da OpenBoard, catturare contenuti (parziali o a schermo intero) + e perfino creare applicazioni a partire da siti web per riutilizzarle nei tuoi documenti. +

    + +
    + Esempio di uso del browser integrato di OpenBoard +
    +
    + + +
    +

    Creare un'applicazione a partire da un sito

    +

    + Da qualsiasi sito puoi creare una applicazione da aggiungere alla lavagna + e utilizzare come le applicazioni predefinite. +

    +

    + Apri il sito desiderato, fai clic su + Icona Aggiungi alla libreria + e conferma selezionando Crea un'applicazione. +

    + +
    + Creazione di un'applicazione Web dal browser integrato +
    Creazione di un'applicazione dalla modalita Web.
    +
    + +

    + Una volta creata, l'applicazione viene salvata automaticamente nella + libreria OpenBoard. La troverai in Applicazioni > Web + e potrai riutilizzarla in qualsiasi documento. +

    + +
    + Applicazione salvata nella libreria, cartella Web +
    Ritrovare un'applicazione creata nella libreria.
    +
    +
    + + +
    + +

    + Puoi scegliere di aprire i link in un browser esterno attivando + l'opzione nelle preferenze. Facendo clic su + Icona modalita Web + verra avviato il tuo browser preferito in modalita Desktop. +

    + + +
    + +
    + +
    + +
    + + + diff --git a/resources/startupHints/locales/it/7.html b/resources/startupHints/locales/it/7.html index ad3a67a17..a2c8b7fee 100644 --- a/resources/startupHints/locales/it/7.html +++ b/resources/startupHints/locales/it/7.html @@ -1,50 +1,102 @@ - - - - Cattura Schermo - - - - - - - -
    -

    Cattura Schermo

    -
    -
    - Una delle funzionalità più semplici ma davvero utili di OpenBoard è la cattura schermo. Con essa, puoi creare uno snapshot di uno stato particolare della lavagna durante la tua sessione di classe. -

    In Modalità Lavagna

    -

    Cercal'icona di cattura schermo nella palette dello stilo, cliccaci sopra e seleziona l'area da catturare. Successivamente, avrai tre opzioni :

    -
      -
    • Aggiungi alla pagina corrente
    • -
    • Aggiungi in una nuova pagina
    • -
    • Aggiungi alla libreria (aggiunge la cattura alla cartella Immagini, in modo da poterla riutilizzare in qualsiasi momento)
    • -
    - -

    Ecco un esempio di tutto il processo :

    -
    - - Non devi preoccuparti della palette dello stilo, della vista delle miniature della lavagna o della libreria di OpenBoard, non verranno catturati dal tuo lasso! - -

    In Modalità Desktop

    -

    Puoi fare la stessa cosa anche in Modalità Desktop per catturare il tuo lavoro su altri software. Vai in Modalità Desktop cliccando su

    -

    Troverai due icone : per catturare l'intero schermo e per catturare solo una parte. Come in Modalità Lavagna, dovrai scegliere dove posizionare la cattura effettuata

    - -

    Ecco un'illustrazione di tutto il processo

    -
    - - -

    In Modalità Web

    -

    Di nuovo, lo stesso processo è disponibile in Modalità Web, dove sarai in grado di catturare solo una parte dello schermo o catturare la scheda corrente con

    -
    -
    - -
    - - - + + + + + Cattura schermo + + + + + + + + + +
    +
    +

    Une fonctionnalité simple et très utile

    +

    + La cattura schermo ti permette di creare un istantanea dello stato della lavagna (o dello schermo) + durante la lezione, per archiviare, condividere o riutilizzare i contenuti. +

    +
    + + +
    +

    In modalita Lavagna

    +

    + Nella palette degli strumenti, fai clic su + Icona Cattura area (modalita Lavagna), + poi seleziona la zona da catturare. In seguito potrai scegliere: +

    +
      +
    • Aggiungi alla pagina corrente
    • +
    • Aggiungi a una nuova pagina
    • +
    • + Aggiungi alla libreria — la cattura viene salvata nella cartella Immagini + per un uso successivo. +
    • +
    + +
    + Esempio di cattura di un'area in modalita Lavagna +
    Esempio di integrazione di una cattura schermo in OpenBoard.
    +
    + + +
    + + +
    +

    In modalita Desktop

    +

    + Passa alla modalita Desktop tramite + Icona modalita Desktop + per catturare altre applicazioni. +

    +

    Sono disponibili due opzioni:

    +
      +
    • + Icona Cattura schermo + Cattura schermo intero +
    • +
    • + Icona Cattura area + Cattura di un'area +
    • +
    +

    Come in modalita Lavagna, scegli dove aggiungere la cattura.

    + +
    + Esempio di cattura in modalita Desktop +
    Cattura schermo completa o parziale in modalita Desktop.
    +
    +
    + + +
    +

    In modalita Web

    +

    + In modalita Web puoi catturare un'area dello schermo oppure + catturare la scheda attiva del browser con + Icona Cattura scheda. +

    +
    +
    + +
    +
    + + + diff --git a/resources/startupHints/locales/it/8.html b/resources/startupHints/locales/it/8.html index 9f7ddcc66..b452fbe01 100644 --- a/resources/startupHints/locales/it/8.html +++ b/resources/startupHints/locales/it/8.html @@ -1,42 +1,102 @@ - - - - Immagini - - - - - - - -
    -

    Immagini

    -
    -
    - In OpenBoard, puoi accedere alle immagini in diversi modi. -

    Organizza la tua cartella Immagini

    -

    Le catture dello schermo aggiunte alla Libreria vengono salvate nella cartella Immagini :
    Puoi creare cartelle utilizzando nella parte inferiore della Libreria. Quindi, trascina e rilascia le tue immagini nelle diverse cartelle che hai creato.

    -
    - - Non importa dove ti trovi nella Libreria di OpenBoard, le immagini che aggiungi saranno automaticamente collocate all'interno della cartella Immagini, per mantenere l'organizzazione. - -

    Aggiungi immagini dal tuo computer

    -

    Puoi anche aggiungere immagini direttamente dal tuo computer, come illustrato di seguito :

    -
    - -

    Aggiungi immagini dai motori di ricerca

    -

    Ultimo ma non meno importante, puoi cercare e aggiungere alla tua lavagna immagini royalty free utilizzando i motori di ricerca situati nella cartella Ricerca Web :

    -
    - - Al posto di utilizzare il trascinamento, basta fare clic su una delle immagini restituite dalla tua ricerca per visualizzare i dettagli sull'immagine e trovare un'opzione per aggiungerla alla Libreria senza aggiungerla al tuo documento attuale. Utile quando si prepara una lezione! -
    -
    - -
    - - - + + + + + Images + + + + + + + + + +
    +
    +

    Accedere e organizzare le immagini

    +

    + In OpenBoard puoi accedere e aggiungere immagini in diversi modi dalla tua libreria. La libreria si trova a destra dello schermo. Qui puoi anche archiviare suoni, video e trovare varie applicazioni. +

    +
    + Area libreria a destra nell'interfaccia +
    Vista della libreria posizionata a destra nel software.
    +
    +
    + + +
    +

    Organizza la cartella Immagini

    +

    + Le catture schermo aggiunte alla libreria sono raggruppate nella cartella + Icona Immagini. + Puoi creare sottocartelle tramite + Icona Nuova cartella + (in basso nella libreria), poi trascinare le immagini nelle cartelle create. +

    + +
    + Organizzazione della cartella Immagini con sottocartelle +
    Esempio di organizzazione e classificazione delle immagini nella libreria.
    +
    + + +
    + + +
    +

    Aggiungere immagini dal computer

    +

    + Puoi importare i tuoi file immagine direttamente in OpenBoard, come mostrato qui sotto: +

    + +
    + Aggiunta di immagini dal computer +
    Importazione di un'immagine locale in OpenBoard.
    +
    +
    + + +
    +

    Aggiungere immagini dal Web

    +

    + Puoi anche cercare immagini libere da diritti tramite i motori di ricerca integrati, + disponibili nella cartella Ricerca Web + Icona Immagini. +

    + +
    + Aggiunta di immagini da un motore di ricerca integrato +
    Esempio di ricerca e aggiunta di immagini dal Web.
    +
    + + +
    +
    + +
    + +
    + + + diff --git a/resources/startupHints/locales/it/9.html b/resources/startupHints/locales/it/9.html index 3a426ea95..f03391097 100644 --- a/resources/startupHints/locales/it/9.html +++ b/resources/startupHints/locales/it/9.html @@ -1,49 +1,99 @@ - - - - Interattività - - - - - - - -
    -

    Interattività

    -
    -
    - Per gli studenti più giovani, troverai un set dedicato di applicazioni personalizzabili. -

    Esercizi interattivi di OpenBoard

    -

    Utilizzando queste interattività, puoi creare diversi tipi di esercizi personalizzati. Questi possono riguardare la categorizzazione, i calcoli, la memorizzazione e così via.

    -

    Le interattività si trovano nella Libreria di OpenBoard : clicca su per trovarle.

    - -

    Esempio

    -

    Come esempio, creeremo un esercizio utilizzando l'interattività "Categorizza immagini" :

    - Provalo! Sposta questa finestra di dialogo da un lato e riproduci l'esempio sulla lavagna! -

    Prima, trascina e rilascia l'interattività sulla tua lavagna e clicca su "Modifica"

    -

    Quindi, cambia il nome delle categorie secondo le tue esigenze :

    -
    - - Puoi aggiungere o eliminare categorie usando le icone + e - - -

    Successivamente, aggiungi le immagini che desideri nella categoria corrispondente.

    -
    - -

    Infine, clicca su "Visualizza" per mostrare il risultato e svolgere l'esercizio.

    -
    - - Puoi ripetere l'esercizio utilizzando l'icona "Ricarica". - - -
    -
    - -
    - - - + + + + + Interattivita + + + + + + + + + + +
    + +
    +

    Esercizi interattivi, semplici da personalizzare

    +

    + Per gli alunni piu giovani (e non solo), OpenBoard offre un insieme di + interattivita personalizzabili: categorizzazione, calcolo mentale, memorizzazione, ecc. +

    +

    + Sono disponibili nella libreria: fai clic su + Icona Interattivita. +

    +
    + + +
    +

    Esempio: "Categorize Pictures"

    +

    + Creiamo un esercizio con l'interattivita + Categorize pictures (categorizzare immagini): + Miniatura Categorize Pictures. +

    + + + +

    1) Posizionare l'interattivita e aprire l'editor

    +

    + Trascina l'interattivita sulla lavagna, poi fai clic su Modifica. +

    + +

    2) Dare un nome alle categorie

    +

    + Rinomina le categorie secondo le tue esigenze. Puoi anche + aggiungere o eliminare categorie con le icone "+" e "-". +

    + +
    + Modifica delle categorie dell'interattivita +
    Modifica categorie: aggiunta, eliminazione, rinomina.
    +
    + +

    3) Aggiungere le immagini

    +

    + Aggiungi le immagini corrispondenti a ogni categoria (trascinamento, selezione dalla libreria, ecc.). +

    + +
    + Aggiunta immagini alle categorie +
    Associare immagini alle categorie definite.
    +
    + +

    4) Avviare e svolgere l'esercizio

    +

    + Fai clic su Mostra per avviare l'attivita in modalita studente. +

    + +
    + Esecuzione dell'esercizio Categorize Pictures +
    Esecuzione dell'esercizio: spostare le immagini nella categoria corretta.
    +
    + + +
    +
    + +
    +
    + + diff --git a/resources/startupHints/locales/it/css/dark.css b/resources/startupHints/locales/it/css/dark.css deleted file mode 100644 index 34ded372a..000000000 --- a/resources/startupHints/locales/it/css/dark.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - background-color: #3a3a3a; - color: #e0e0e0; -} - -.title { - color: #8ba3d7; -} diff --git a/resources/startupHints/locales/it/css/light.css b/resources/startupHints/locales/it/css/light.css deleted file mode 100644 index 4e1f81f0e..000000000 --- a/resources/startupHints/locales/it/css/light.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - background-color: #edf2f7; - color: #1f2937; -} - -.title { - color: #5f7faa; -} diff --git a/resources/startupHints/locales/it/css/style.css b/resources/startupHints/locales/it/css/style.css deleted file mode 100644 index de0ecb4d5..000000000 --- a/resources/startupHints/locales/it/css/style.css +++ /dev/null @@ -1,36 +0,0 @@ -*{ - font-family: Arial, Helvetica, sans-serif; -} - -.title -{ - width:100%; - color: #6682b5; - text-align: center; -} - -.file-extension -{ - background: lightgrey; -} - -.image -{ - text-align:center; -} - -.image img -{ - max-width: 600px; -} - -.icon -{ - vertical-align: middle; -} - -.tip -{ - font-style: italic; - font-size: 0.8rem; -} diff --git a/resources/startupHints/locales/it/error.html b/resources/startupHints/locales/it/error.html index 9c6aa4e39..cedc7403b 100644 --- a/resources/startupHints/locales/it/error.html +++ b/resources/startupHints/locales/it/error.html @@ -1,14 +1,20 @@ - - - - errore - - - - - -

    Qualcosa è andato storto... -Verifica l'esistenza dei tuoi suggerimenti nella cartella -/Resources/startupHints/ …

    - - + + + + + Errore + + + + + +
    +

    Errore di caricamento

    +

    + Si e verificato un problema. + Verifica la presenza delle pagine dei suggerimenti nella cartella + /Resources/startupHints/. +

    +
    + + From f6f700132d53153d9384bd430e8229e989269ddf Mon Sep 17 00:00:00 2001 From: Sofian Elmotiem Date: Wed, 27 May 2026 10:59:03 +0200 Subject: [PATCH 130/133] feat: add Marelle cursive font family (OFL license) (#4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the Marelle font family v1.004, released by the French Direction du Numérique pour l'Éducation (DNE). Marelle is an OFL-licensed font designed specifically for teaching cursive handwriting in primary school, developed by professional type designers supervised by teachers following current French best practices. The family includes 8 variants: - Marelle / Marelle2: cursive with cursive or baton uppercase - MarelleBaton / MarelleBaton2: baton-style with cursive or baton uppercase - MarelleLIGNES variants: all of the above with Seyes ruling lines This adds a properly licensed alternative to the existing EcritureA and EcritureB fonts, which carry license restrictions that prevent redistribution by distributions such as Debian and Fedora. Closes #2 Reference: OpenBoard-org/OpenBoard#1469 Signed-off-by: Sofian Elmotiem --- .../customizations/fonts/Marelle-LICENSE.txt | 92 ++++++++++++++++++ .../customizations/fonts/Marelle-Regular.ttf | Bin 0 -> 350256 bytes .../customizations/fonts/Marelle2-Regular.ttf | Bin 0 -> 364236 bytes .../fonts/MarelleBaton-Regular.ttf | Bin 0 -> 259364 bytes .../fonts/MarelleBaton2-Regular.ttf | Bin 0 -> 261052 bytes .../fonts/MarelleLIGNES-Regular.otf | Bin 0 -> 1512924 bytes .../fonts/MarelleLIGNES2-Regular.otf | Bin 0 -> 1512168 bytes .../fonts/MarelleLIGNESBaton-Regular.otf | Bin 0 -> 1192080 bytes .../fonts/MarelleLIGNESBaton2-Regular.otf | Bin 0 -> 1193080 bytes 9 files changed, 92 insertions(+) create mode 100644 resources/customizations/fonts/Marelle-LICENSE.txt create mode 100644 resources/customizations/fonts/Marelle-Regular.ttf create mode 100644 resources/customizations/fonts/Marelle2-Regular.ttf create mode 100644 resources/customizations/fonts/MarelleBaton-Regular.ttf create mode 100644 resources/customizations/fonts/MarelleBaton2-Regular.ttf create mode 100644 resources/customizations/fonts/MarelleLIGNES-Regular.otf create mode 100644 resources/customizations/fonts/MarelleLIGNES2-Regular.otf create mode 100644 resources/customizations/fonts/MarelleLIGNESBaton-Regular.otf create mode 100644 resources/customizations/fonts/MarelleLIGNESBaton2-Regular.otf diff --git a/resources/customizations/fonts/Marelle-LICENSE.txt b/resources/customizations/fonts/Marelle-LICENSE.txt new file mode 100644 index 000000000..4b8a16531 --- /dev/null +++ b/resources/customizations/fonts/Marelle-LICENSE.txt @@ -0,0 +1,92 @@ +Copyright 2026 Ministère de l’Éducation nationale, de l’Enseignement supérieur et de la Recherche, Laurent Bourcellier, Jonathan Fabreguettes and Rosalie Wagner, with Reserved Font Name "Marelle". + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION AND CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/resources/customizations/fonts/Marelle-Regular.ttf b/resources/customizations/fonts/Marelle-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..04b4d36628b3c522662bdc327103b6020859a1c9 GIT binary patch literal 350256 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

    g4dGf?3&IMWK|pk})J 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 vwau^MHWUfWJQhYkDYs literal 0 HcmV?d00001 diff --git a/resources/customizations/fonts/Marelle2-Regular.ttf b/resources/customizations/fonts/Marelle2-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..af86177a57fd6583ce23721dce48602e656699a2 GIT binary patch literal 364236 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

    D_NMF7vpjo_S` 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%0DM_?QXdIMj6%CV; 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

    Y zkB`qN&V8GH9h*f^y%-P1doe39C~P*fT@#;?5x-IS=dzdS#mo3&aPwg01MvsQ-(cv% za=Sg*V-yhg%4lWH{LW}#HzKAaArNRw4x<=uPa=|I+AR#I>k?CtE-Wc>a7J9H#Sp)A z^n%Nm&Mlf98xoq7!va~Jl^r8mDp%{P>K5GIJoCtcw&S_WHEdNFs27w|JZt=f89@QM zoMbl1l0^WY3ar0=+Vq|E%{A;8R0+X%O8h(EixCiEvFH2aX3JD^_Tg;u5GM-99HBrN z4rYrZ3@A%Y$;t36c@z*^N!7z9JMX&kltRv`PWBwU^}E|>wOgJ~Z&^Hh|HKIg+UDOe z`T7;D_8EB#rd2J@Ji`q8Xpy@vYodF=M_)9=4z{f69z+}h^6Z1C6+to1ALR>b=9 z?Ss@hx21#80bpfMM0@ z*cGYK=5)qV%Qw@KpR_kBwe&(XTXX#<*UqQc2WvBx9}+U-bh>-)rDb2gg?=KyZrXZ) zUOj#SQf-F*mVw`B#3AzOR42n0$kaF=Tn)tifnZuR)F*2N##vKdZgOTSh5Fom1vQFK ztl~f`gdTxDttpgRF*$H-GT&EGHgW%~)|)5onl^s=kwuG-%-DX};zjGy+hzs5YPC+8 zG_`rbwCVFU&Pr=7t6Wl2vZQj$#N3M;8rPMVuWKAuQ!~t3SY*+RS;~%P<;2I;X5|bk zq28CGFa~f00**i-hxjBAK0yTS6UnWna6UrCd?yERaJ3_WL*9X?fi=L@-keXE!@F@@ zH>d{mii){?AWi1NI&c~b#pRI;$CXUYpWi%k-cThlFFrkW-+hs}mzGYyY0{KiXIy;O z)Wx6NRh%1@$X1W5&8*8CJ1uYQppJJ^HQJl5w%BT~n>Oj1`svT_-1qnE^l}PrXBOE5 z@~84){oMnzrGgX19&D*}vj9wA=RHN(7ma_NdKg#R% zN6yEVI(&Wawp5-73Gu;}YUY!u^l3~<6R~Ho_A9XV3usRT)ldw~p0a29X;3x$L*vtZ zx2Od3Z{&~Vllo(z7xbNKRJp-)HI&*1cQ8A_E@J{d~+J`k%nL#bUt6zbbj zitH80)-{kVvXg5bRn270@fdgj>7?dd&&-_Gl97i)4TaP_CK?Lab9?)&^PH`lWo@zh zxf<7=6!pcpvRC?PT{Sm_fs{U&SLmDa=}YSmL>Nu-+~D zd;T3ZR*Ln>#%csFHkSPlc<)x=cmOt5aNCdjW@Fj^_-16a*YwNEitJ^;u>)}Y`)sWA zcOPx6?h2o5Ec@3QY5loE+({H5B-rEVfJI=F@QYEB2ID)k0Ku<7!sb+@eV3Y`fkT#m zKm(n5mE0=1Se8iR(0@?<*b~2@oYHKAy-X4hW56ojuN{xyl6VWdxzG1+b$kB^p1;fO z`L6d*dYu2Z&gbcUdj4*==N<2#!yZBU1~6k~@)P)kDDrh-{A9QBU(k9neyZE}ExnB2 z>KN}n&uxzJ?%#W$mw9gQW&Dm_<~i8Q_#qk>-jLP_ed|}M?H++gU{dVVVvfC zKPXDXMAcnv&2c}+5JF+jA^+~5;?FogfSz)Xq*_E>lp{l`0KpM;52a(umV^-W!O@f& z`R{){E2HgoRG3a5z<>Yr6TSocioNH)*B?QgC_+fX%>s9;2Qfz4^bBUWxB+>yjz2W` z1DUdPPBWNxbl7~iBkpU^;y@KMiLJ<}LW&vA5FBkwakGO#O*V@_V?KM4&kt#4AeN3g z6-mN_2oM$IqTVhC%HzC=(xi zQRy2`uJf6nx)ETdcaK%2&$SNv%o9%71Bo<^%xIX(bb2~!BZ8E6;?`);8;p9y?GcC4 zXxnkJgNC*^;c+35!Qj^_`1zrEr&cSW;XFrktbO!A=kRY8{QbMg6+UOy#PRjDm17WY zO6LUQ-GY54*!eiqq7Our9_^>Y?ISf0_s1=lgliyozeTJ(Ll`Ek6Mkb4q?qI!=I^%* zjiH@%t%j7TiHiPyMn8YF)zpE$I(>T(g(?GN6l)m;gU)E61S<)l3QA=JZ39|`fB=5G zfCepIAxt=8wb!5bWPzXCv34>1Yymk3m43qId$^Hu|)AQdvRe-7C_=5(_kb| z`n=6UBQQDychO(A^I-(Z&o@ck-%Y~%%^Y%rHz7XrXg9I%7o&9Q=pQ;-+1MeS1{ zQ*Zl4ALWj%B?|Ptt%RLxguHb?-iE_>TqmrtU*e3V&tk?vsrOu3Y%YVCt_?>^foOB4 z4>YO=pavXAK-9RD1qJC_{g_@Kp|8iiQ0p4kUb<@evPEq(r%!2_IKH~l=8V0Ec0W1q zZ|q%-Jh}==Kj_iePqoJ$>n0n05=-9H5A}CuPdAb9iH0I_929Ad^a78&Ap**I98Pk& zOI~}1RNwvlN>6$1>dA)3^Q$EuVs2YJhupC9*n94bc$@Sp{3TC$>**wT8OU45(UsmM zZ@p8yQDiv8lW5pHxeWNeYXI|L>19k>V9)DzZso{cPw&cJ$5-Y)rIzi;dy@{)`j=I(W)8r?euTYmRktRpLB((#JbC zdA^=J-RVALsfSMBkNzGy9rH0DCf@2p zKnyXFE2LMYHM;FgC%y@iye=3X6vPwK>&FW-K_a}rS9)2zO}7W{zvXv`)=!7is#4k_fI+Bmt5ha`K$T+zj40r_Wgf4_oaRV@?(;ubqF8=i{iuV z55S@*o?w3UuebURC-xoXBpB!-gsh7{3!aN*5Qt$ZrjrdyM>k(2h%Lw){;amC^pAGHA<%5zF z@l1H;+;{8^gp~Y*XnO?MnYB`+S1skD6eNoB%5<{pI9F$enwsIms;h?u)C?b9T|Inw z4IY9mp3`xhof1w9Q9_745P!3+7``+i&`rxH~Taf$7Vr9qi%mj;R?E4E=HH1eeWCjPUJ9L%u{Q~d@UnhLORPlRkuUhg9=K`KJXY=G;(yuwprS=ge$RWvOfEC$r$iNU~RD?+Q2bk%??|Gc} z2;eB%S@Zx{^l|(o7T!+{doO`PquIWWW$C}c6`3><6S#HzU;D(ckcQaHU{(V#f4sn4QAmYlH#I_ z#8868kLD_#!%;f>YyEb!j7e6P&q|yX58osRSv2bds_GZFIz%)W6C#iqFV+SJ_(_I9JqiR2!h(<>oy4><)EE=zBWh%%`f{$cM~xDMQ5B;q z#*C)y_mRVgUQ|?&mus({oL&@{oM&c_D~{hZCLZDZwuRnNu3?VfXI~MIbW8%u!0C-0pJ*}-$8qKr zWj6(C)CvlxX;#m!xTbWA{hqW%nlo^}wVwYz^JvFuT%Z*Y;8z;Xe}Dh1hq;Z&c_ZP% zcW#9UUz%#=W?%IhB3Y;8G-jA1ZF;!|*K^_bnMVy%0_gs%@1G6ezx_(pxgTNsq#a_K z59iM+!JL%}(j4Hm<1xanSS_Xzdgwoni#cqcTswd{2_s0(@ENMY#xj&Ok| z)Z)NBBv?>0wZnBX{h^Ut(3HWXJgq#ynpn9hE+I2o`K|IQD`u%mr6nOVj0M9_ewDq3 zpTS}9!6Hs~3{@s56FY{UR%tS+<0ENa=l41Zot937=HHRby^q1T#hJdH`$UMA-o%QP zSC!vJ)7P_d)}%b3Jk7uUi1;!)%I+0kJ{>{duYB7fDn&{$etyfpAH2jWJ5I{03{T;1 z`&(;{XE!!KYJ%g&YGd)6bU98$({TV7i(ctSUe^e15P4Y^TkuPyGAdDSLU9|OBR7sX z6bceK%=oycPuhVuBtr@kw5VFm=J+fOGbV*6=9m-JYXJ>)x!I{UtHla)8|6?NNvSDn zn!dvftHzjLq#2Pv*kMW3I8CP=PI34sJoi(54T}>gk4?&qH^?Pr_dh#y)X2Pzt5|={kuDdcaCMNRA>r#s9N40xXf0~v6=atnU( zvJyel6br2O$Q&d04u@ul%u$j&d3Q{MEb(qg4R!Dna7Phj2co)M7)nItS=Z#_k(uVc z4@b9y04}e=j;Yi8fzzny=qMMQc6@fBaLN{Rd;*?6E<_4x_GGvq#B?}H1k18Xz=k*j z7#5L@j}Mp%EH=Ku;QG@N;_PMM*lk$kYABG7_e9>fpyN> zqp$5a)bR;@q47cWYrp>?s~EoDnvP2LjBpydEb`ojpQ2S=_EWT~%hdO!rNSA!ALe{t zJmGvF>xji+*74G2Y8OMb z>}Ube^%iXjhlI2}v(x4YcmKbvB z;!x=NNX^@<{Ag0htQk>>*=B=Zb#q|c4a%3x!eSAhyplDam^(e%irzlPn&w-S4_1a_ z(;f|;5ruzga;0zee{#|Xlu?~)p^H954_X|TV3JgRlt6obYL3F!?R*QMalsXJlGOu! zl-!>5(d2oik8;{GeUxvAKEk)4kI|hzX+hjOihYb;sJe}kJN#T=BKp8UY=x68(H26u z6!gi+Rr$~X42pB9mx9Cb;Vjt&DSy-X7NJ1$x0r4q~+@7Dv<0 zg|?~qHy7#|=>(z}A=c+)Wm!oR*i;`6`%YDQI(MiVInw1lVnK*q=esDVXS(84@yE=B zq=$@=AQdOcUHGU2omyyQskCQ6P5_;g+0PS;XdIw+hUKp@2-US zNZiPM{DJ$W5Fvy4hwNs0KN*>ODNyc{1wVhizn{JxXH`x%BWl6 z(R&Uby7AzRx8JgV=ZOte{(WONn?m8q*CJTOvC+}xvs0Jb|^#Q6~=TBbP+lT+S{)f98CZxMJA zxDDYtFr~0i?N)$5FIT~laG5EB)%7!yIoajNm`TcU=Bh9*0}RP0F2-3Fd72;O9*2e7xiK zy1EMg>JcNV{Uxy^vt;X2%>K;N%#MXU_w+N$b5HI36WjdRgKXHB!)`i!_@<;EKHWtbDf3rzecYjG|{3F!O^DKi0IUl7iJcI3JIA^y!DpEoIoA~P-Q zZv=(%_!kNfHqktiHel4qk)xC|SeFonTSrbBX6kMd1|gTSQW!7H6c(co(iUN-aGP*c zcuaUrcvE;+I3;{8{8ji?ZmKzMf?U*n^O+dM{`}(O202=IM=!=k|L-Tikpkns{Pa)n zzO4xgM93)UFYoU9J>18d)B23CVjetfq{ zW6pn4d!x%D-R8p@qToixM#n|R#_Jv3nnT@c4nF2aX&*wClEAx9;D&b?4UWuidtG z%i7Hw*DqPKWcAABt&3Y1&7V7A=7bqjTB^oZjcceIUOBv?yfklEUP)$JPP8pei*uVI z-jpITlKaCH^^7dkL`3q_8m{+KlVKFpSI8qN3=tf=GcpxCn#4Ck?yp@xQ{?h_*ZN`C z&qTO<#u1@%%wM1;an9b2q zW^>d*{Em)~k3N`?!2cF6b-Xy>_<(Zfph0PAgY(j*C|iy--j;29(UzSYYs<2wC0i3T z#yDH1?In!FTXSq3|FA$qp{EOb&m!v*BElo$67bs;Zu-|7O1>D$K2hS8B`j_(s+Bzke zlatK}$>)T)=%^$!7F`+_6`d3p8I$yBd}L&z%<$6M6dN6#6dxUB5i>Jw<`gN*7M~)f zq(5hDf=fgDgkURj?zrZR~;9NdgX_XpJZ!XGB!_1ap6HZQA6Gm zZOXx$JEpUSN0qO}u{<&4sg7@;q_l$Z+;@hF+NFXO=U0=kv%5stEnIG2yZhSV>9S6H z)!O`AYRyyY&-6w=qu#GQ0G2I?8G_moX^_w!!3cksG&vK30$ETSa;Y@hKs0yN1~VPn zMM1?Qcg>}>gUz;c$EJxU6cf2xx%$_krpV|Ck1t*NKjVJc zG$_z)8Ir&9s%ux}U(|YdR`G%?i)~O-Zf?^cX)}Bj(`6?9^X#vkp3m7okxz3O93uRz zXXOt?)&_-4Thds*kyPwFk}1 z;*TjEWjep4BvG^^v1@W0;pS#7D6Uwa7a@vKgEm&qx~tV<4jj}pXi#IW9N_Y0FT#O3 zMqbphf4Z*hvfmaNM(%Fd_Qlm#f3dCc#u0{#et-Su4>sc;*acgD;oNt+nYwEc6<8-c zWH-X18&`l6s7n~_EbM~OpfebCIIPeKItk@q=y@h+H&7mdABETb1cTAf(57b?WjeU| zo$>Zr6mK6JYai1&gxoqK-aS^$* zu9&f4|2TFhJ!7`Ug^j_{iqV*oRlR)Vkh!IWEyWrsJvJ#rV{F|!Y5v_aTW+5p5og6g z);5syi?l^c>UYkab<2Ty_bFHJICIPNc}Ald$MtJgy~u_?`hfD>$#pM1wPf0=5nFE> z)pGQbAUu;jz5Jq!B1epjNit_KW*D)oa#(9oa#>o8ZE#}ky3tb)&TTuoz>r^@F{!d} zWDNKK)I9ftVY+-3-{FoICJN*1jU$Gl07cfvf<~`tYOGI9Ny|X{#S|-ohR)mvl0=XV774gkUqM<`LL%g> zLz^RAicP@w>i=QxJ>a9N(!cS0Zkd+MWG0izB$-Uhv}7i|H^PvFbVx!=LJtH&r~;vi zh(PEHC?cYQ3Sxm(v0`0&!?N$%cWtY?uB)s2Q$YkWm;d+NI}-wn?*8`O_w)I$OYWVy zcWyc7IZypQ&*S5Hr-LqAA6?W6UMbf;E21ayE(bjW8mMG^yhF-Z;SB59W zZr@AF-<9o-g{y?S#Baq9Uwje4$iLquT)vQeMD`OK{@Z`(i1?RH%Wk=O`6ltthe^S! z?_YEE2d^x2m8oZopB)izd0&(3=YC7LZfbbtB`%m17w>X9Q_OL*79{3L)>iK*RY?5X z3YJ|#%prAa@3F3~`Su0lM~@kQnO&T7sD@>0?${M=5VCVR6}lMm1N3cBK3T*t%G=d0 zCK_JG4Djj2%-tlh@&0VAxs;oUGP<2;l`HC5R=tC8?3L98sOH!gWO)WDLA(+fn-`y? zl1@?#J_%+3y<8CYP->%+$ zhi=`sb@R-{GZ)UAojD`3YuuRpT$uG4)^u%>HX+V{+iLRSVBRwj4Jdq07pBW8XL`sb zpYxmq3zg=4fRv<#jFlTkETP^_9Q=AzXDXudMc$!%@`=e#Y3bPe;wXUgCLdUR9S9aH4{`J9lx3i_bF4gT$O%;5_6I(3liJI)5_J)Fy8(PVp z+PVs29zCYM24VCq>*{lY)x~)>=ZI>n_>Cxvr^NZ6bZ6(+jvv{PYHpq%?7q6r9H%jo zBKCp&%o)X*8TmVkGP3fLGcBEBVnJ#~sh}b;IaZg)K)$EksC40!uG{Cvr{`z2Iw}{; zst(S|ZFf4_^XiAFhkn!j#BWvVabvH1>)F}ub1NFIsAuDcq^B1Y=cecHD4$n5W{9o3 zrhJOSIx?$afjz6P?~3)O@7{h(;pWB(d*)0!aNqpp8v`k8zS%!~Z#^Y?%(ysAJyksu zP8+LKEwK?8tRDE$4m0;LN10>H<0K{+y=5gEOE#=#O-3q%oFL%w(dgr+i{f=_6kt54 z|EFIAq>(;WPh!_leTAp`iq4>A1rC~uSsjm-W(X8>Y&WVB#v1jp-3i19myOZX&BVpT z#K9zqi|J%y;$lGBNRAC(TuTIAKu<--u zoCS7A_Goc+gD!F=_Fd9-{5YBZPWrSl*!)V?lSPacg}P?km}%)d z++!NXwa1XJ^kdr_#<-7&pWbmu{PZ`RpNKn1(e@Irw}gL*jAADYzWuStJ=tS}?>T1B z2M&^3elEUZ;9*5^&{ab7Nb4(vydvKFeAnUM%$l>IF)L17<;xd_&Z(%FGgK(>k#*`6 zbK}N2vwm}U#+a+GojB*_=8-opm~`#dF}IM|g9J9qcek8Xk_Pb+@-Q3PU0CR2YmnK( zB#1-Rb;`}~`y&tyP#M}c2B)_Ybrgad_!FfjYp}keIVQSCDX?6ON~h2Yd=v*(j_L!N zDDZX-%W66pjfU-HSPk1+Tny*7Ln6PiBbthzc4TCvBkAPK2*Cs+_xvieDOK)SuyV|1MK?Hw#@wQ4l_JK!`;28#6dwcI><*|ERUj8+*u>TzCed#4}+d0eu&qRs! z>aoB%8xSdIMVtV(*9a#n8l@05H>H&&>V~1L0(g0)Vh+(L^8>6(qXZUN;5R^-q8Juh z-cgOR3_VeVL=);!=z&VCQ7JWWlU%4?(NeNK-IFJd9X-4{c35n%81v_GB_nLf=zUr$ zHZjs*5?&ZR(9@`JQ&39_6|gC4fzE{l-@*>6c8BK(phihMhR}pNTacEtq#)y2V5#Br zz(ti3=aH0TAA~JAK$OduZD}1bTl{$$w#^eaH{P~o3n||`VN+uZiQB&c+x3gt`Ee9{ zAG&_6_?OEkY;H{RiQnF`i8HHBZb-5MrMP)W>xc<&w~p)~ie<}jxzRKA+4Z%<_Y5DE zr%mUUY+kmEsCt@Pw=7>O{@l~tvZG=1#7(%#mfIV#vrqhcYvZN~E5$F@hIYqO+&|mB zWIevA+TBP@Egz~2@(Oz#dL>!b-Z~-}%4prZY&mj&N3>?>vqx0k&`{Tur|lYzsl+rO zOGULCwowd|f(C!r2d|wS@N>X_O=Y8nDdX5EZfp~)iE69_L=-qtUR{Jl?Mx`7D#RQG z04#)Pp%2S48ln6s)U`xJBpt%oJT4~!Vu1I z5V^=_aQX%$$$zrCr9(?i!JLAI0f8dxh%XdQ*< zpfV!ZP$<{tB(PgyZT3W|Sp`Z#()K*O2CJ3fI_Q?8m54Z|xd`B+GI~i_WMnC{+9mM9dx8|rtmZV6s4c3P^uIP zn;%6a?RK1&oM1P-Ak4Cx&b+7;W}Vq1@gvyxh?`u^Ksf-qeYI++4iqnw*jZXR%rCc99q@+$Hvmp~kJkCmpOB?fLXvz9dMl^l8eo5%d zF==rL0MdSvd)M4~cjfedg2p=8r0}NKZq9#V*|hgxtYu$t1g9$Djilhwc>2`Pyv{ zmX^{uX=zRAaD9osI3wV4hP%6IB#wWnI4B)4s@f?fGaKxJ5+}wJ<};rblous!=p%>I2uw|}4b!~R>v@Aqwak&Jxd1u_EN;~sqB ziZ3TG>$2NJ4`;0y)^UAXZYEoA_xbG0mW=8MCFP9H@l;vZfEWtBmz0cQgr@%u`0)~~ z;~1KWjVSy~W*Kui97)$PH=#qt^H&ga!X|Q$?kU%veEl`FcJ zbuU>kck;~1GrFct=osDFSUQ#YQz$D8*!mp&yW;w3l;-Cf;(Ciag3BcsL z1aKqbQz9Zjzm!4(5{Xc|!;|LSYOwgCyc?R^*VWdpZ*T8QApJ9E_T;kp zTQk^zeQwWzeS3Caw{z>}jT=_2T-rN-ZclgD zw8<0OAv5Z0hYht2v6UAU+mpI|zYsl$rCK}vR8qEgh;7Zl<-3p2d3XD!@TUcy` zXt*X_O|pL_bsO@_bis0A=Q^rWYnrM`{S6t<`Fxi2#(3|P!p0@Ts#lL0GhCglxAMwSu8$U68gc= zbELLi{<@`F<&3rX2-iQ0=c`K7YBMiKI%*kjh5C=bx{7kw8&tx_+qpr6Pm`fHQed5n@i*a&dnCQ zns~P$#HhvoLyD~G`Z%BE0ai^;p1zd~Y0sNbTJ3eTH?vpZ&*=8TX%z)v&5D8b zWnwD8*AD^J@i_B#@OKb{yd5=qW)f5MLJ}8s4PsZ&R0IH^1c*$;rHFDhqcugDv|#lr zjb5YDuK}(-ku@iFD`?69?MGw*{2NM*l7Syo$3&ZS(LIbw8)NFADQc=HO;2(>8y8FT z>Nx#uMr|N5N$MB~h@^ysq&94l60m|2k`h`Tee}*dSFMVVfAsN3AAjuFosZo4(0xZ% z9a?qA?YG`?^9|Q;+p@85?V1(K=FXM~d`!#8hPtZC_=@-;Zg-#qIagl^ERd6KYmDxF^T%|Jap9|Mg{{Aba{blc^MC2D0#Fy_+?1R5cIp zn(|=VUm%I7zREpBOORX{hd;)z5^PpK$Dv?}cr+!QjzNM}5h$R<$AM&kGJ6MvHX{Y;JBws;fk!au}0+D(mvv%C3S;XUdR84UMbZ z{2rXrPVaQ5BVFYR(7oiuCc0@qGh&boQfxhah=-pmnJirwhr`DINl0^szOSNZW~Dfa ztMh9{S*;GQFVT@@>zJ9-Q8N6hj-3AQaZi0rk~J;a=Ax&1U5R!}97r_TpeqXIwdFSz zTI&6UlZq>fj?v>?^pU#)wwT!9gQMtv?aeha>2_x5uY(2B4k|#Pq72Y6?ZZL!?ha-J zvys_KbitS!bl+%%jmT|Xv~B9 z=|ss8Fn2`9V9R$ie3UAI6HLI`Boh-_)IlXNnYbxt!kM^cOK|MJxFn*!f*KjH|GVpU z1RFMOTDfxk_|(+oWLkr1)7DK}w`^Xyab@3CtH-YxzkJE!%jVCXHDmhJ$+Rj~b!Bm3 zYC&pVRyrooo8mynkwiH4X(qLm>Z+7(C2a%R=S9?Z!7+(tN3uf(tXcWj=7GqO?2Vv) zPh}X(Cv*CO0*TC_*bLCN)~h``8m;cp3IO_tC}%HG&0!X{gM z#>0n=K1;Ik$YJB4Plu26*z9)0(59vSgW_lOgZ17zopZGR<%JcNh=jq-Hbnk`8PtQh41j#ZA#P+7Cx4;|q z5OK=MZ00Rjv6|?mM6bD?X7<9|yBl~A0b0rhN0jG}KtG{baN|*dPS5IT5-{x-rIy0E zu$ZA-gVUnRt&UN|=-{)8LC?V$C@NY;6|GePHO6T4(ePpE8CI=lsdvj@ARX8cLuV}R zZGba=DkJEXdI2iFlGQ8G=N}@@ zTr|=|{pa|9ENolK%drH^W{y%bT?}R;xURHgkQIHZgUA(MCH}8tC9k|sV&}3`p5N&( zAluH8#_0=34asSQ?S0eH`HF_&v)`IvbGr)^WR%J4um=;xKWowwT?K3))tgc3wPr>Y zS1gFHa5#LiXM{p`LYmGyH>WPyR*>vS@jILAu38_M_|n+9XIJG+8Ma~i*iGiVsa0+3 zU00RNtX|N|-sN3Cu4-zIMf~&F$0m(gS7(mD?9QDdDi^M7xnbo$jdJ8erXHL znX%516l;fIG$Qw>1IA(bb0Nm)^5=E41wGyHP_Q?wTJ@ zlE;aI*vaE3PKd+B&$#aZaVJv!4)IS?`?T=B=%PL*pcwE+Y

    TI(vq!`rYru^=JCU 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 literal 0 HcmV?d00001 diff --git a/resources/customizations/fonts/MarelleBaton2-Regular.ttf b/resources/customizations/fonts/MarelleBaton2-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..14bf32638875fbc01b627c01d1367d7bf48fb448 GIT binary patch literal 261052 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 literal 0 HcmV?d00001 diff --git a/resources/customizations/fonts/MarelleLIGNES-Regular.otf b/resources/customizations/fonts/MarelleLIGNES-Regular.otf new file mode 100644 index 0000000000000000000000000000000000000000..06389f12f8201529fe4cbf21059257f985f06386 GIT binary patch literal 1512924 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%0A=K&jbpc1$YUXdrq`nzI?~m%#;1;54AwSK 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 a?V7~naDX4IcFm0Oyr#TR)2bkoF5|Rhj}?? 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%0DYJ4bWj=1B%*5U~xV19-1}gKe zsLZ&CwYBoO`PqBHoqcZQdQ0Cos%Dme_nQLn(b8U5gJ->mgrp&lClr>Q` zW!`P9%)3>TdAF@H<5pH?+{Vf*Yfxs{w#xk4mOsEB;41Msd=C6W{2};kX05KwtTmLG zRbYrj%%f~h6_hzur_8B(Wlk-i%%hc+IkK{XSGFoMVr8H^2Y}9S+&1-ebuusV{wS>t z4l4uxcg<+cdd+st9?dyzfVMYtu(A2)*G!#qX}4;333?@MUW`!8dq)V&`&-%j*XIj$ z-n?{+-n@ixVM_jY3;(7Z!WCV4C0(62pV!6ZfBKDZUJ2ib`!~72GtFBiee1o8FxOVW zELRn++#NHl3bScH%p>ub^)$+?r&H!TJ?5>YScx#qx&d?38qB#HFdr4d%y9~{>i67j z%scnFU%29+^}l1S@q&}FvT$P|URt5;Xd#WyQ zUEzAU7peNf^@AJgeykb+7vp}cF5?MQhrm^Ws|L5uy-2;$y-K|We|Ny`hT9MK1nwmq zaWCRSAhA~QwSc1F`SloA8{jsfR3(9Di~^o93Rui2U@@bBYfJ{NF&Vf_P&06$X7v+sW_H+99Ey5db;@use*Ls!(HEA|5GxapvG)6o*UP+~3m#xLj_zo>?Ko~cH_ z#en;bv4OM?;2z-{J%#gqt2b+t{~ghIM>O6Mjhb{tO}e5c$*4&(Yi&WR*AH%}ry$;65brODeiw><7m9utihdW0K6OheQyrA4PQLyVi`I@+ zb?~@UUEsRH^+JpHh3f}5)N>0t-a?M7b?cx^b$oqAsXg0oh5*03IX9i(4m|O$T!BBD zo5LT2JC3*$a3>Kyl^e}}hVXf$xc~6h0n1fInSIMza+;qPhG@;q?p7vKn-4ClzbiJWgD=bOm+CUU-soNvBS z+Pf(2X08Et$-$^`W&S9_$KX!FoyNN8JmN3F5jYvn!3AsDz(vBfg?k^a9d;KgwI5~$ zHoosFEvkH1{6^lKx=H|>nX9QoM}w~l*)=$?bs*F3%J6f**euQUM-B`@90h)Cb8u5* z!9l+X*@yXmo(1%uy#ajTbdYMKjCoR- zyxOt)o`QRbGP88ABxnCqWmH-hnKMiVD}%Q@=mkJkyz3wO221tMyGkC}XluyuFecJ{ zlD2o{^H0Pnd~5~7q_oycwAM|A(L|p`e}4BHeBa_7cN?Gu{zdlnj&y$+g%Wtty6ur; z6etG%;V=6)LGj<^H9(uCfhz?rKb|tb-F7~l9+TvF^I~;=S4RJNoKMQf{<6Fk`H;8I zGD#8otkUAjTYcjXrA|kWy~HF&2))&Qh-3LEJpuQE@f)Wqe7*laENOMLl2ShQytfT} zC4X0r@9wK_r~H#te}XuDJC{HI?W;FyCA0*_kP>38jTZ9V&7TKSya4o#uTC<@t+zlpcUD@veV=(wc82|99i`tz>`k zQ|XuK=v$07F*G}CQ`8F>a@V`+f!e13YnHG2G@i!u*{rYnQsvRbxB9p5?z{iG?_p#- z#Q2|%Q$?Xbf@}rCHWYE$K(}vwop=7HJ%e&jxjde=K#0V-6I?gk_1IlcG50D@L58Xa zZg;DKEI$SmZ$ahWHE$YkF79rxWWAT%hmcF8yIXFQyC2@Jr1qxzb01|$!~7o&gj91z zkG%iT8jJ#%QHGZ2H4i~!f$noZMqTz{z0e3HES76_pY{xL@A3qC+ZR3bCi+!6J5`0a zWcT~1|E1iGhz-iU}Jz9OBDfW0zv}GrqiU0 zfQVv21O-9|0cj$3?1-p{fL&2h(WlruA}Y^{sOZCnh#j#jDpLO6naw5vL-E0Tzu)iw zA)9;e?AdeAIro&AIn!=D_g}7KEv2k9zRlesPw%qtGh?0-W#6T8yZj2j$3U|)h+!&P z4;RL))fMrAQH9lTgLum+Cf=jJskRDVf--MF_HKXHBSstdsD%FunXJ#s8ycfc<=^8F zSQkrH!~bRYCH`Cab+_}wvc_>%`F;BqiqoHR>QoNd9tWK8H~$o)Oy}6sxwEU{7uk=@ zqIhrFRlOedPiv{#pM5ty)PnJ57qu3$DFsqpoxOw=8@4nlFV) z+lpNdt8X7G``!ac$dQD zWFKGYUsHYN7`4D}PD}gyGrp|gQkr1jkqXRKVB17mxeGi{cJp2W<#oj7)ZZx%YKE^g zZB^do5_TR7mA>&!`-3$EJ%bn6`P_)t6?^`8{qYu2-jm$T5&x?Q$J73LtvnZFNoy&O zKHYH_Rk4iSx3*&L{|rnIo?XuAXp5{jSC`UQ?eCqgw~8%_^=Lfr-po)f6`r{T@~X|W z1`JT@zoGK1@nQ5;!3FeE>@(jeE#C|B=&7j&dh*;=Be2c zKDLoPQ5bv{^WfEe!F=L=RJO0H6pxqoYdLQIOB2k?^Dn7?Nl+|5U6v4kK>wCt>mc-H zcv}nW(+${h#Qr`ky;iu;*U_!x@iU#pJ>$3bk6Eg19i}@4vdzSQ@0D$}7`aB3CCSN*nsL?9X7Z zJ>H6J~1huwJ4U0@@*e?FC`saR``xU>BvCQ zXU4{gx;n-(aqVp%ea2gMypiwROAW|f!16aBwE~anA2`WYUYX2R^ML{Fmlb-A{Z*L9 zy<^mqwHV`e<2fqewfJ4zU*mWze&yGyV6lxAzLQkC#!KtwcVg7g<{}{Y^6g8EWRH6UUvDF)mwKu!%$F`FoJnw{66SB(Gl-f~N+?`T(EF?WIDp)J455M~mwM#xk; z;_>X2Uv;f$A95|lB-rfmXRYc<`cL-Fc))Ez%}I|=0%Iult4^;rq6ar@U$(ARR@PVG zmlc#&l~F+AY0siPtb7x*#CS{ET=^e&^t2toB}gkL@eO+Fq-{Uilws}qYYDr;HMI9^ z?tCG3m*eZznef*#$g_~6bgq~Gu20J<_{(f6&#^rOAMm6~TWl`s4snCl&8$SaRTU+F19(HHxu}b1C*48Rc*!ka1@eHea=Xb?_p{L>$lm4^X&<5zQ z1}jdjY;6(WBVI!J)mD%41Xl0%YpLQYE5D<1hP(Mreq}K4EuoG(G$k(rHQs!{|Qx!@riL{OXp^X!oPr8f|%h%it}a zX`ZdkNSlUk8ObkYJZiG-pSHYjzs-W;$Nz?qHa7NU+YMWOCw2vKyugyxxyOyq^?2r; zU0KoSX@d{ERb_|1UGQE{uu{h^Bz3087x8kGuFRS zPvW0#AECq6FmtT}c8C?S2j?BvcpN`)?ad6K$1D5W#k!qahHJKyktBqC#%wDmGiYvKdx|L87OB%{tLIW;*-+#vgaVZNLq6 zq+dtHd4uf>h}WR0@%gz!4qIX6Yf$HUJjZrzjjxFt7{^LDiugU1T$AWaVsx?==HkPm zmKlr6InDC?M%7~Lgk4E|r%>K9oaL!Q1{|13kOCGWuV!Un?tSyR_JRTv9PDjx(rD`=5D4AE`%vDK4p)cULgI6zj1V zg)ECZv#Wb5|84s|DxU+itZZJ!$DOex21DiL>^zk@Kr3V8YW-KqI<44>UG;ICI`2@M z?lDUL;!j{W$uLp;m)%`$#&xBoHwZJ=WNtgXMQh=SRD!f3hSj%knLb1LbCA0nTiUuS zEm(U(aY-~rFLqkp|Nb8ecfs4xrxpIDDjbswRY=_t)c%UklTBq%d9Fr7Lp<;Qy-ylFjG-jn=Rk(O$0F&4sULF#{FqO{BY8YN%#HA0K8^CG;l11p&*k&*cs?J0t!%uLFP2<9kFUi; z`zE}#TH!~0Hy+Z9@eS^bR^buw@)LZz;RpPT9F7;)i`4%bUcN`-Ghy_dOd2MUQgob^^H7-N9>>SGG4GD zdDA?--Zf9J_wjZuk~QY(wFytJ<8dh-=niob-I4A%Ck_A9=}t9#Qm=Aq;f;EeQ(t|* zoW|<=T8dOE}um6wGT0Nb-6=*?LB5eJ@Pc+qi>XG3atKjLG!6k zU|vM=`7h>^$f&gf*7*^#`4O`D5wdlcVjl6S_`~;SCh0q7(rm_LmFNWehZ&Q=3|)8ti7FnQvdg+=Kp?(`M)Qb|9dhs`fld^Vm{58*AFoJ zALf(A?0y7T=Xa*f?@Z?RbHpuB5BHYl;obtT#TS5IgwXm>XP>6>)qb`D?6BfWe4-G>|p+t9dwOJ zM_pr_Sz}UQ9+$=Daan90m&JH(r%EUD*Y0F*s_EkW?ES29Bb+9zFNa7G8Y80%qZS}G zguW-J3o|MaSYu>#!7nuxSYu=ang0=Bjgip>3|o~HjgirsF|AIz#>i;R3_k!^V`Ox( zb=%t3ZGo-ZF1Bv*BInbTRU40yQJwi2kC9QGU*a(`sx#l>F*2&#s%~Mcx&v!E9x0;+ zwH5FT8Y!a&>l>Q7jQG*p9kCaivB4yNI{l_C^)UZeyHNXY&NEtOOQbrBK z3-t^yG&Q^siGA@EsK=V$s%QR z1QSf<-7y+3qm{+W2w1#~0}U4h3>O?|xFBG-AZWOtwc&ywxZqOyU*l!8ws;vqiT(Wn{3%y5dOzD3Qb?{siF;AO3`GwNIHjQZfFqkuJb zMtzH&QQu-`)VJ6f^(}TreT$vZ$YN(Sve+4I4Rf`%*crtZJEI(b-6)MLc19zMozd1} zXSB808OQP?))xCTLg_p#+)5(n6Z(?(dcGzG`d+Fjcyi4qnpLi z=w@*=x>+2JVvD0uY;iP-EsjR9#nC9XI2y$kN2A!{XcU7nI}j;D<7hNCyxG{|XcSu< zjbg)|#TG~7V0VZ+MEY1Xje~h(*$7~bsnOUS3sybGB5O2u&vefM*7zEYExtx`i?7k# z;%j7De2q-QxtSJUqlv}WXkzg-npk{|CKg|#iN)7wV(~SaSbU8p7GI;A#n%clsep^TBKT3i>emY z;&6)~m2a^vs#$D{REuqqYO$k=EW$-Qi*V7-B3!hy2p7o~;Ue84T!bycMQ4j}5w-{y z85ZH9vqiXwcrSU_{d=!?Sg={Ni>gN3dKzu(VUaJYTI7pv7WtwobS?#Y<$!;)IlKPh zes``8@AcEYMG{At=opuAb(}Nx48C@}?yP#fvpVOx#4~d3ZGYYDcb6JBLm^{(#h#_t z7F_cPNB|jn!=0g zI9qF6xycEawx&BJyR=Z>lPJ*CmgLa)B-S<_wlg$o43t>klh^}{f4%fE-tahZ^irst zz9(@w_;RyMbo4!mSKE6Mzt{I9I!TIUoMe4ZqLZTUNp#ZmJ&8^_>wKVd7%SvS=Qfx3 zBs$OQn-HC!tp&Yk#W5UuE#PRw(UC)YE&iMCY6tQx!#KwL?Ov%cPR=h0Z;9A}{4qg~ z-Fzpoo$>otDFf79##!0*&rHB^gpJ&ql( zjY-Soh+mO6hKe{UUgNN)w<|q5bJgSD{jT@L%cxk+4(W-Ph$OQ55~pxX=lCywryTF zV*|&3`}y6i~^^fNm!f{gRq422ELx0=d@0XD0OpYm~ zhr-iK5B+U-zu!WhIUKV%uH*Qh{H|@#wrD%zZPE6`5B)8EXx@rP#rt-=Uw@0|t(Y%f zZu}ZAyJG&z?yFe-!bBoOB`j4gC>TySm-p2+5#hX0&;B@r?Y*>qdxgDimY!zmz4R_W zs&^5kO@BRHQ@r|`!i%qggGVdue`Pt76%HmS9Jo+nmz&_nSa+PQWOtsz?(LQ`(9Wk= z%5XbRvU5A-%G|DY?qlZ@jZb^t&P(*{{Auay_3Rhv+55=OXIgr`ou}$q7U|hpXy;Sy zJkZiR7<{Omzqa#tmOf6;?%|fw%Fci2IWSGn!H#D+%vEntG$lFRqXt_ zo}Kdyo@8(={ab_ASo-A#&o}rBJ6~q!W|nU4cVp$>W$Ewf*DpP`EGEB z_hIWeCY8PqyCeFEZAg+dx5}qfIu(0|wMwN_CY6SiHWs(F3Y>j4IN%z{pSXkjYE^Qd zY7TaNXRSel#!Ql%1`V4~A`43te$d{#{dh^qDdT0ykg?-Vk(Y*z96Lx>*qgXljT}32 zlB^puu4IgSb;{5oBjvlXlTVo-zl@tOWUOo&&lg7~j2SuH2~He2c9>Ij;>7G6rxxd^ z(};7f(}HuJQ^Yyn>Bzaj={a%o;EB$06DN)P4YPibEtXm`YVT6;|INTKH)WObYjY6!$z z&iUF1NcSij-Bu@;LXClVV>u9O*NN4myCjw9>lu2)xju52NyxM2$Wr;;DR6qbGd$nl z8k`hd99*1md+`0>lHhBcze=c`P>?V+;mU;D6CO`|=zoZ_Qx+bk=T8p%v>6^l#^jUfiPY+k;_%7q=D(_aUS~at3XXII0x4t`@N2#*5 z!go)k##ma-F3_Hu@8YD+;G4diTYWHge6M?u)YyBodG~wj1Us~JkwX{>yDxPh-(o53 z9LfD5-z(myb+qCam3>ycuW8wRTI->HN58Y*)$e9|RxMGVKzo>7D!b+9*d@Qn_Yn1_ z$ZDsl)z2Hv)8Q-lQ$2~UA+0;X+MLWB()AORdW=Mfr#pnFjv|jwVdvVK-#SVs`l35~ z#t3`YKCCd+i&RJQc@pbPqXXAOsyVh)o>|)@nRQKusagtRRGV~BwGIoI5qDz;)zqYd z%}gGsx`ZduAE*p48!6v%>V92TuycM}RbO>Hg^p*uCGcbR^if(7dp5E9U3)&?o-k<7sG7P?v{9ck#hx_HW}!x^J_!w* zwkTrlsA?^!ZgtkQXRl>XUmHCVxgk@8WlHa(UBxPbZIez4t=iTlyp^x0F6fuJ$LAs-dU6VKj}Y)!9;*F=s%2H9GUHEH7UUT?3r^!56A z{p191ls8KHd6T?Ja-v1t?Qaou2YBu;2kkvQHigOD}e&07T?Cf59L?+tII zjP&02-j>nczr26R7^1-cAg6d6y^S)?+X@Fb-gkV+te@Z~$VC4j{~(#H7zi1~{I+n;@1qPC;}G9dCd)X#4bSFH$aV zxwkrFdGA6>_?IV1nOk~ak>#HfZ$Zl0W$9Y}ncjtb_bp9ly~<(r>LWk(+&bO@y&DN- zc`wFjTLPI#Ai>pkm8H4P3-U2|-$#2Df-6cvPg)avRt-Ac1Zvq3ZmK2Y+8ip91D{mH{47LE z-X6W?q1cvmL!NsW7A3vW-5!agw=cFN$D^ejEQ4eqGS#6_uu;fWCt!gv9-D*7%>2`_ zF*r-k#TxknB*Amg56(beI3HQ?^=SBRL$`MqTL1ge<=uzI{~>uCecjXO>6W6OTZT67 zHF*_1+$-qa-bDMh8lBs_a5EpEBTGd#obF^e)tstM4YXFLJ5!xA&|#hDoa>yA&izv7 z66Z4K3TKux&zbGab*^!)cdkQcb*poWa~m40yPdn7dyp!>>8y0#MhEq-^Re^3v&Q+z z`P5m5*6C~KE9V<@P(M09I6u3-^9S0eKbtK6&IdG1{ITC^@7xbM3kxu3Xe-LKux+^^g(-EZ9uUeNv7 z{mK2+{lop;bKK3a(%Za%=c9*7CQf#$mqD!T1H7tUO|OPm$E(d)e#|UTj<=kOhM5y} zMQLdRI69@)&Cp(}Wl}D9UEku+8fkbtqiUVe3@BaeiA-E+_%ZMu{fv^IY~0mw^v9!( z!j0RG>S`QmwMbIxdns>8m{&%F??5xFbod@Lu{+Y@=g_JuJ^rV>Y}D}$qmJ(=p9R)S zLdKtl&NJdvajJv=rZ}fL)6hkp?VRIGhhARfTa^jPeL;{)4kli65ZS!_ZoLTI<(d9d+vu& zrH`RYpF)|wfHr;Oe((O^{^Kbstybl0<`qk*&FGJsc1(r+K zkUMO=lX00Er?ayjQ82J6=7_3qZSdL|o;yRb>!CdEYZOnB(*Ct%A<=T|U^@{5rtMH`Y zYV@tAxMSRL?nHNjdxks3o#viSjwCp*QSNB;v*X=U;XNk9eM}`iz6aAij?xK-w?f3n zBEIhlmeGa7j527x5G(Q~R+Pt@Os<57(g;qI;9k#U?OX@fx(JT-QMlD5F}?~O^%Lv_ zew07pu)=UxhoIeW3paHv9MmbShndXv2hgfNhX#EW^LaCx?hLfr_0eGGz(sXq&JN{S z&S$RPjJEiGG{euL1%89My3u1lW)>&^?!M(CEE&GVYGDg2_5dsqa^SkUU|TQ%JA%oq z(i_puJ%YCXMONbH&add`QqjBDLC2m2pR3kJgXr&bSWnlZ&%OuU^;77nUu8Xg?-p%v)v-r@^R?m$MTMWE8Uyih3^|-;bzg$3UFUA{l;@7mnw8Y`seB_p%b#%8Rp6?#oI-f% zBjBHh!ZV)(*1OYr$a%_n-gy^$wf;JgL~ z{RteI;#PHQyN%pTHxE9&7g%uweEOwe!v*dl_d)kbcbWSNocek&UM=csiAMLoGh342 zD5^s3GNEt03m$5A9B&aC2gdscwB`*gbjrujg;5VWAsfrOPCciA(}*!`=43i8oNOE0 zc20Yzqtlr&?(Xz-dO5ur>*JihPCutVV?Nj!;tX>}F!p1e@y-NilFfn3p-FR~M-}J7 zJJ6pGp*??{6Rq4fZacSq+1xl4tTWX;i#c+Edy#vIJL4~NWu^O;yUKl+IrA~p<_jpz zCMe9GP!|t+k`6_wZq#IYB^al|uC2m|#P@Hyj^lf{gUfbtx~}6pxh`dUxueQapmc{<2|kGL`QmsXzV|z)Z1=Y#o`~-T|5dgh{Jv~Qm{7JSEMHT# z!NFmpJ$Z0Foxy#_z_Hu|58{+!=cW~QxUt=B1uTzufO7LkdnWHM+dBlI!kXS~$Mn+t z7x5l6c00~W=D*MSPJv>_==DLRoOPV9j&ap7o;t=+$N1?uH?6#MoRd~QdNMq8IR|}N zDb=5ETtke1j&aWq!8t!w$~DJ$X62ZbU;bbRUU_>?xpF>vdoHI7y=mSV>c`vzT0dFdsyYF$AX_?d_bI=*1eGOXY-8jTY$aeou!;~oI_9!I>tY*0IRJ6uf4wm z-@HB7TshCYJ;z)*zq~!SygjenaXU_Vdp`LuoYW3{bLCufg$|ls6?^#(R=3N4j$b`}b1m^!EFBe*}Be^>7#) zp@BaA7={kkh8{G96686ppaNaN|3`!QPXgzU0oP9j*IxvVn+adWX=2!J=`Stw9ex@Jwi{MH-``!KC z{&9YPe=wNJW1sKBk0x?XX0Pu-B@SdS;WCRAlVz}{aGBFJIM-+Q@3L!b$vKyOzsr8H z1Lscc`CaC-dcyQ!zwaUs)Ut=L*LRuC6F5&|pYOukPUCzgdwmZccMf|LmwA0P=Nar( zTxL1kKD_Tu>~~z|`i-0yu>W_N?Ta}-$ll+DCw`pslkERpc;lsC+&=F?nIIEd2SGX9`7PI4X!@IwK}|gEv|Lp z@EdT|H@-FF+5&Dr%C$fxr{c4J)xB$PprdWqI*{K6vlAFb$|#enG9K=^N?A#nX*=2L zNV$Ps!Yy2HXRmM<*L&G9@NO3OVfGD=bA6iK!&0suV~JrG(W+fxiR#K`F2o zWG@#o3S5^rY#yR-OtratChrXmA|=aW-Sz?3Ud*=^>^Qr7$AEV);afJl&mP{f;9zXY zk)-9awvPiJ&){1gyV4`P%ZczPz^irB3l>74-1zMOAJe8C0%z~8g@ z)`nf|QQnE*@+%O~9OPkx@9~~D&h@?aoEvz|X?BzyIXCh;aX#3?HlJ13g>w_HE9a){ zdR?Aj4ClkWQ#g0`#&YiAjpN+Y8_)R&?^MpcJZ3*_naH`fH;MC6-ek`Gy(v%)T^X_c zmguoWf-M?hB~+p>k_$g`$FIhcqAkSUAh6Mf~nBfc0U&QNO}!v?~%8o zsF(!yLT`E;(&?ajQiVkNcL#0(PD>OSjCLb9p89FQh_ASJ8+Z~;0R9t630miK`_j(qz=&w8FTm~sILt>bMT_R^J3BK(W@Q4;go}%a%zm7@ z4g_OX5t;usa1mo#Rpe&s^REYsRuj2xA@B@%K5U)tLed^Q0Nh$bFuihw^sN}VrGcly*{&u$Ry#*xf3|4U@oh2r#C5BwFfY;*;E z-?DV|$#VugVX%7UIfHMZ4VOUmT8lHHsljd7J2hXa?JSC2E1F$!G6UbCGzQz<8K zH8Sx-#W{PZ!R@8JIOqQkJR92CL7Yox7~B!5t8)co8Q20n?Ig}Mv=g{9ALn}JN-*{w zUFTNjM=%Ngv8yB^*Ls8%as4_ZDi@-4W6*!jmV}Tvy+a=<5!I~?0 zI6TY{aeF*&eLIx>mV4Av@;nA-18;NuX~2KLwGS6}0Db89K(jGI+(AzP=b49hYl5DfqtAFBy8)=m1rG2% z?DL>4mvFCtnR#%!mxCw4E$YYVUd4R#uS6aXwV6AZHn)WDg67BHgBri%NJuGs_GPo6IBqaLwdN5(f$)x6!j!yd6b>K*I#e3U$=n&+E$6!_Fv`w(Q-$KD6L3Z58_ ztRH>lFNZI_Uc8gL0pG{&{s!?%HUbZYTfR}e5sJ_I!9m|7-WbaF-$!e3vv{Xo0o+$^ z;p0tay)Z`lR!?u5uIm%vvKNSV4s``;pl!QNybE3gJ{aEncJVINbu`?(?7SvCY-tuA6&o?`GlNLjplpo=_vZ8zWPNopg7l&64L=e8v8zeHm|fyJ z@t>*%ybekGr{XW6e9}MT<1ag({INHj`^)bJUe1p43-MnaN4@psOFsTeouA9)D?a`^ z$B{l%)T`5fU-84m>^|3v|8Ym)b;$9*q5B$H`UWKJ{#QzmVsB0NzkQSRbLBfe{!hBr zK9KME_`hXZ`VUAY{6Fs{|3U0!e*`tZN_q!&wLeK9kOF)IT7sV?kf>wS0V)13u+Cot zuSGZWs{|s1P*x# z_)7VcPoRaaseJshHcKFSIq)j;Qw7uIpl&qw4ZNuNA;&qD?_6(MM^@zmUFQS=+Zh@Ox-J*a7t41bjMj`k({`O$0sz zEky#|{T*cID>{Nf?Vr&koO5oOOm`m?tfly5XcQ9xCOyo(`C2;rkz*k|FP(uRuWde^g zpWeWOntnaf_XA)xzz^OO7-9~ z>N<5L@G|&{JO?=k!FJPc-rHz3>PcWF&qX=)o%#}3b*trX;53lH>gtxiq0>+TAIzl8 znoc99kpw=z9XNtc?_ddhs{Qb*)7WV&0h_mdoF)#DExz4q=}n!cuo^$p|MQWc93p|= zFC+aIv?$FW?dMpY=15k8?j-UYjcz3qRuvi%=z~rxOM}7);bVb6Lf6z;f}?vFtUlYpaZPF4^~j;RN^l}=_UAc= zIfqGbYCqsYw4mK2c;;2Wmm{eeb7*U20GbeB=}GX@ERm$$4c<=4#3}_H9Jm%&*+@rfDY|=2`;M%{3R0A zz7kxnwCO8!nf6` zoVX4Xj+FNzZwGE5k229Nk~{|@Nj3iBqV(D2T zlZ0%=)z_d`94`rZZvoFm?|Z5w6psKdL;^iQ658Hu@I+^#By`Z{x(pp8@{z8C44&*v zmW1vbfJY;zoFWNF9uIsh)-I_L3a=w*wrgNqwi~#pi=2^~Jl5mRl`2b{~XG_AVj{+ZycKRGin38PepX;0} z36KFT|2*eBNjOW}(-*DsbV-=r8F)5US?5c_McV$8Ey_T`W%>zZ30J@;VE1~F zbCD!m{WkDTSpQrs3G+|2^h=yeB;ke!fxBVZb*UuW0^VbMXE-w?;STMewOD&yCJBpl zjJ`xhJ5v(wXI=Z9u^+lz5*}IvJO^vAS(5O$&XfMwhFu{EPhSUo1QOjVC1I(~$y?Fu zUL^@HUIP3ha{t+q@XG1HPoRsxS`yxf0(VC9J4X`Uo&r1v%d%^50oL*DkDb|EN%&Cf zJp#M4d6KYJ=j|f22lFN2^8vu0qBFi$64ti|*X3f7cAX@AKauo5u}`~R5`FR2?lXbz!zjGbQ>ZT3P5H982mDwYR#N~mcr zWxj*0++DcvhJc^Ia_(*kwS0~|3F@6Kq1=~%&%m1Q9^8660c)I_dnMH70^oiYAtKa% z4fifXQhpyUxwin{?cDF&FQIPGWp6H8mBkY3@iF;5Wa$q`=*V@XPr}aPK?(Ia4!9q7 z5D(!L%Ubh>VyE!1g!)wjUT#q*LIXYko{R+kQ3(xFTF~El%y~>gLv;Rk$7fPx4)A^@_Zc73F9BtD}5?ZKuxVOd82;I|x^yjcZ zc|}6^yTEs1A@Zt(9=sd)VJtXa!=+W{TNUhbUYF35ier1DiC7__B};(|u$p@V*Hrq1 zabJn%I`q$~zz1Uy`KE+kEe39joy}VkdSeRkAgm2vYi?PpKBZ;2!pUtq>{8$o0LEw();nqrGN;lx~ z*k62t>#EYkrC4&Vlf-IMfoEXX`KctOz<=V#|;_@o`llqGue??-XS1^zw^P=# z_pP(V*&>NEvw>g1c5tRm-h!c zwlqn6>rv7hxan@XB)+@a(!*|865oH*?#*yBB=O@2>Ca%-6_Lbs`ix&-cU46azj(yb ztGZPsalPV%fJK=}{O&a7KyP$+)g|#~o-uH`Tf?m(iGQ@W^qOu>N!)rR@O+C$lY|U| z{X14;*eNEq0d9*`*MX9hcDkk4c56#g74S)*zeTP|s`)kb-hocAt|Zl-MZK$&wLsZl=Zz0n%hm!zf_l72KcX$>T)IcwItADgj;lGO4dOK;>hlBB3U`xc9a zlT`2y_uhf7v9Tnzo<_Z{+r(`mN$t?HNqb#XE}%odU~s2=dsZcDeNBn|!0(zD%cNgCCf z@{=qUPtv$9q^Dp{7nP)mM*)w--Yr*>PJ7bQ^Uy6Nov|GFF^k%hbgr)DIp{`-A9kUx ziyz%Ww@{L1=z6~z>%byOnsp83ABy(0Sdy;R^?tS6%55b{^M~8LtB+On zQyU#^M@d?89sT@^+sVbNXc=SY{p@yjJ4@2?^MHSHySQB>=@obY(!07{C27Sl?rn{A z`C*du)~&#;(DZhbq<23c&suEG50@mBKX@Ob|LrbGYqb2wu?6fQN$ZXVehi!Ro|5!M zBJiVFs2?FoUq5T+Tb5(agLJy&~}bSvwXB9 zZB{z?GS<<3BpG>@rXS-TBguXi@F*N1hs3GM*^Ob+xW1u%YiS$qgQ~JOkVTlH6F! zsfGpONs`=5`?fDu_9shn3&nfKxdYvSlAN1K{!!SQ4wB@8xxl}p4<9Vat@K&exFv3h zB)1y_{E@|MO73_#_okpRA1cXRk0pHxcALW_xqB7h+p()0F3Cqc20YK=Iwc>~3-~RI z?v#8ibJ%+hJ^Lt0?)wSwlUNjwmgN4|13!b+@fb-S*cbSDY>-cpnrc|34F)}@mq z`P`YnHLxU{EXfz#2HXrA=P8nW$?L!;V-#qwpkBtOmb`nO<*aK0ojy$kpQtR63rkUFOlTcD}mp^{`68w{^$Sa)HIrIq}p&Y4%Sc9<#2-+&Xm2eIP6T#~eGSm!W-mTNvYKg_)hma_c}?bqwRUsB7ddS zzX5n7HX1ib%E7aN*Sa^lH%iJO6M)~shUg|q$?8no^04B#SyFPe-WT0l+*>3izb)|n z*a6=vDMcHAZ^ce`fuyw2vGXjNSW0{7g})KokJ}}s%SFIz-8;J2`vUMML? z7SW%1SclvxDaWv07?-=;yCmg=9N_!0GQL|<2CN0X6)WIHk}?=P7Vs=WS;}zbD;8r@ za<8O}QTltG`w#aYk}`e;@Jwv7?~|0t{eZu-SY|2Hx&fbqjr3wkIUBkOo`1l7KvK@n z20jrR;|C?>;>&=av8ZP$Gd2J1*s44%DOd80{w((q_Yq0CW*YFhSbRS!Dc5cSUT5*q zQf^YbJrN7+$0g;qBY_8CA^n7;+<7nXkytQ4DJl2-3H*RXQcGD(y0;k{n5QM>VV$du z-Dh0v2_C2Yq%U!oNXpZ%klxv1uBAN3`~+7lb(c!Y3p)2!V1NCbq`Y*lr7v@rNy=-D zfHzolwv?4&?wy8h%?pyUY6kG_?u+h=lJZ^)OJD9Tmz0mR-enfYEoB{hI(U_ru*6CE zVkU4;th-;9l=Z7E{T25WN%>Bnca%kZOZj;S@C#mj5K8n-M!^i3qN$r~iJi%S(u9MXMX9D-ZiuzMY9SASy--ZX) zXOcRUHRX@SQvP#E9r+P(SN99|3rQW@5O^*gT3<@)geQPc!e8qvNjbr}J!cv4omgmpBdHfCo%+q);BJuAO9ui!i=WrGk~-@k;KlfXeJ822wGF4> zIrP1x&TGTksfR_?50ZLAf8Zp%iGGySTebWx_=f!?sS8U;_pyK_(%C&cdmsb5!CxeG zF>60?65eCKO6nuf!N5@LvNlTUQ{dr1L#)Mrlhmar0Z(*)cYl}E7r`@u*7%zJA*rvX z0B2%TzDZJ7>UvMbw){^?eWwfX0C%&ySyJCuym~MmOAHc(nNB}#(t3`!{8hXvl6KS>;4OIMRh6{k7;ExZ^QuYOi3=@Hb+5Xl4W!@5 zQ^TtvX+xnGP{q7rX=I45gFPe9co4pwX;&NoZb`+`t)8UKZY<({hP_*TNxO#mk1bpS zuYsh^zXEt8wr>q3?S>11J7NLXNYZX*9KD;dgF9H#ZezY-CEeI-ENKgs9*x8%u8E{A zY6ZLr%ebbJb{}ijdkRaxLnQ41+E2aByk?U2@MeRXd(9>7@kHQ>uMX>Xi2PSQ<>lIxB4#!LERb4kC-I~5Dl^rx8T z#2J|2O_20w4+g&9o9IoH^ku7nAGLS}>C0zOZ+&mFH(AnOxrg+3y(!)lNnZg!=B{LB zohIpT9z~ur@O_vn>F>M-{1aXfr%U?#OX#07urZ$|>1&Hg?~P}~8Iu0lrKI=9N8(IL z|N1@3td0fmS(3hi_3p04e)nui|NafqM`FEuj->w#p7+*byL+yr|5g*Y9hST2N&2Sa zfEQu6i+|Eq0X`9{-SdfXplhwfA~A%0+TgtgCb&?-A)bZY7kL*+I0f2-*Ym~R#S%{E z*_r2;c$Y{xl0f=sZ2d2la5ZQ*^L&OkL&66f1Kb|_|H~v?dk*kF@C2AC;d&i_Pr@hQ zatSxQ8F;A0eh4@5fmh-uaD{}MX@6emUFlsZ;T9(Vf6NG6CE=((*InLhZ?=T<*U~@P z-qqgK5^kmQ@GftTH%G$l9tRG3*Lc@RxFgTvPsCn-u7nTE0dC~Y!&f!j1AO8)w`ddL zBhLk%=UwYvE8%09w|)=rIuF~^zJq~Bd)Ir{OSnIK2e*K@6gNotWY6Fmy&EMwh%qAl zChsN*my9#`X76SR54{7pnRknKi-dI&;XV5nHJ9^?S37_2?_@Ak?e4P)!S`6Rt4G)q3U5n%!zL`1czGv}#!wa-Mw?knbmhc@xgCFr8k?@`1 z8F!(@`3*19b}sN9^B$A%y+2WAbNqxKm+)f6GtImwyeB05&|&oXAd3YYeoXo8!C?BQ zB>XgM)?LHud|JXwz5@QpVg!eudy#u17AZLV!oPsO!pG!U3BU9#@OnHnmP+`wyMf;( zF4A)nUJ3poeVMmR!mAX=z8#Axyqa-@a=+lcAmI=C0;gDf;qaOvmcHCuF5yqkxAcE{ z|CI1&SJ1Y47I!%O)&0Qry_db0CA?uJd0JZ};_wgJpKXXo{Hlb1=DF}GdChxG!W%mQ z-{`&Wy)NP3nZv;!>FE^`-UfXSGp5CF8F8Y87tACMdwO_H&eHoG@_e|mpP#-}>}f3X;qUYu>77x0&RiC=T9ObVE0Zx;0Gj<^cm@s{Gd-ntTbI0?JcrSBx62#e#he}B$29D zl0HwPBuS)Z6X3cQBPViT7xHZJll^3g)a^)m4?o4n1G7GI58zZkRU(a61NX*nDor9y zo6@%Fe!8D7k<3M;kMYBPSR&cgDQByn;b%xBSKB|xkN9{16i(*Z8~Rmz;xM$KJ+z^! zUsWRQ85eJ+U(K&3kxul#H{7r8SC`0P4S+B6Yxp%J()}O6bN!lrO^NhkJ$f_z1N;Ld za@6as%C6QxuE&qZ3ffDJvgnAqMwf))>=}({d7y5PlIuaQ)61c8@Br^13;A$3g zC^GT};2L;>)sx66%nk1xzrJ5zBBw@y&-EMl4J0z@LEzi`hJHhdOjUYR&2Qv4lE|5( z3_jRDSR&`1L!JfH+*l$PFjs+__)R2o@$>Y_6Mj?l6_FW=(`swXZHZh?KO{8qoB7Qo zGDqjt>3(y+xkTm{0Uv-@TBby|m_$Bd4!fWGNBBobzVW3qirTm8D4MdDPzV? zY};VOq)FpjwQPCXX{WU~Ew{zE3By}Pv$L~XlA}Srkwe-x7(V9o@guSuv}-ed(4-Od zhK(FErfq|UMa2c3y5u*g$L~jwJu^3Vgx*z>QcfRjL0d@ zFUc?D?&9LCyc|6j7f;E`kKI|6l^5lE?0-ZSd8cIM6-0M(Q$b!K)#VlzWaVb(Wfc?_ zaTMycghXuxU}kQ1)ULo&?1s$zqRhM~703QZM04_|XdPJqC0W`us?W^J(KAi6mQ{9- zK21q>W*(2ibj!?%mSp8*7I5S+6`6cftT!^F+06cesCE)Zo?iPMVI5gmRKP8{*;E+K zy56^ruXc^(VddJEEY78uGMH^9r&pE7w?ZQFalj`Ngr+ z{L;(}nC6WY%eCJTxdnw;dD+>eB@{&I14<}nNGqh~#8Rn_He}~%=4fek(O3~V1vyp* z$yNr*T1LfWErjHvB7FeuV>*fAY=-clS^3$8CDE*Cac*WbkJ&?qx2O&^OG&9FAiK4M~e;eE7>>k_Y@aVh4c9v)Fv7HsOD{L35 zXHT%*zA4JE-99PGu-(2X$*|pC7p2(l-voC0V@ zW)!5XG$p?%E2l8K1d3~HR+LQn5CAA6v@{p4sWA3mk`*lgU*;7L9hyPGWi)o zM!^M8A6h_DXtWZg+@gH2GQ<^voRghPt4YYo%*_FNLqf9)v+@f{qST(llafo%g^(<( zH!lmaZ2!fj&^1-&%!8h?RSK(J}QTLW);vbI+8A;vl(WR_?7XZN`5HN zF61&MC$BgwKQE8=!LLDvbLsaY=0skhT}$$HvT8TxX6p2Y?a6{9=jL)(l|A~cJPx~aIHOz`EqKo2%6LO744%VKuL^EpX|jq6 zVQ-abffp%(t%Cc_g<&eNOJNkb3oK4iR*^D={0zUsRk<7Eo|MJShqZ!l$6JW)aF@%w!COgL%LuDB==^FblQE3%7C_k1JErEfg;}ABns$lXc zXG~TB-JGMGXAayL%p8IYs-_9Z$++^v|28f$pRp@0LQD3wS?J|oe4kA4udmnvC3;1cQ|~N2-A_# zyuIKK^Y;K5<`?M(g=Xx6JJdY;fIHM;c8LtFo;^Z_`=qECGTawM#gO4XDJg~w_qM42 zab)-(-)rwjr~A?Ae;J(?>>iz(q-;0n)bi{-I^AobT)BpC-xOu&be|NpUw*k?ez{+M z`F~4(S;6$-uL^Ls4oGivatljTB&yP7be389B`WA=%aRSR49A~Kn(jwnn%N|Is|e;Rw#zP9XF}2#rcpHRviGXEy?mU4Tv!#?pqMY!jTti z>8j&qM+EDRw4a;(&7xOaC zqOMRI)BF+prl|c&l>e|m>pxC)_KU>!i^TpTBC%)=cJU}tib}8x!)&NnRUe!SiYEeb ziTz`TWR~@KlVM7f#}Um_-dsIS)n;BT=+(X+^@#cxs4GOSo(s+Ts0eE}Y`DrlQ%ky=~{>SY}cZ0Y0TZ8Vm2K~3KL3fF` za|)Gb##QA1GS|H)Zle38{QJN?VZS55j$Tp!ae2#r)W09~???SRi%OQW2M)2hMNxt* zs7z_+K46w-?|F7BMr%SAg=MYU-)EWyS93-i;BtH_eD`Lr-gk|QY`4o z-WIi6o}G{wg!(APGgH0z)kK@9Ap|xlvan(Z1vMIoo}wBrY{!TjM71DN7y?3Mh*7*X z)rcDZ&unCrL<7h}##n$Lkt>2mjYpMLgpCGHkJw_XCn(_^G?)t3)fh=*?oAjJd~J!e z0*r4i=F~Bun2hR^ipUaI-9jQ=6%;Uc@~AJDdihE;v}g_?REYjkkW+};D(2mG4~~=s zkkN|yXPRNQO>C87qQgwd(Rde8LVOSchQjeY#SXlX`N)+3AUuFZGsDarH&4C(Klbi! z$&Dks7VxV~$hS=kC{z^yhwTX4aeT)Y;BDJ6bVMJ|gg9;;zy0~vPEev|Bvgr&q?%L( zn@BXeur+|=gs`5Gq$uRa;nvZ@rmAdgY7>&TA7hRpWkit5zUyqtPc+jKyt?CLI@WP?@Q zC3QrbMKxsVaa0YNx=3osv{lr4Wb&lHN2aUVaZ_6?Lj`t_DP%>K0P|N-!-uRRMGcs_ z5Mo0W^g$-oC8&^2%11KW5gKOPk!eS!@U146^#POXaYdo$h?{arXR2+sBU6dF2PbVm zwpe6U>LaRw|4m69U@G3YvMk5{959`MAhqBe!;M?LG$ z!BfnHgLpH3V=C3@5(}zE%9FH^kVWHe3_B#s%Xz}{!)|zB+95@{JPeP> zl|p8HkfBn%i+M9!J5#Oei;Sj`;St-yXlE=+`=_@Rq_XLdKgXsUu0?}%$EK70&zz$e zA`m)J@{ZV)rU3NB`azaV?j;6Kl>@VzFoH5_m{S9~qAPpm?0k$2pgcFQ7q(-R%n2OW zb9Bd4BF6-J4^2h{%`9M~(qTl3NjzbLjINpSfcrwRvhQjS zbJ&)0)~;l3xN~5khfoyX$AZ+E3S*EhDAL@ zH7x2PsbSGpQOj7AhrF<;{39U%L&ADBHOK4erYd=WGu8P*eh!Q3LFdarf@b2SPM;^q zbbS>s$OtnozHK!3${iIL;hQNqLDWtpUk7qF`bFF&aACeYj^L<#D5?3!;l^1MHLDoo z&D1cmIXp8g?6Z_EGG;^YE)Ze{aerJMDyI(Y@f{U!0Zug||D~@MBXDpa1Z><-Mx?x% zk1o3DY!ae9aL!y(2;>4o;Y`D9i}E1OoKW3*JqPogQfLfZDHua2W_uz@oV$7UQOVm9KuYop-5fOIN3t;Rz-130$tg!cwN4-v z4&pe-1+KR!a`7ZJt~dM(78<sGalk4^p_K0b3FDO>-{~~Tl`x#b+KK` z+5b2dbNMAF`U3=OjKHVIco6GMgM0EBYiS4v!_P1R`?I66w1gHfbPvO&oOrGB0Q(%V z#N^RDS=q9v8IkbiPK-q<;m*Wq5SqX|uZKtJl37O~v!~H1ULTPKlAcG)1B&Mk@V{~w zvKAdV@$zV7JXP<5c-TV5JmLJCZDoY-=@xKJZv)iFSy3E#Ev(1!or&Wa$gg~KXRLDW zzU2-%aVY-6FP%dVt6UB}oOu-HFk*+a(5WLKc1^?QCl9H{(~K~q4me)eN|kfAu{k^k zR-F+3S^T!J&mC9PmgzUK9D2w$9hQcOxw|yfer%Cvs~)gl>WETDy;)RS8hRX6TN=7Z zYD>dbQOiri9QQIax>T*CSRCU`KQIN?n$hp|RHTbHGuli%fsF~|$Be#Oeaec)rRb(o zI^mhEjkC1`2HFrLdDtP4Rb#%I*-@lSZL=x3U@mw*%_0X!bEDv8V1)ZRSsY{Kku@lgyg=h4+*)*?*el$Iuz?gf9{+d99=c!o17Ji!-S~Wl^*NBha8QGbprLS zIxv&kEfJg!Jf5rvKA3eFu~s9xOw*bAB3P^R@(}BTch_lX>qGFdNa8JDl-?qVw+WI^ zVGpsMgdMB}E>?)$3A;WW>Es~+b)lh=tB79*-iCPfjG}ZzbZ_*B7qu|NhwSt$2%aVf zOpCtGPjr$&l;mhFFU-YUWML24{OQp}%BR4&o*viSwN2xIC^Igv;dG7OKf1KE6lX1r zWa%}Q-tX!1u?s<->k|@sy2UwpNl$qmIgWHakpHh|PSpF0eNP^b3!c`*xQKTIbPTsD z#=y}-U&KnHaTzD;vZdi1P0N$Q?_zmis<`_eAVl@Yivx~P5(?Pd5~n9T=q@@)zZDBC zgUu6T{lJ*J#iSV4l!(m~vcir#A?s|@Vcm$ByI^1YS+#C-5!Kd>9-`X1(M3{QH@1pe zUNIgt|Icr(#`zkX6i@|7DL^ z|JdViSW&*DRSjb=fN=+!vP}nQikQ35RQp*4OgMg}A?fDr*eGflnobtU zKvS7tx)a6jOk+J6kUk7FaVLN#ubhkwU)mUj>qls+#ht?-sT%PvR6C=f8Cx?v@KidZ z<(2_U_Y)0@`}C|TFiUkz;jhQ<8dQ(pRXE68ig#zEI8H9&g_>gIcMa|O=kU8ywqBgy zby!i0bK-ShM51id0f{2!E)vy#Rv}RrQ4NWDh-ygGMN&het)iBZC@MHt-pz%@OT@%G z$2H0W5+zA`9_)$d^q!Iguj2TNlEl!7Co5C1kVwp;ArUtwL%1^6aGn}Z)yZu4x(1nc zud8S01$kZh@2d-(r})g<^mTe&hZVIxyVrHAgY$JlTj@jH#TCp)rzPBGQOgU%?seV0 zuDjQD_qzT}((ACMP)ITCvO$r^bNnAs9uufcwDldQdA;#kH3J{i-2UCa9{%P0@8@s+ z@E`y5O>kAL9T;X;_YI2dXPrUOL)6Wn=pgE5Q1p;=GblEST3$DX1T0iQf9iC6(XQAN zA#;@vI}2sZ)9EYrZ153MMn!UXT`8qPGsfR}M%l2YE=UY>8HjAt1Bi&Z4@B9|Iw0yH z>IOs|MBRX>hol=2Z4|Wvh*ai%07P6GiBJd@PeR#S>VhQxNIaU;+B}i+^nc;+5HLRq zk)$ELe(UI$B^`+aolHM6hzpj!;+C*-CZ)W!MY`*i>S6_^bpmSj4qPelCf3P@{%zL*{8_;lk2Y1 zv*@mhPLqt4(S%E$*Pdm@4ZLTW{W?eZr_3^wUmT(WBn8MGYWzKBnXM_JQ^&JtW@MWV zYevM}T{CJwtIUipqS~6#LsVNcx=3nk##T|wYsPzj$EPMn+5H{6zhhWaL6>OzQchV# zb<{XyQug6jt-LE`#ZLYS_Y!Sl_AIR`l*3v_jkzs-HYkI z#A3P?{*ELjeO3OBy|Rw;^_PqE+LG}*&GC5e@A%Y9Mz{-hf5%=`7wWf)51C>0BxgxDyCgfLN{IW^9Wh(Tp5l2ml6 zi83j^3#-6f<#bZt1y4z-H*4sY#TG$*Oc)ZMWIpKy87z1F+3>pRZOm+_u{Ii zz7e-;6*~^ov!g4@+d<(lHq5c;wk0lux;_DJaHC;RI7%iCcG`p4)EZ zaHSg3$@)|7z0nOQ=BB~*KtQCHIK@e>lSd&0oydvYxez(nK85SKa8=Oml0A;9p=1|H4JEgVT13eSYs*oMtl}C^qKZCs`(wCx@_2?c zLTPe%hWu_ufEJ&hGAT@E&nrmCIH}18QRYJ?7{(pdekstw9bh&E1j8s4f*2z*nrxg( z|FBQMkc%A}UmBn)cg%U3e;9UZJb@~+Qfc)u@g{4*Ngl$fxY!VtfmC2Bk4F7t)(2b< z$)|B)+klFr7zplT*7k3w*}moQr6h;bo14o<@ks58py z30)4%NLEic>@LmQQw@|9YWfFN?LTx0$~d#OWleH(uh12LMN)q_5&S=%z%7~{FdHBX zIg_GKHwjpU$I6j_wn@4Wf!(0jDdn-N#E#Q*QQAosMD1WFcKCb=O~~iR6uM6s=!}SM>Y>3H1Xz5OHy6ZZQ9Nl~mWdJl z&jhZFXeA_J$#AD=pTf7F?l@Q4bjX3j&=vhNsA$CIAM6*XN6v79j|$6uoqmVgI49kv{%!-8$GJIhHu@Djm zj;Z_s*x<`KEPNP}tab?WZg1YaM%(0q(eM)o4=7UDpgr6LPANgQuua%!CUi+xmWJ)m zd4t6xN?lczLgtJpG=pO(I@2~`c8RVyag1AlW<^EZ;M5m^CfjrXnuxgzG_@aF;^Ex#W)pER!db6koG(C>00ZkW44QRHCS`RdzIy-C!n%@D?tSF%Zd6tsQ z+31+DZK35m?_wv{&s(abZ8`u=#N0)P+RrMW=_0BDO%G8GXu3#hK(kfUGSH0iO?6V8akuvILu7Q(E$t2G~}HSwCo-N-7Zz(rH??&a$>D+;B!6qn&9+jM}N zh`9?lwVzdR(?!%xujz19H@&8Zq?=x|QPeWr9J$Qt{hy@`KzXU7t0V76qRI%V>L@l2 z?G+_59~U;%M+n69h=Z0Rj2*$He86`d2U)t84g5G6C;ZCvTW;08C4PP=0ymXXjF1gTA+9hs%bgR5HK4p0M1^lJIfz4t${e(6; z$eBXSII6?qjCwg%9n1vayjA6Ls-A1%B}JegKIzawNYaXn=^@sYuR0LJplKLKR(1$s zF1*?o-!iK5Cw z0V{<*2z8wobMCmwWLi;B16r1SGufsKv@G~$YCkKXrGu#V(6U|BduZt(={>Y;6SWL2 z9PQC$J_7}3(J6;|Gn1ewIIYf^+UDo3#Xy`7oimp}5cf;dVh#xbei2&CiaHDd-9_Gs z+NJ~4WLI~!m~61l4ctXkgPI)SZqI0+iVAx5_1n&+J4sPFnvT7uyhesz|u!j z0n27l%fNCFEdCrk5@OAMUEgu#1KWsQBs~D0h<2p$!92ZeTv?HP&jMYx zjk3*lT&Z2%!8TrW*k9S%SP;zy~mRdy3_KE&Bl|-L(B6&jT6vh5cYN6gv z$J0}_eUi7GBzB2MdC_l^-<+pfeZcL<7p3x~84nM3+|U|6CKEJt@C3`+Pnu@-uf3)O zAWaI>y(+0dB+2%cEyTCYWzUsu$7!WuVE^-N%l>>NKVt~Bjx=^72TbMPt0YJwynSkW z$Ss(kG#XC!zSsAsYig;I1iJv*EoC?xDM7_Llh=>v;ag(v`fqbA3r^)5)6Le@-NOH-YWEP; zRP8R3nyS53)Oyg~QLtU==+q#hf`KY#)uN* z80Nja!w+ja9~|_j)$Gq39Dip-ril8GMI4n{J%krEY!*{Gqb4gCxnVfw#*oeZEa!H( zT6IH~?5mcIs3hjfJN7cX$EEh3Ip};baAwf|B3_A_;{B2>)3Ul)rQvY@+L%& za&phuZE-A04%W)~;?VMj{7~(x6vNQ!B(WO~QjgJN98CqEAV$wH4g*G3>CUdkCnvzJ z-8j6Ejku1nKmM{`Iwtwwe-$$&PvdU-O!CT$d~66f$k=tfo0eUJ~i6a zUczVO&IH?X^IU-of+7nJ=*@@LBy9%#no4K9|JD&pf^o3=yQnTHRd%%Cq`q z(=@fk~6xK(<*3o+adeL~~Gz7%7CJCJx+%dyxc_SwMiNvVPM#&eFc^yV~jIa6+{f%a*5^ZJ@=e4&yDyRAoQMw5y)!-?|i z_}r>!%99<8)-0oL1CCsgTomDy=J_9`-W7z1_~#}pbr--ljhnD-O-islE0?e> z+jPLTh`EbxwVzek)33(l(e?+nPNgItQ7SXR5X(5hHOEzkVYV!HOWb`q!B(@}_X0(MI4Qi1@*%~Ki z;jX;BH03QyXlZ;@O>~*(6MOU}D{m{xm!y0w5(?Bd+X1e`+yl6_pEUs2M^ph^7f}Up zeIymYZ5Fi%aF;OghU7aAk~2q4?4D~};-Iy`8wX8nLCE%V@D_8Etp)zl*(asSk;pZb z?nWc;*2TAttRcQF+m^$N4P(@{jz|sOSf3o*TvsE?=60`82-SXO0(IgR+C^z+P^j!LY)fs8c0#0=spI4U-9%r}Q$<4~R zxJk9Ia({h4t^muNKpY+^-12pOsYoFRn#KV z9izDg>P$VM0ZjR318Ry(a?|3C3pcUxWh-S6dn7h$fp*$#6h=B`4QV_B7?*GE)S=(5wTN7WR%E|Qu;w^h_4%w4V6P)-C8%8l|T zs8Z+XTnN}0mO(knMO3nTC`X+DRE2WkGb?9%oZGZK>$nlhB`it3q9T!-@fK0s)w!3Y z&Lv<@sgF8$PEh;{Qs>rGkeof(3!XW;Xae}rv&x*v>qjIbmzcYVQv1nnmh#&Ah-x^O zoo+pA*sU#Hdv|7^$>Ma=Q@bGsdGIf-PE~_qE^G)Coj3!VGgK&3C_7M z7v|PfDI^nXL7Nkj+wX^+rw>7El^#?3!8&e4vVQ$Zl+wh8*%u$6cRPYp%tm@Gk==qF)i z3D4391V~bdl@xc)a0O)YI$z(35Y-#6TY@BOsw!<; zwIE3kQ4NQ?NNPcnt)kZB@Se-J=P4&L!VU7<ywzbP8|&GHU^2VlISz@@VB7Qnc+*{&3CPW<~(Defbx z`CyYIde<|Y4Hi7Z%?H~>QuD!X6}1S)dyeFuBl!|@B=4f~MP}@9Jb%%iig`_CP7((f zK)I49w}Wz@9L(ma*qZKG_})AfJw!E6MHfj;L*6QC5tR3I&g8-Gh1DMxR{!SdoOcmf z)!3KsJf7Fo5+%uT0h0IB({+0C)_l<)gLs=$YZoDTPd(i$iGEs1^b%4}?_%;-p(U>< zda8WWB}lI9)oirMkK8AGeFl?Q&4fkGxsbA|&rwvU_dkPis40 zK>FC%kH~B4vjRvvB1@uCAgpjwy8iU;RqB-5&s&w(soKbL^vl&0&6(T<+nY0atEe53 z_iFoJS#7@~@~6*vn^#nlRbKG|BJa7!s}Q*^)4f1pyN(Ok-aN@$)0h_#dCxuGbC17- z+~Y$SXhI%e6sFr-^5}o@W2k#Z zF*}666}$Zqnrx&&MIR*R8OK7TK9DMNI%&;z+J4@=R$R$BuDj}^{iXO^=_V?f(91qJ z%ZDv=^7D%Nx=I~h0{^7nb_gSG&Eowrw_{Iuu3PfU>&SZW-xHqqgy$EW@VtZnKYsh} z`H%nnk6!-p|NigOf4}>uZ{GgpFMs}rZ@>Ni`|tn$`_te5>AOFEs}kgp&A$1=fBnZl zee=hs|NZmZc}>;fo@L!3_q*kgY)y^+F<`l8Sz|fesrl)iiAa4uYW^3RWxcNeAG-pq zsCV2`ySHXh{}> z=QS0V$y{D?1ZA5Jj-ahc(jPd2x`^8I$#;6-y;0YXjk;cVKKX7De56HiUQ_J3C$aDR z$vc1Y-VQ@h^0((t-tB=;Vh^mSFRd)Z1$&@nDrTcSb3VzMGC7mc*?!*q=o#9YT=`>c zV9%W2-9n$cE7D8P)7;%cA8QV*s%gdaytE7yFZT9jVCUaGwU%uPp8K@y*kqhbx#ud>`6i|loxkCBz|)|K4K+TS(yg4 zZSeM;_xc>o@BhE^MxUH~##;CHwDBEuh;6^h$v~^+Hk3IQjT^(5T)UHHv9=`|7L> ztO~6HMbe)1z9+p~zw%?bJ7ob> zQqSpgsYYSv%fm&ry+0fk%V#_tj&SvOb=gK$^BRYR?ra=}$24z0JY1}wx{Mw5#kDe$ z=>u!=cvhkRQ>I2s>2OZ>T#d$bkpE4Zgx^haIbtw)H4IZ9*T!X#WZp^G2G7Qt+SENC zU9$aME}6>4|78wet zCs^WsaQ_e5V-R6_2#&wK9k;bBJoe7p`1XS(h*9Uf1bcL+-5 zWl$hdc^u=b^SS+CicT17Mns(i4cVr6bB2Kuz2`oUbCSG8X9U*@#>*G zrR|J#nWRjk*Agrp54IB%J$b}W4`&HQOt}Xv=3=tvhw=Ov;|>p(cq@zUDtJ00Jinga zY=Gevm56()^VY259|MA2B<-ordkG4+&R&A@2b|llk6!}}uc-vwGn@C!<~_6d)n0b; zf-{@H1}t7t{kJDFcS%3q6Pe4iF-X82S>oexesxg`Ym6HsevHXS$8o6fG{@bs2l%)r zRH>&BokJ+p5Uvk9y0Vz}MCQl;`R=>_{O`Z~+n=8P^xZd2K_22?IG(>~KgF8Tzddnz zPh5WBBIZxyE#@PhhezEBj~FkGulVS^7KG+Ec%k?&Kk*O8Kga3m;|IM4htvul`1YE(syyqoLso+&mw|lGblG|P>vLiC0j`N6uBWuu{yt0{J4D;)7Ilh{>yNs1ZcApXBD?sGy zirPI)CF2tHer?mCBV%@TuX3X8=Y9@pS@h)&box^&UAPXY~m}fkdtK3AA?VCU)kgtfn3$%VTqHp ztVj>l4Xye-zCAzE86Obo4A<+!cv8!k!H2nV$x%j!GtR0Yvbr@n>^zx|UQOy4; z(pAp|y*%FQXyw>@5Z(=!;bE5Mo8(bsb@5A6Nhzub>|R}Yzm1&Pr29ArH=Sz?#k0gx zRVWHDVya9KsCX+u8lbw%OY;QlVcQ?}^f0D>97u`%TA;BPYf>&X`{A+Yd z+Iwa(0C+&B2@ybCW?IGL43#55$M|^4gpcwRHqi&jG?!H`{eDoGZ8#mz&#vfOxf=_h zbQzxArY{bY)|6_^hh>#1+jPLBh`EbNwVzd()J0Uoq#mLgCUue2Flno(MNB$QVf?$E zrpGL;W~Rv#&cBS8%jwzj>SkSEg)r~}4J^)sf}??6f;iWFQvG7#Obtvq9utE9pq2}8 zP#Dfumb3~`H8U%EQ8*Ju!YE4@pU#KqTcsUY;O+L%e%{r(4Vtcq2{Y%e_KV4vmQ#$r z(RL^w$+Ef}&(xu7jp;!E369n1f;$fdFtO4EN&q*6G5Vu8rKUL^!F=m$w8z-E8}Tms3pBDx5vRlGBGF0hg68bmH?=Uwki3zr#mx5S zym49{K1);>p^M+rhQO+ymFPpEcmxM^u4p7f}VSeIymQZWgr&u2<8^+@+l5)?;F&Dov@+yq=#u z=bl9-&<94(yAQ0=XLBt&*_4OXbLv@V`(59H3-hv78v1hVN(8O%O#FJ|l@@t@9%)vY z9xwxHdddgrWZxOVL#77NAdi)o@iGN~rx>;-A+pnl$v%w|u-Y^VSfq%Ny>^-(O(u#{ zR7bPa>))uYq%kLAQU-W(Do__mO$FL2YH^lwOj!1>7PV7* z)UUCntQbaqxlF|2Njm}y3QH)-h*?0g;$5jam#czy^Wav{o)zwIqOWBj#Ykfb`F18I z?*lKO@yt^gTGPLEWKmz(l>#4(I|@=v7 zVO|o*jDLzdFw0e5+g0@2hmKIBKT!hN32D$0wUEll*T@9mLsiFAq1r^9MQ?b%*aw#c zC~`)uWCU38`6c_qLg*XrX=2Mx-P*@WaYy(WMYrPube#pgT~HS@;hJahO|Dm4F>|vBj;ySSaQN7m3pbs_l@+;JXM!ORgbI|XB_u0)i>k7i1Az8rMzx=63#9rALDcW zkos5W$D|PvN((RJo7WdsjT4T%a-k0SX1sY}1rwoiGx!r|#V))%5O)Q)uWRgdqGNLd zXHW;3Bj)&EKzUMRv^rwr7Vp4{QW)208C;Sp}|LL^W{jA*z9E7fB6V zw~AT;uAF!Ut|;t0mjO$zuMM;-|f_4G6lg{@fu++8lv zjKj6o6JW>I&jSO`6UvyMvPz$xL`{yRF{m=xBV| zD7&J%WjG|6D%fWs{e?(LZPNi|v#Yx(n++%_X4Fz@OczlNWqXKfDBDF+L)opOmQnTq z>aMedEXqw*e-k3HNMot6^W}YXc?ZB!(m#iKIRckKX5S^o#F=`jG^VNj;#6atGRd$p zP83=InBKc^C;*t;zy^T1vBL8~&I;ZpYD;N58E*hcjXNf-sQ55xeaGoZ@SeK*L^FJ( z`$yFViAhwTaZ9z7ty2IPj8Fv?HFL7l7q4cnC?=7M6s7kr0M<6!0kFi}1HiVQH2~O0 zQ~_WYQ3Zf~BozQ|7PSa~Gvk3&QHh3n82~e zxnbo>n8B2sEXe$)<~NV3HlU|6p&d`$vSHF-l-k#OeE!hrWk9n1{XHpwrH;x(IRk*~ zFWO78_2|#Eon-M00xSu!#nukPZnBSAz1foWUL&JaKn~oDu|`EuPm{4V zYmq~aTLPu9-zsHiCPT`QW3Hc>Sx`5Iv!$-vrD=FFw&hP+0%Idr*xzYMV_{H8LgJ~3 zX^{LDccCud<(MSugwK7<-tg%K6>+R<&Xjm0Bn~jc)83qWzl`Nr5E23sy)=%=adNcD z#LCl?1o3#yMQA9p9)M(e#ib&jsHKZT?f4n^j${0D;&6D_tt)J=lhe-4<5)PkaT&SY zYs0gZ-E*29I7BB?j}w1I_G2%ab>^NAT&b25{&Ohb2^ z$EIS5+#4JG6>iu!|NM_1l=}RgMj!w7f2KwkRZgSR+hLZ@y0DVeHrrQ{5_4}QY5Q5T zlJpVPROwuRtw+^V=`NC*D!ofqfnL?|1+7&D+2H z<WVY$B z4n)jd#I60TS_is_YU@A`QEeUQBB`wdTSYCd0~0kW76tvB{=q~}?tVtr1-G@-B<{;- zT}eacT9jKpo}Xqql6X;hH1Amy>hDAnmIEi#&u)i||6#aIsXC{BR5;xp23DQWSrGhldUGoCMp=P;en zW7#K?RHGC-%Hc{~PyQXh`tcME^`3T*Zs&<+$D>XKcR>{l(POEB0+6xH=9CmhFYcz$ zM^&ZwyI;ver1e(WLk`t%=4b+6&X-fzep9;`b=H^?2M6dTivqjPthnf#3amaxoloIr z+$+(4Q`cY|i&`eSG`)IArm!HRQ6-rtjA=#bb%_K-6BiT|PK?&zf}L1YrOuzLI3eo3 z0N#|OUotYf&9O!#{i+sl_%X)(pHFXIdysExd=ft{ zvVC$f673|_W0k@YGP0*{1#HhO&qej!Hm*dT1eT0>9Q*cN`OUrYQ%1&zhQhxd{^k7d=N}9OL1ION z+0|Xx&Iao|;ax=C)b|cYbyMGaNV=)-8%2E~u>HwBK0EOLjVEUZ{;wbS*A$DT)NKLy z-ZK>LU);O`=;fWMEV0{+dS7J+}JqRPfPm2;HKmyWjpyHHa5Sp_B8ao}n|C8&GL6;@&djj8sY0J9w(w%Kv-^-*JoAjsuM$#O#Ud%622xiPY3<5u zbkn=G^RB$^zO#+Fm|uwUDsMQ6W@5y=ZE?s^Alu;WJMSxtARpK7VYjN!k`FzLr(corv!aM< z^H}zfbPJen6t!$e^D)Wr((j>ezH)8(PvUCEOC|T=?EMVX#TpeHc9n9gN~x;siMzcx z5cmqY1kWkXN$pp?IaiqW#xTy&JvARfVh_zMJB4R0G3u3(lqEWPXErZ1Co<#DINhFvkpw6%52Cb){ zCpG8>{pz@)fJE}MWa&)&JNi|&>48?n+=rO#XB}Gg5OqVV4x(;o)kD$^tu~6lG*R1hfU4~3E>vZMbx_qs)Xfy^a8x%_u!p3ZDY#M8 zGE^z8ztZNlrLjzDjHfh6rloP3RqKaBkt0{mrg|d=1p^}_7OKMxl5E)w<@;qrq=t;; zki^dVx!pl}8=InHGGK~$21Ic1DaEnU}4G( zX(i=51f!f<8Mox#9#^IDtBhOHn&y-hW}{8@TTXc?=$HMh(we%6xQ0bVa5=njXWL6SYxM$KAMVi#F=Z;i5DJx13dxegwVp9b=0zV8W zY3;Hn`L0azwJh*LB}<=Is38;Z2r`|q4TF-<=n5o`sZR|ujj2)n5t%~D8Dv5z)S#(o z9*Z1Ji8J8^P1A%c7voZQXj)Yk5ZdJEE_V#Nw4&?)O%ZcfORD{>f~GE_8Z`9~)u5@1 zqy|k}MXiUXbbo4El7z?~w4@8FB+YbF8=s~LRkt1fXp~h_KYx9zKV{k0;H?c5GW>nrAUGqiT6GvR5*ix35g`kB#RLM?>>*-DbqC0VS&qZ#$p2Y3{ofWjkb zcNs%iY&i(?14_9m{i~@;m-+atd28fh@d^)kCsk=h$pO=L(Q2!0w&PKWxraw>KWp%) zkEp_@ljkiD%lfM?tMiY%$v-w$L%-0?;NNyuLkC-| zhJn3EO+(Z)64id;DYSk$taM-*)51WuJNw^6v{{&X(jGNzB}~(r(iFlo4GuC(w1>LAmWhTs?uim+WV|0T^o94Y|Hp-&|1q=2;q9c2=IYZdSnR##51 zNX+5OE5{S&f9~_ty@!G@IsdV-tr6)YuvfTlV@z}{!^*3FSY6#oo7A-UHF_MZ6Iaq=y6nSx#%LPEf-rwEiM<3lH)Gz+(8Mw zR7((6a@n??Tqxdtf_9?+JMc#Rz6ZS3m$2BDEPB?@Yv7{jZ#7$m#y+|BT5f5icNhDB z)sFa7t}Pt7Unb(ODC=OhEccDfHXRT@V(!9p?Z+02`7(9Xn?*Im?{QQO@w-TBh`&|T zBH~Y)tVrLl{#-nxYBXsW8P5k4hOP|nsZ!H`R@$;0sGP&2ep56QwW;*s_(Nkw6cODi z>HNY9QB%ePszaM$oeO2RZUq9Q6jm-hIAvTSE)0{PN8obC8dr?c`cgf;Vwp!|X;sQs z2gRzqul|S4o9%+pJ9=(t^BfX|S5H|gJU?*aNUB|Ps^KCrs;5mbD}A&=aF@eutc=Q3 zA87v^crw^L^0axdp-E9V554}3HZQWGCYK^uyQP#TR+St%kRkR(lec~v-+5z~+H7J6 z=Sj$^G)M{;%1OX0-p}gWtsK{Vpf55JoS~B2=!&rd!egFf5NDVw-_+qoTa;&nJ8gGF zyQk~860hMX|I+mL73C?zIW^Y-#$R?n*ESu{JiEFJ!P#J){@z7YL-QV@8k%>J)X;pZ zs27dqpPbKdUk~>6fV-<&VSJ+c_AhchSW&;j8@iZZTHAD352_?2TGcOb`?US6((b#6 zYU@D{QEffwBB`whTSYCd2k8?=yBBMWDxkSg>TO4AGasVKqBl+26-gtywY=rc429ps_ZpeER89nWIump!aA>Fhc4Ow-jxk5#n=A>$p=9 z*`T);!mGrw%Tcx%$NePu<^Zi5bZ824y}4HJpMiTE?{wPI0FgOBNx9Jtypm&(b1 z*vJX955=8BDP%fTmlAJIOn|h(43Ca60UJg`h`|{wXNA-0({sKI_|_jTasB&a&WvBm z;R!Y9U==eV(GXPcxwz~i(HO_iwxE~|b&uE`c4j9=f3cIWoX0^m$mxpb+4$zQ=P7rJ zti}`0tPxYOsZY7KT1F3T`n3F_aNXA8vNFuX=rsbwl zy!i3Zr~#eZBr_UkK*mQrwo#LUvq=eoXbl>Lf5WKw}?K1&v)q6*TsdRM5Ct)FL!y*5t+~9WE?}Q5?pkZC-~*N*iZs5kmN&+D_6!j3Gcw-q+{^)4PPS8OSduZ73a` zjh2ilho~O$(8Z2;z8#Edoh_)_@E|H56}l88dO1BOo#knZwoWPy9XQ%z_L-D{`f*~F z0xPd9dvHpQ?ij6eplm0FB%`wdRymP$vdM9#W6(4no+ZWNVgzr1k6A#rzb6?%eE`jx zE=NGQ*5kSxbo#OCSgQ2Q$so=i6s$c*O!Q@+p000RyWLL7#i^AlrR7lr4SeR+AxPpw zkyyGT#z)sb$8RMp_d9rvUZ3D{^6fmM4us-7Oj=p2T(gWxOuA!@`S>VR4(gb(_RU`a7c-Fpt_CLuUd-9w z8FVp0t%MK;a;V!OE|GYHI7$%HbQ zf?=GSX^wYc2`0^7z5x+tjOsw5Di0DBWGJWqqTTU%)=8C#AKK|UByGU5uY)8Tpa}NpIe%2siA5n#b zT|^ZU_K{RbxLMTi5(#O+=6xBb#S`$3nc5fwl9IgR*cXdqtLoJ_3>I+AN*mx0z*vnx zK9UkK_i(K3XAO?kmYYR2bGgS+HFLR(q-HK}6}60GS@l)DBq*5$pFOG4EWux@oJc0k z&SN1UN=r(q&6$QaCO~@-f96b#)ofv=r^V$+3FJvi2$8o(H5lbE+5@F6&i$mOR`iYP z5p}Mry3SFPQht8$t*P|B3Nhb>qMIkMG^qIe=o%Fc)xDXH$9acS!~U~0JCk_Bq5^qK z`C`SF5)wC@^5lmLHFZv^Di@xon?ch`!KhLx=3-&`OAI+}vYRt8+7q)*#3C{7#DwE! z&?}r`sm)t-C;D!wOeunkKXph1`-N#nud(a8ESG7{eU9tWf!4oGWRb&)a;MYDyG9mgJ7YIFtj>ZMu z)UK#B0vvgr#X$LYIJ)?%+K=c6S<&0F&C!GIA$NFu)wCE2l~Jj?W1-VH4t{aDWEGj^ z^`mSd{-7r%O;3-xlv!dcu$NPDnIo1<98|7jTww|H=3MDTvve`(IF2;wh(qEu2W}zB zV`n}oo<@hF9@{~uv_4fylsB%gq}EYL1F1=_)Wf7kju^*zW3Gp!n=!Xh z)G}N(V=g(Rj5#xCVuWPGco8fKwMe;zlR|uXO43}Mv!=5wQC?KPUp*1CFsQT*R-sf9 zGbqWWaip729+?E!j_7pQT|DoGvyy6m;tvjNUASi%iWyb=+C^HYtS}80KSp~pqc9&a{Jx=KWnu`B}WSJ>(25-J9h+0t~v1?RODes|O z(-DnSvCc;sm-;|ybsAs zeUgAOIlgGcy$G{gb3;l*NHUeIr1Wn`Z81*?d)D*>MXkLQV+(sS2@i?2`Zd1``La{Q zU%4=|N+su|BC~Z;)zbP>OJJD$oL9LtV+2?YtyQj$*DWO+r!^%UyRN!XElh&TuB-04 z>hD`uy$}Ap1*{fWzk~m01OF98DsIc7U$wUB;Hb#1?&;fYKlk$6ERjM zLQP7Nnxmqbr6$JzjQq9#I=YF21iqNd3tdLeaYLq@C=7+Rb2-~vQ$~` zHmP%~$}V`nqv_s>l&IQGq&-t@lj|{J?oPwnPj*9(&Vxl|{`t({I-<>@+KldTRBc9g zk<@1NR#A&H`kKu8<71{q9z9bhmFbzkhl-SFCBx}uCa1bVzN*n=RtA;nkfaUIu4!t{ zNZF7*62mEzI1c_A7bi0|Fq2tkX@U$R>rLI5rz{0ckcEL4Zidtf8PQMy6UtF3*XO1V4o2SSv`DL_QoWlE}{F^SycMX^;b)lSBf!8P~;89(hz(l-5 zO_!*0UzL`^E>QxgLlD&8d=8s^?p-`e3HpR{IHFWm*wCw*2XC#EDW;$kDJTf=(YokE zig|e%DKH^o2U^L6OOV8t6~KlBL?%jI1r`F?Au*xj1>0a2c>pr6q|yum@OIjM-n>TD z!2O28^3nc+ib~x=yJ9Ca9qQaB#9NWXU(5dz;*~P7D=ojQO6^L^uC&}&TJAy|Td=uk zzDkHYlp`MeeF}(Mk>4+yd(kedZMG|QCFY(n)%Nqtn#zw#T^~^`gDn?e>roZNbvY>M z5U1(wW>Jeu-Eaxfn0_+ly_hRg4KEZh|DJMu~Wuu#WRvG~T0d2gvO&zWm9iC9By zlPvTslFHvtOp2PoXfx6km}$H=p?2f2xwKf+<*mrsr8#*|mLN6$A&{BU>+( z3~C>-ilh*e&*hrnn3RlJei`GCVnXq`*fMYIxLiw@Vlct99ZM3AM^2f(L+eU7?I6~d z-5h1JRQV!h%4vl&D0zJC3bOT7|L2GPle7~G549>8bw1$vs*F0<>l`MKBm*k=jM;lp zvp9wyAb0DUn%H!C9VOq;mBLy;tGX(7IEyDn;~G=vn4(wtiB}e_kv4U$D)!uy*>{v^ zvdyV>2@cZc&Qa`=B$vEGM(a#j441djMT8$9)IVoe3TvAd^^DI9T znM=)k#wo-q-o>3J2QvOH)RcL%NxxfDZg9a^vY_9& z4=FAUDs6E}m6*FQQ~Swoep!=h7HuC<4g9jxtw+_suZyGxep^MY2S4-1b6wz90o7QqitQQXuhs%_+w4`EJH z<*5`jmGQ=K!KEWyC7jgMvGP;@sJn#7L5PYEopW7fW4U(_k`VwpL(z7ita&5YC2>ix zD~z`6xNC@b4)b|e|2n9DS%->LSG99=SP9o*yP&jF6(_|TXG|u-EcC!DW})Ak{e)y6ib9LvEFERY;SCHmRNScmCm>_+JVUobyH%mjEf8;Z#2vhGlowm z6<+M~3Aayue%o9&0`eOlK?FW}r<6nqY(}c3@F20iX7wDU$0mnVP=I8pE`1^-xF^L5 z4nC$V10JOf6Vv9l%yFj8 zfx14T3hKIuDyZutsi1DNs70s)7NQSo)K73?Hk z2kbDVw2ccfOn7T%2QEtI0Y-~~+GJ52R%)=js%goa1_m(=?L>wy^NHUk+ z_{c#AQ-m+$cr!RWc$b8U#?rw#$ka~i7H^_xAWpO-Nknhuw+mx9^3EDhMV3}PYbv#> zoqQH@hb@Ny>9>}0cLyjBfv>g7)SeOI+% zh(=cz%$Gmu8XMyL`9lOmbXoixWkvKiaO}S^|ic$hggOdy*{j#N7+ib_a5_1px+J4qx zUmsCT&C3PYdQ?r#>msSCd0Ry-Vjo&+oPw~glDowrQfa%KShx$rte!t6=Yjs9GCh-v5|>nr7|>BW;hKZ4nw?@yr^f^(ArU}zG$cj!bj&~| zY)2riMha5)o&qEarC)yo1#>W8o(Bn}Qi?v}{8UZ1@w%_NxpznwX1W0}BLZOFM$4G=5?sAlt;%Q90kv% zp+4ilsxhG$o4W&KC3NLRI9$LVXK|3+$x0?1Q=_wqjdEO(Pk)j%y@-I>rUL>-%w4Rh z{j5U3E}|L&_7K$&u#2RIfLlc^BjB}IRhctUX`-lroim`2#10BffsaDKC}lxF_G~QI z=spZj)9w=75aCqhZ_=EPyPprPZw~WDJ3EI`7s>9G;(6BHB05{rlgGrhDdJb~VuXah zuQ2bpqV@oT&T^PH+jKy`h`Eb?wVze!*G1G#|Lbs6H~p`Nq?`V?QPeW}jch0yQY^AK zaiX}WT&59lvqk^ox}&PFzyMjf`S^%TuOIclze>oDN+MapS4vwcwT?DG|4S@|6U-bX zH#|i=d2e;B*`0jpp!ktaKKddvUAYB~Du_o<;|dH3d7OL~OWW_r$v3X4(3o*uEf~5S z5nU=YBIX{@wf(FCy4rHHr~n$7QDNn%11Als#m{s2RsUXY;$>@LguZMp*|NHryKm5l(ee*gMW!F(| z?pD85Nvg&(eMIdpzTL&QyZF9p7vGvfj?mOEBA{)07`epUQ`i(1+Rqx@ueRJQ>V|+F zj_PLQ_KEoK)1UVd+mWlA3_Rf`1~2|}40a+$^MQpmxxUxgeuh7Cc_ z#1E4bGEeiK$dc;S4K^-CT7Qe!xL8xgfz-LiEy1fNW5wsOaR*+#-$f$JxT0o5UC?s> z)@-vK=W18?z^OJ^g>!vG-E3SZxAmxQHf|3|Hyd}Os70KUw!-=L8E`JeR4iZh9!I4} z;rJEIRGuksK};hraTV?c@7A0a7Ne^vKQF~Is4i2DAUQ?l7d8PofP%78P#CRk?$qY#j%bwsO@#SL@T;i=wzl>zE6vidWA??OelL%ANcG4Z>bOeIQ z!Fh=ZE+T44j!A+`<>S!1Bo!q^5&-ftiicHqMG%aliPY!&HC*ksad~U zMJ?hSuC-?UerlZCtzXW~&rs2^+WLh{zhmQfT2tO3&1(r06{q*`2$q<8=+pMI1{3>; zYPw%eZtGDs-LH$Jru%IbwTOv77{8wy6L;hHQ&e~C#_wPL{14xL`~COd|NZx;zyH&B zfBcpc?+_dLn?L-Qgp)r${qLXOs+0TXpa1d0l$6VL{@#1rtN190M?e9MKz_c$5AzSfMn|ouJ|mVvTF-LM9%ODw7;JAO_@!R6h(tKvd9+gwm5N!M=QiVnil5ufPo*0s zy;y%`4{`!lqM_VsffC_jriY4R4*jFh$q=tqg;0{8kxaHh(Ni@_u!ZqGGrYj3wu;4c zHw%PH9ZNsi)S?!zA5ZdhdJ>I!*}Z$E)iA7b(o)dsMH%fIL_11s~43`dL>jrw6jd9MP65OKZq0A+N~&Rg%sC>OK^H_ zyD>vk4C64=oaum>(KRY|LeT;D#RcRpLvvij3cP`e>|$&uiNf|N!s8~)YpU@c5;t)> z+#}5=+?li+%brCVa3yEl;%%E&6jThSkS=8I{&GQWZPNj8va7o&kqy?xV7rKFfYU=% z1Dr0B8sKadwG23MLZ4Ms@awtxbBIUOiD#4#k_paF!-DkWs+(6`ZhUEYbK`tTD`*pE zHje5_fk{f`r9FpBH0>pfDXlg81UwLj2nCysPEnvT>8)OWKpqU6ry?z%Roa=DitIu! z`Y^tEJ%w}q7lCL<tLvhs0KqlL^T-d zBB{a9R#A&EfVl8>NesMw02MK%r=US_xOeJ)sgd!<2%9Bg{W47@pEN9+^lA z=ZBD*giuK_cg7V8fb0lS59ekErd9c zJ6IDoQ4&up3K>*tFV?EoHXSf6ySj^M*YaGU;DZgJ?CSP5*ziCA=!Vp%RB?GaTbGC;mBjzrO)qZTTn2%ORy;)R4 zu^va&P^^ojhGJVqEuz@1+h0=J=>}$AETO0(XmWx^loREQ;q2i~GLMXlAQn9%Tu0XC z%ym;xq9{f+ZY4$=Y@^I%RPq4BzL0)`q0^*W;V%O40R2iSr7nS~A~JHCVNgqX9$wPcDBWc`L#v1({F{xD$;iHzW!FaR^1T;FTFdNEUt_Y!gT7(j3N0Em9U$u4oxtu;s-~ZxtmA`t6y* z%!%j)9KjhcRO{$vA&Nwy$z-~;(dLm7)FiRU~cr?t6Vx(m#!)KEBjvBa{jVz?<9 zGL607-17{u&;r3kJCRwMT4x|Ev4I5`5?>SFABv?3xUz+F&>^Pdb*3oI@HKAgk=n!0 zr}9DpON}#5V|!Hng}qHH7~f+ip2HX!H#ZZq!T@P*T*M!#qQGhwzhHO-$TvbchwZCb z0?Jy1YE&yH7b-Owqd6GXRz^NFzVML0xrn(kCz>pCHp4M2YfO330j8(p&lQJjIksFE z!m6aeWg5n(a2BWjk&b7*@O^(}A{VL4CIa4RMT)+F%5sn{+jIb#h`9?gwVzcW(?wJR znI57V$aIm^KxV6`MUX+t4>+_vio0Z{!-VS*ca2%cftB?6JfS`tV({76xQH^IWYgB9 zGTVf$%1A^w>zP(B$X^}y@r;)K5Q?9X5~8Ry6%&rryQ$uR0;UrfNMF#Zcd7=VqFI@U ztSj1pE;cMr6Mg2DV07v&1uB`FdA)&+-I`E0qFhQ0u+!;*c2eqv$Jss=lBWMd#5>rwH+NLLRW<~X2+(*{5l+D)DsZn_!) z5hbZKK^I;bEE5CEV$KOfhUIo7Vs@pBZ(h4UE)!JQbU%lq85>5z?E9TD;j^eqItRV+T7r#f_Wdt*?iy$_mp$|#HAfD z@bPJy*&Jx`xh>G3W-+y7X8y)IWb|BTqNe7D_VB_RwCj|I?3F(zAxXN=Aq#y@TF9-~%x*$kRk`as5RSq9MAb zT5ZgR!$1pradqT(y?{d;{ z8dAyNWHe`#y_=A2O}6_1P3e*wDcf{FwurflY_*?N$ks*F%`oe5R5!z{hoqZfwo%j~ zvZ0nPwL^T%wof&_9SO~?}3Vu zO}C_nu_@g{s}{vA#M6Ubko}>gZBcjA4IezKJR?-xc)y4J#C)~?N?kqq1R+0fZQ-IUy9qfFxm-!E^7+X(1QT8scwF#y zaWr_A^=v!yvw|(FHp?coQ1SwvcrQKDar%aepPOb%4m4M&k^i&ERb+Sb-9#-g&mLJW z@o7^R@>=~#_=KWR{ZQ8%CshLFqHSqbmZ&-XtK3Dt6TK?mtyMb}!1Od=$UID1l>ofO zKhw-^(*o~ks_DkzPf4GYG@3rk$*AGC8f9>0JeP|_hjrM(bd|joFOHEE=Vli#B~6|8 zE0@AekgA?>k|dNVoy014hr(hHLG~RM zcUb&X)j9K;w0I>}i?En&I>2JY+=a#3&nj5#BC5e+4^a&kyGUxVxK-35EZ#3Qsh%el z!J|yd4$z*-@K}wZq+x~LP%s>+-4H_bM6~Fn$tDiAs_RSA$|A7bdsmSt;bFS02B_+M#((o_!iLF6oZhrUOVu%w3SI{j37X zE}|Mp_7K%TvWuh!l3PW+c#!<`miZ2|JIsETO7VG3A;1b^TDgFIbkPOk*0!HjFqu#(#MmZ~Gr*f{!kI6Vyf8hA_B*dO@U?kr~7Ou1h3UR#lr3X7g2k_S} z(`q-&H_NBVHyS5?{IS9isdG3b8`db>%;6~2B#akPeDxv#dzMM&o5B|fNC>nhyI&5; z6VIo_kyN9n6MVW@kDSCAXQv==DqANJT*pY)P0WOXn6pf}4#k=OapIaCb2v%#sbu7+ z#!l7Mx<@JDxp&yPl7hX-wL8=FjrvZxQgUmlry@XAfWfgjNa0JG&B*EO=7_)~@y!KI zWmH{Q!RbUkL}HSZn^E}1IY@mJi1ARkpw*22yeUy`UXka|U|FmeuWh#Ld?n@{g0%fC zAV@Wd>LaSasEeoqqdt-fj5do}1fz3GE3vgRY(r7(>19V{9MR!qikliRDJ9ZCNKQT! z%EN1TWrn7V+H;!JbrUnAZsfi#c{MKP7Ym#rDR5n5jhsH6GvjIRR zZ$=PFN`h3$jZKkdaK5F$I!PF*M=B%L^>sw)ke+x`@Ce){cPFI*KZ8QfmsGio90P*N zd<2jPWTMKMMZJt~USBFdHzfoWWRYmhX#frlL#uXx-$y~IbY~weGe#%TN;VU`%4zs7 zM(h+IS@7vZ)-0M2^EL&8*OUQdWm>X3v(0u4sxt9=7}V;>*I-Z|QB5J*T1x#okK^^M zuVxoXO(EJUY7v7J4<{Y;5##`&kXm_MYgGFeFe#1&)T2>7`CZB-{yid|I%y@tnG*AyynJ6X?D9Wo+kfyZcukFXPl`usz{7unPTB48vBT1<; z^C=G$ERMJ&$%|Q0HiJ3^;0x)f9$^F5wSr3{(i$(XYfM>r-6O{hAfj?D!JDVm}&f;fmjT~ALzJ>ZzK z3{_cL+dIuR&SKQjV%$i0JpuEng72w%65e%rEe&wJGLoz1uDCCVcS}Px=GAowWM_}L zH+G%tkme%vL^xXYLN1FPkCeR+v+we_efx22`tzEK0$pzwK`PsH0I7(%3sSY8RUp+x zR0F9Vq8dnbk<>tHtEgp=3Y|fUmFVShR-3J!{EUg|n%L3&&1x;@Dqmw7jzG#s@johH? z!xWXQoem(>^VFP_Fj((nb|opF6d)&WjT_w{=>k%iVl*OURyE4hd!FqpxDZT=%RKN{d;0Q0SYr%Lk7J${!1oWMUqo(alISFSU zZ6%PP|1TNj6u7{}*v<(81X7K5|!(@sw33 zqTRSk1BQcvvs}q&OY}7mne~W%m9-#trMnKN_y#N=>O|2Ml9pP^R~FwEXA9iL#gYmG+Kn;# zOKocc7mJROwG#&jgy#EE&+TD9Wv)>B6eM`+qael0lQe$yRmL0nR7#^$$B+^K0wK}G z+(wED97|?gv=(tVhgTt9KzHU76PN|QuOKiG<2H-!>HNZ2BaoZ0;mp)B=F8FdMySq# zQ{xEbLl~ROFy;@nQV6?>CLWQW&GtWuuwNPN;NsoC@=FJ;cKxxNiDY>977jK;_1~(lF z^~EX>l2wso_d5j#jv|jiX^|%vP%?0agq(BNvKY7uu3Op1hfSv7c}*3<1h$u8D%*5` zsff7?Q?;K}Fx5p=gQ*^(8ccPO)L?3>sP!;K%i)CK!HGZW?D3sE&Ag#usA7JYwtYJNgaSH{xB zLBq%sF5{l^Qk@{nB>cd|^aDbCTtmnDlajKMI`yisEN_F(s%d0vXy*1 z>R3#s7pQElsukc~TT-?Zx#lsAGRbhIkGpQCcgcs$8$T5t_^=ztzaIYO{O{)iU$kOmfP6$i(4$yFwU&=yG*!>4umyKlpwZJtWPnv zc-4x4lmm^2Dv^RX|5L!7k*PN&S_Z8hMaAV}0j7R4nq&E|KcxjoN98M$_S`JMB&7p$ z7n2RlcNc#=O0ytJLX7dS)p}4PRvvIPRRj=ihWnt!UdA`CkLbwalFC$-o8Sto*yU_Y z&@n#$6ru5P#f4WDaq%g}9E?jdtVZ!p8Or~~{a+rd;J zaMzwbR(nb?B0-P8bxnmaiD!?xmiMaYL$S5EZ5hN-9~ zWF!{Xl8_jG0^w<)SU8me^1><3aQGC{gRG30Yj$;Mo4Q1YkpN3gqF++7j4xSTT9rPI zgJ21VhVT?@$DxS13m&zfRXEf|RKuYjq8bi$k<@T#tEgohO7=02L}-9Nsf+wQRVdJs zgoB0^3?*S|x7s#XZDNX{i@u2bhc3(*7!sR%kyhJ^#Br3>i;3g4O$QjtuI|E6HdyIA z>LKc;4s{T9Q-^v;x~W4OMJ>Zn=;#7NpE{vnhoQetAL!sb`gs_7sm`Mnx#LXDMXRi~ z*$zV`<{k{S{jAZ3`iLqR>LRLOsE?$Aq0ORJz)-SYq78)(b>@qZY$<11f}R4Fkc`K= z@{uYmzNIAKad?I>AY~q0&&;)CJ|RnD!ZE=3jkt?s7p06v&S5-Fl8W-fRU8MB9VQdJ zG7jYiAr(zENjdVHF}rXnlIqz|Y*{OLkYb*^V@x-35iG_Ok|Q`iN=@PmiN&3QreFP2t%p z>Q^95csl2laj6qK^CTxZTFPFE$c`d0JZ)Unl9+j-l16x*K|8UYWLNd`em|>lqKl}8 z6Fo#VoaiE{;lx%^D{w+eG>ycpc1Nfii84vC6^Om)<02-N{9nv}mcl3cgako5C+^SBktKoAvrAg*)R^lvD}K zTf@~wpgATCdWFu^(ky81bMf`$Gqr;IlufwmlnfUlOwvkZa}aVci*r52|Fm|OBWcVw z71fT5J+)t9JePJ}HN2%Kltw{?NC}>Epy6RYHiK+N-N;By$(A7tNb!dZ&&up^+^y$T z*t_`7GK6p}Hz%qDj(4whGV-m>A60VF!^0<#af?22S(EB~#nZK-aiaFK z3MaaVYBf6UB@<&v`UL{hOv7=Jsoc{?|4i@Vh|FiA|#03X<_6>iZNrL1`&y|6&#b! zA6C>W$(wL^@j6LKid6J1RJ_niWvA^&tZhnt@EB(?{g)vo%exd)zd6f?ZR*~dWa~I8 zmejp$(?Q+a>JxcQmyUiPK9L@tsNH=ONA>PL`fA+FJCJ@NAYGR(zFf5uZ%+px-Rd;@ z07$!t+Wl+0e=Y90ug1T2A4m@=^GTbguTmo&X}BoNK8;4YCZRp9t|g5$+jIcZtzNYc zfV7LK-2oXO-5rp7kOOPp4#J-ZgjZzqm;Z4Agqx2t8;Kt$%v*KWzq$sy#BBA2Hn%_@ zQ3b+XMC~5h-9!63@X(&QNA-0&J{EU#2=%dsW$^!<_Zi>+mvO=`TAy)``g=m`N!^aO zG~D$lwRuE4NlVo8+m9n(y{suV*qx^x{ID%n-ovAt?2Zo3;T5s+_gTKX^YnM(JpDQ` zZbc%GsnbS#+OG;!fXkgm*dxok1J|N${Dtx1J*X%Lo!|bZo4;7 za@yMzBFIns<@EU#`1sz=-K$xn8tv7rf6c1;Gx?flMYi%arIy91FM(3Rqu2TR&O1Z< z(V8+9J!u-R5H~FwiZC-|n7-~ePDHt$qP(d^(heqNYhE#d@+~SPRwtw+LA6Y^2@sA~ zPOYFv(Jjv7j9Ut2u4@WqcIV&j{M!p}zm5X^`-bsX0ck7ha&}+eR<~Lbf_7iuIaDD( z&n2+e2!E~`;roy_sj8tgec4*tn);UAwYR(W_HyQ(GU0ashbyX7G-=nXG=}*vv%u6g z9Xxs2)!n?lY;eat^<#2%9noe{Ew8V~QI&?*<)B)mW3#AbPu?j^FL)fvDWe7E<<&K9 z9rFgML%I$eLuB?UC6?6+1WSnyPpMwj)*v;mQwYEhI&5>%gr=@qAmA2%-vR;G4|eeU zMEQ$vC*0z^H)$iD6fdrxxM#vGUX>zg#iD1Xmf?-V6X`ztboi(JTWj1kcBW4+`erKnT&cd6} z%~it{ZNWnOeRi(J^YV3b);;Ge({NL@H2OXiAG5H(QELR(%M~d?J~TA$23|0o z4Kui3E{-tj zjR&<1bM@$L0jD(1fHY4)TgAL zqc)S)N%>|*UiRl#=|7%1{MFKCJ?9KtYrN2c!Ta!q8s!#WEGEY>YDXB)+(DVkVL~&Y zaByKn7((!n)*5ZZ!rimTa5`1`Ho5Ba#Lk?Vo%mL7Y zz6MB!!(?{RyVRe(0hH-CR|rkBtg-Yzx{StlbQcuC8lbkH#*3W3gEY)%odQ7()stMB zPwACz&U?KwG&2?v{4v!q?D#v>D_v~YBYGu*jZ}fw#}U61s#>Cdnefl z1FbRrktfztKGrbV##angQyPngsp{)hLZ_lq56DIdRl@yV2`xK5^Vz8nMRTm2MmRI*hQVQP<~y167f9MpT43se4 z9eYLzXqttkRYgF=2t;D+#pZ{}P#bst^(oz(b%!|P{TmqaXa&=dBaq|Gm7_8CqA!P3 zIg9s|yb8s~Dtadd_r zaL{?;80Nw>VYaAnwbtk6ysmeRirSfQr>0ehVjD8|;TE-LkV{Ws7tR;ZR^F=#h$y5T*5#t7X@mx-N{v@wY>)4IYtt zb4}k2`F5^TBysSL@ta&vsO7R)&fLl;KE<=kb+%VaVLE!qO+}`S3Xxyh_~vyr9kXh> zzP^^qoA?TAJdJVPq_b0{3rZYR=E?d-0_-&7MTUWl8NN!VK;P!FsyA<5Q{r=l(!+#n zhmYnl9%`PElkHJU=D3`QHy|i>Q=JGj%6M|t`3}GL*#+VxxVrwAVOwh9s(O?>{aI-dja2LSh2eg0!dj(zNHGOJo_E zE_5Hwzi1?*HC*EiPSNyrzhuPkOvQRQ$InC)xcb&K&5v{iE-0=iFBA>ho4ARf4q5r3 znZ>9~*CZ+eEhu4Vx`}j{AD(l}^EnqL~Gv2_Q8Eso! zfZi2EeU$g^zvqoi&QL?LGKU!)HpzsjE)JQDs;;hhGk)HPAO^U|#8Lcz!kFNnm{%!+Sb$~q>0%z&vY$C2?Nvpi(M3|qc~@Rk79smpV-a!Z07jIJWUyEm za%(hlQeF=8Apt$PzmI~Rav`{=_=bR<94)0ZNGJ`sOS92^G=#|<-H9IsqHdG2>&tQ# zj$63WytrXFO}LoU{ga0RTFI5_I5RjBYfG^@+%R+Vvf;2zk$<^yE(sKhVOwWf~X29JXn32bWw zuL&M5yqk$T&Ji~m=b9aCS+8vWn@`N%(xy5fWl?~HPmCisRu>vbs`37GK=JH7@kl62 zK(uz@nx?*HZUK9C9_@yX_;3d8Y)w7dnV3CXiRaNrk#muKL`8d0H=y>aqCMy$DcXaz zqOxcggc;aYdiZ3cDFXxN28DpmBjyeUn~XBOex@d(A3VqU0^KaS#KaKPL(Cnn8vsH5 zd6+?~NjncU%v2KCxC~x<l_Gl%?=Pi;YcHxC>j=onCE}jrtioPUNbE#JhVl~)FNeX5UwSW_L6izs z3gvR}@gOAfbU^b^L`QTCbzFiLp`$1%4eOpKu-CBehrj*TPal51`sXi~ge3EEJvM=S z7DHM2iSxmZuUtcMOtjc4n10jMa(j8y14n+Tkhj*pol7%a=p}lb0 zIKsMPQt>3xArQUd(TVBC5wx{5#-t{9t)n2xdMYppC|U^~9}u6)I7~O(B+?b+NtFFr z$q;RN5R@qz>1QHVo>Er&HBPZU%t>hsdx#V-WT!OZxf1irIB`@79nSzM8>*p5Q&1DA zA|F z##-h@>cGRTRHkL=cm-o3$Cxyr$g!hnwH<@gRgDY`jiNA<9Gs__Q(*x%$P=r(R~J&N zW8pS&r1*q86I5dfP!FJu#>{g(v64?sjVOrGSwD(SEa-_~sY0geq(K2ObZp~4TlMfp z>~vPH2^e}9@+LCD26)KL?y`ckdz>=Qj`Pa1t<>yl#1^eKdYjA2!A}6)M}{b3~U69Df-cn z*fqrB;kXNVEReD)v5TR_<3oD}23o*L;OXB`ES%ragLkk!8s0U$^T4~3T8^d55|`;b z;z3+CF?)Cy&r^bTKB7|ajyG3(RVjGqAt^evy5lt$mB%|G+y@m$4Qgc-kqknE5N+)R zL!_^80WmJ1lZ#tou5M350ti}Su@I-@cNi3E*n+2`{^uBf`U2eKqEg0$0BaDzUqI=C zpN0*MpYb+w)IcIV0!N}M99GFvmPPjVa!kLT67ei5NTQ~B#G>SgS*NFm3O7Ch>~}c_Saq0#I#Pqj$ER|&9>$_R@dffCw8$I%0!|b* z9X$0}96sWY9IM>eg5nIS3kxugHT5=~ooZikb)GVeV`a6dgmDg{62^H*N*GrussQ7l zCK$#k+5!y^%%cC4j)ZD%2)j(DFj*Ht(N4{IA=)-DHy}B%Xi3Umd}Ymj<-h_nV&d{h zTjWng|2*Q^P73C3YAgli^r z5G*!pfHl+;saLiD62>~# zz*=8YQ32yHn|IY32UwGsT`aQm6v3K{s0eEwq9UxhNQ$slD=H6bgW@zaz7)3~SW_uH z+*2LRbeq?;A&!XA#Hrj6N7jtGCn_%kqkF;lR0IIH2OxkXHBaO?^@ccL3oRQAaVQN* zh@+2f6%8WjbHgqLF;thrk#c?^4wHebsQ?RAL^1W#6=tr8;*?x~ZrE7ZW9%^}0Uai^ zB5@puzV_p6NeLNgL?cv>AtM;bt2D6sf@+7B6|GG`UZ_fLTbK^+A}JzKt*AT_wXA4R zEs5ofGP>^(t_#XYEYqB!R<~?)E}m+JwcVz@5JtR@`ymWsKErfb zEy@9|TQ>TAnbr-f33aK}1>bi0|McPVx8HvGmyaKR|NZwLe;;Z==7z)w2F^Zzsc=Wp9lJCsB@W!t|Dxc>f$v8rb)KZWx|FlD#l`g zX<){xok(jDsfJUeT%2o84*25QUIPo@JwkFpeNj-ZJZCa%O=B?Z1hyN4q0vDLI8(2m z!SEhYw4h`O3S$9^YLuLywyI>wPPG?AwFPDLR$XNEtTmChG2N&Uq=)SZ<4ln++Ot~2a9Yof^d!=#K{c_3UP_PShw>0$F;K=yeAbRUc52It@u?~&de_p7 zH5la_k}Rj>M-;PTJW_nl1Vp%P+b9J zPZ`Nvk(eF2Fv&fJU|O!1TcpZTq{g1S#6CHjxGFHFRb8NpV9k|V)=RxLy7TD{5_GT+j8E^{ zK106Y>k`iOmH60V*s+x76$ZB6K4+k4A!u}vsBwHQJUr^0Fi=OJS?=Qf0%}%R5|2Z? zi3sK`bE`Ndn!@qZ1uDZ8t8j#OsT+ZZVw`P$s`Rj`kTsi#8^Z`l9Z&GM=>qc5MZ>qh>Ae(Au0mB zi=+tjwW5lF9%vNMYi^c^>>vt^bXtpmW*`HOySeOCPif4RP+dd6KqC5_YdhfQ5`aqa zE33r^J^xUmsuLJUfoF?)b^`*04$v+>Wqzb$e|ntI-j3Fq=q*sH0c2{19>#{#?+>Td zGA3^OfF{-@51nwD?aem%qiD*&^{g#0;WP#VzaOl5sG1U}VCD%ptxg5tvo;|fPC92J zMmQ}}G+2y+umiG}#|=rBMn^x5q32kY2`s2LqxLO3GSb%6=XG5ho598_r$%CNr@#IT?bjy>U<qqW!#6-iHN{x4vZk?7v8Hu$ zDk^kTD-`|(Lz{jm3UkwVghDNh-6vSn++ev58c#vJnvP6MkjcpG4z4N85pA}~_%oKqxmdhS9%3C&JOGk{r^$~{0PPL988Rh! z5P943lQ8nBD3)$LG4~frO6Ba)6i)68AJUq7L=F# zt`wC=WMN)^QulHIL#lWriG}-(vdS*uc>ul8mMbg?!X}!Sqep)LnAD-C4v4T7)2lgdlsOAi7Q&ND0pcH`( zSgIWOsr7RVil*3vD1|YI0%@1z&)C$pX9(h_0f?7Xt$l&5m96b49;U zZ({Z!Kc0sb+yu4Xy(Fk{u6pip&QCY}Wdv+{V z8Oc1>L>$3wO%Gc!S1nJ-!^i_DdjzvnKc=TUPbT&&+JuG1^Uoe3HQ=M+Q_*Ye$psGI z4VUnE3#*Yw5D~KrJ55m-I(T7j@#hRF!RoU9DAGI;Q#oM$+|WzF`ndilBxD#9je}xsU%|&|$ zE`yGA8bf_$-06}AVmU$P-%OAlV;`kQK6WYxB1ssPH>yt-Zh#4#h5c{9hv8VI#Rc_h zY?RrMr>$|&Vx4MNU$mgeaI-6_78SMFAU9r64h0#3u_jT;clc3HfknFjEg&jSE+#SU0Auc$S?T9 z7sJUEz&&SxD5#Lav(Crbw8jA-BxYBu?L4f=Z}TpqB0zYEiU8pvDFQ^Ts4PIJF>%}G zwas%U&RdHMYG+8HVRK2h9*@u18V4=bsdlwk3(B^67g14*Jw!znFiwSYQ zT`jiSGs}A^E~H40Iq3wD@XiU*^KY}nb!2kR72y}j2lIe%w~i;;)0tx)$=P!Jq!yb1EtjCX@?#1uGs8j8#p%#?w^)8~4#qMxb$zu1Alq~j2QCT(oW|#hzDeOD($qNYS*g5&2 zoz^&LxWw#gxSgkHqjeD#HQYl~)NmI`QNwFRWi>qcV0lK@4Wil9z`(LOxW?`k-dP8a4|> z4C0LyagiSE6yZ>dcon(v8Yc!Si!X*gq9%4_I0u@uNB&R@QBi%hSF6fObWiwf94Irv zQPwm;kzcJ2j>sVl2wO`x2+eZfiV0{k%v-#EPHgAow0za@1cm~FXX6RfrsTyzinfl6 zq-g8ZipttL-yBqUU%a4K7L(WoNKJ)>BHsYA6H)$d_p70V4ylZMF2kxd4$fe0^8XGU z(nVB?x;n5oQq%tcg0F%MA@#atvs6sr}LMX|;cfwA3qB6m3FyC6GI=GsifhZ?00C6rn*GIAiR zH4Y$KOa8b6vM!=h-oSyqlkx^0l2YEFQdAaX8&BrjOJ8(@M#aDp38sFITN zC8Xy;UZSFe*(b)#+RgN4C{PM92$T zo4X0qe*450hC>OPUtFr3v#2!=&SEWX>yESNA}TtI9-^YN=prdPi?yP%R@yg*!y3cw zj631%8fcqZS$jd-WSz`>aIyy4N=gtKH?5Ke_Qe79Ak5uH`YSIg3vG>?c3#}HnUN-L z_@geQUcxHyXDlfm5PvCWT4{}gX;n*=x?@_oh-$2|H`+R|)mc8F&T`j0Th*4^%RJMd zHZNf{@K{nh(D-1L)T=M%nFmSjHa}2#QCah>@xh$aly5O~HI}gU8gp2iZAdgDDc-c#c}y*%%!(=;yz-44u< z)wErvBk{^~UZ#lA6Kpx+I5L2iAJ8alJTf$lRuc>ZVyc&B0rFG+#s*X}D0t=@4J`X= zJ`ikJ+KwNJTI1l9)e?B_IAt!P z8rP{!{d#1|-&?92Ts2JlEx=g`b-eMLDyc+Y5@?Oz#Oz)TiGEe1NY5igHDSiS3Ct;> zi#JXagst611;*%N#m=WR4nKvF&C1vP~8P<4AZ+rgR zE>~cABcZ6Ngd5(tOO3nKxJyKUHAj94FEl}Z7mwabENLnsV>iAMasOSv&e&Qdew_!2 zDv_~kMP)|jl<%*y8@Ul5ryQl}}h0;rlSyE@DLRP+%A%0Ka^TgSwpA~D>3Q*)XxEp9l~~8 zr^CqLIY!`}D9}WG;khh&9qI0NKUD_3;5g2-3}X1*VPLA=qUm+gb7?rd7>e>a^4tVd zWpx-r`U*5m{Us*}oUl8Li^k~1X1U?& z?p@clysKLu>n3patrMZAUuQ%xkq;^lKMX4;JdTqvYO~|G&5(Aux`S@W$caW~0CMC8 z&ALIvYPR_>ARvs>Y2n69O!0%@6Gr$vkZd@9x)@ib#tgrBbH^}oCj;l@I1D3~tH01) z8tAq(FavOyG;9#wkqqF&7`OyJmT|q=)KV`@bTS$FTt;pKV*ojRx`36$orl51o#7lR zfaTsFd0U(aO44zfcv*Ee-LSqBZ%Nn3P{EG(!{@^%#3Vw#bm-yb@q=n^f3M&kj9`e4jn?6cD~chijc7eA}9OS;O10uoR@i-J0=ksRH5kzR`uhv>jwp9rCd-JZp=E;e9CO=~Od+qZ5|BC&@j3R}beM;M7|L)O_!J052{Z_A-w${(G?QQpj_V349E1ve zufP|$qG%HBw8xD|(9}!GTg2=AMZ5~wa3InslV(tCm|%OqzM5eBqTsY5{|ZwN8(7S)u*G;a78((8P+GahY5m^Oc9J1% z0EFa@3(@@3k!xFyi=yqzi$~iFXxmu7dEZcL9I!`XcCp9KQ-nP(q9XQqh>FrdA=5G?_Wc(eJ&uDhcJ-S6xd+Ln~{XUbj^1h;@2gPKWjW-4Ke$$ zrt_4+nun+aYYw6kta(UEuvRH54{MWB*YFpbN%fMr_D%NM_st@nvAs5zFw{4ZHTHoG z0Pp}d6SD_w@jNBK<|7Iz;&}1qYOl(G%}0^}TeYY>u%#?wv)8`hT6KK9B@utV`sXi~ zVJ>00Z(TM#jv9D`$4yK|#S6pZKBACfz_TB;kMDjT4sU_SLDDVo)QQRiPawqIEUG`! zvK~a9Z!&tmEA*VR%~L=|4@4_-Hjk}waOQNXJ?M$&*;jISpTiYs{E*mgHuYn-?(8E?hVI<-|Or438Insk<21&3$Zj* zQ3=^ovrGq(M7P5>o~R3iE5c7G%hMrHLP<#vv{f26 zP@oC913Cmp&Px3?|KwK`RjRZxP_D>Nj{{B1d7qp^z0SvzswgMO6H~`~=_xR@Z)U5u z9My!1cRJJaT*MTPs*e+sh3#f|M9h70I1|Sj%-%rL@u42nnhj6k9_@ zib&$kOwj0{ai~I63|-#m3_XrFV~x=1ffK(@6dURdab<^z;?CtXL95_HQMG8`22eXb zY|E9Hd6W-xYHnl*lzDP~3RZQDRFGw*q((JUu=)9TMw+uDb{*#%?!v~0zfkhD1nM{u z!pF+-)bpw8_NolhKJvrVQ&!3~@`>TvbFY7fBJZYDHxc3ysH~*DV}I(YSf6RgcoGS7;BUu7{ub264{` zacUjU=dy(Z<=}A9)c;`OXQQ?TeL&ECsUF~XzdGPFPMAu1x1i=>E5wW6}fq({8jQqO8jeGN3@m0ILL3#No=Jz@r8a;o1B zMhaHg3~N~S6Fs@<-vBUSm|-dLb;4G|_QWis4vHVEMeQTD5;o{r15yEz9yuIPW7is8QMIT9NDiVBAbChifK(|e4@lkeUH}Pi z508%4FnBCDcJ$>DH5*3{w@9@{_*imJ2YIGAG$TV9R_>0DeYfH?s!xtek&a_8e~5~v z9xpWD=HS}V7zQWLjte%7*pqS#sfIFN=dh09nlnPh$JoLD<%lW6SgfAS*O-=6P2uNJ z63AhK?T37Nf~^!V;5La}%8@qfw5Y)&rYKXDQ@DXkCn!@zkkd z@@HOt_`mN$FFz0I4Q#dI4(Gd(%3n?0)&~K@y-;>1{)E9*(R6l+fk)sE|<%;%E+X=su zJ&fH86zNZNogwVC(9`u^{nH3yz3NQsThS&Qz zB*;+ymHmT#f>8B|0R5!6F^-yCw1orVaVZ^mhgpQ-q#&{~wgj#D=fWn#D*g;h>@n|b zprEkVUr|;_*qZ-o+oxU;*nHz&BwI!2ynC)lP|6XkhV)oz7DRbRMD-&^d@oK<6PT0bQl2EYQu`-QTSR1xAt2qw*TJix!>a z262NU?(s9%jV`Zs5YKPK4=AWq{GT<{PB>>Qk3-%hg zhXw&WKqfNiOg$?71%?VW1RQF5b5!$X7JhA5feio?9aV7!F@vy7KsH*Bat`2(7}6v( zCDBL{j?3p=Xi)MaRS;f$$Z(pY+_UMGzJax`3AUst=oM zV7BZva;NHMsN+B?O7EJt2Hs-lu|beL?7Au#D`CQ$3oCFjk5{kvY72o@52lrg*@rQm zrwqn2Or&_p8Bqzw97H7;^N^HatWs1K#`Y-$Jxv<$K4?r}(Ul>{*iiZ!CA4jtN1Z%8 z8@@0=4-Ky(AILOG_5*R;`9!xs($_}nl4@E1bS;uBRJ^77UuUX+DImHt=Oo*V!Pf97 z3Ectar#6ByF}uj3Ybiq(t*jOmk;Ow)L>3oG5m{Tt$UzU`LT{fY1e|LSZ606<|-m z>yeElM8=j;DvdCCG;c)efld)wN4yeD5-;j3gGmK6aGs5PnV!}-K#0Wb>b;#uNQLRR zp8|6c6(Ph!RD=*0NfAP7MP(txnJx4pu<=sF#jlg?ZxaS;^}#6wg>5En@iL25;15oDj$^R5A*v2T_VqH=%*kPGi>jR$ZbW*<0oo-*L@ z5S4(#K~w?`4@n6)Dn;diW0!sNBEa#01Hx0+STbGLeS}Bz;fKG`6gJkDE+s@?_&-_A z)*1)RmY7}5w(}Hewu`8!*&d>zX1hp=nq4a@tJ!WWnR5Yw#%8Hwvy^afC*trqD?n=; zutH*XvBJ(%gcUBLB35{aidf+yDPl#fs4Q0OvsqpQ03M7dG}g&mVx5#wd?zS?SwLcq z2Oz1wLV0TV*?NKUFTRex;p>wBb)GUn@(`5($w5>CBo9dmkSaxG0coFg@*;rrpj*<| zA+LrVvKFy<3npjJK9jR0W*2VkJVkKhA}aYx4p)_YB@ao-SE>}1g_~#0;l8Qv6c1qF z^Ll0PBR9O3@NWbCE^?NT);L%~60-|UcAg?=auF4w$wO3xCKpK&nrcO5p=na(FMM;D z=};Xg|0Cf!!Y5blAS`g`XHX)rSE=$*fgmJR7^2j_*caSWG2@}A!iLvydmaz|UcG8) zODQf2JS0e{YIwtxDbbQt4un;sqiWGruP9~)QpLs)s};9h4OVDI2^$`2i{wFDfS^uA z5QRnXh2dow7mgT|ah!Ms!l4rIMK2f4+2KmWinpFUkYgBe#fW+xxspL`bq0}TpwsF& zs;>>S4^Bsq8Cu<_CQ`>5y69R$7aa>4Cu@y^)=A8+*4cTAw9Z9T)H)AQQR`eJMXjq9 zmDRch&XH-I3e5)efpQQU6Y*%0x*{1tWr}GX*ioyrjw;|swN7U~s&FQ09eh+Z zm@=)itCH3k>73acy-IjFMy;d45(GAMJ5slyXQ_J%jxoPbtxXV%U6q1glhN1x0{|jkB)`a;_yr&5oMH+)k=B4mvF{yE<*>Dbi^dQBkKo zL`9u;krZ{hR#aA}X^Yl$I_;#?O!q*N?WAa7?M_<4Z5*J-=d@019JEeicD2sVQ>1k+ zqN3J$h>BY0A}MNJt*ETl&DLoU`}O_oq?%36eon(hwI$Ge;jW_vkX3fQ(AaX*24zpQ z+hW8kgNKn$xeI+NxmGq{wNu1Y@dbtw$|44S9vFPKW1VUr7<8U8VDJ!?fWbjj0tOFB z2^cCxWr1O$wG1XUwjhS#M0Isf1Dk~&omNSH#F)jz){MxM@REZ^r7ONKHSC2EX zDGiw&IxKZYx=vJIaeNIHwztxi(ESGL*|NK_YTmS{u2@N@+E+TAr%dTQL?xwj5S5h9 zLsC+@N>N#*n<qVbor|cbbsnOk*11TET30J7t92=w)V8|A>k1~7Fy==3 z^5r&Ct#MFkiP=?YJ5P~HyNHS^?I9|vw2P#u(zT-UDoxj)wvpOK%1)2dsPquGWQ8I{ z_aw!-m9io`r0yU(W&^}BNhp-kpa3jK0jq%*3HvpTIc z4mvF{yE<*>Dbi^dQBkKoL`9u;krZ{hR#aA}Q-HW_)81jAt%Q0-W;d&JTH~N}60@sx zcAg@oa}gDl&O=mGIu}V%>1svgl@45Q8|ia+q+1EAXri%3&V1Dx2d$HsU9Ge86ltA{ zsN|74TvhT&JtQTMv{F=7>rz(c9c^_jDRWyix)t%BhJ3frku?suAThhRVCN~q1s74t zt#!DnVPV}PLlJPMV=&(9!A8F*_eF(UfRYjjx{n?4 z?mnpfFz3I`(-O7D$0QMkFHN&wGGuVGtkJo1?0PFzv4^DO6jzGMB0}RIXZgp!{O50%Km5<%uC9LiaQc70{`%j4|Lw2;xcbMh zAAX=u!^K4GYSs`)Vpl}6;C>qAk)t~Q0X!P+qFmLa37;U4rGG@lrjsuS03KW^K?ebp z!Iz(t;%YWbkPN=427Ky^Oqc#Z?aP^*0GiSGrWdZL8M+2f@e2?N4klQnrs0}ostHu$ zWkK;aekVC}HUJ{p%C^DB=HCM&Bw)VU7%EEyi$5})2=WOkNwOoC16|UQOSsRV4Pb=C zO-FX}azaeCMHc&nX3D}#01Z&pn>8E-SdDy2BvEf@Iq1%CwO}QQeozmREi@W_0XC`w zJeP*_t|}6^m5|m%G|qvZ);NG(EvNYo=(&hWW{?9ZJ()osl9CxzDJlzkjsE?@^zU6r zT>yXvspkl(C3HXWymOGMH4czkODVqtsV<@-q}jQ2elq%QGzWhRf%O z%O!-|R(n!e=3!{MEdo;yNeP!LMP+fh)t=l|cR$G%o#^|}Fz*~OuY|GON`ES=Z0=y5 zhoppgm7=nk*Ghk~r9Zod-lRc=Es=AEiJTHjw`zQHQAe$Dh&tAm6WxhAx`>KVM-Nfa z0e6uUL9bR+7W7)>)vclTGL=`mh}!Zv=b0KGx)Q#=O005-sx=OXT3gL^2T@%_rPR1X zIbKSQdq|3iTKoR;h}sI@ZY#)NrtobaQlaTIBlY||b7r}J_{*Q~d~|mceqal*B#2V3W<XV|8Ei-&qY$iyjoFt%xh(zw`SyH#T<96h5NMfv1@7PbEK6I zT}dsC>Q{51XVtJ;RM&mYrBpW7(zu99(a6dIS2NEn?d)+;i4IgNDhqn8>h=w^LfwVs z#s)f9TePU!hw|DSEVrWPBLCZ?5<9_it*9(4x1wiN^1a%k=Y2q?n^+5oo?}3?q*iF6 ztThM7TH_ELkeJ;r6n37XE)*`JlAY{uRVi!lAt`0;D@A1ic_cVMB%E4bijb*~rUURW zLOfX~+J(nzW1b2%G1kx;{g|W_7)DXGN}9D)J2@rPtX6kmy^as{5vLBC=HjYgreQeM z*)(pT`nWr;^jo0ln(E_~7Q!TYki|qSx)bWqPt%QFY~U6x$HybRBJ7KavCOg2ziA(F zv(eV+NZ*Dzj@#MjR!pztO-+fJn#IL3LMwDk?&3)MVbx^=SL&Nci(=YQ(D87dK3#A- zxD>9=N%JVmPPA}Xq~hp4E^E|Q`u*NV!jGCjL# zCV*3bT5hqmr#k&_C))F?5kkN5z%z-4j-NWdOQompIdB6AaXW(gr*caI=p!tkS9$>c zINt9mb9cbjr;C|kerJsmCG{91??1QUYmEa+NX#xu*m;Uj!bMa>2@g>bC0ry$l&BSz zMTvpgac#r@yy0^@&RdmB$_!?VpPVXdje{yn%&scid5TooMO0K}4^dH-T_iiaYDdF}HUEXNW8V972m|di?^AsVCi>Qb+9-<=BxJZgf zQ!6TqG$~4;v9m-8n0U?HfRV;yE1lACCNyDp;D3h72F)Pk$F`Kg*bG6k@z~dVcV|}i zW?k3lwm4x)tLb8M^FRFXH=5Y}eD%*?E{DE|6~5&&+aqfnbWvhC=1k^%2< zRmp(&kdzGgN>N!|{AM@*HEQkq@YDMergC2p&C?nOHJ6xOHMjE=skw`&sOBD`qMEx% zifUdfDy!znPk)Wd`(R}K+#T({gh4wH8_YS{TH~OL60@s|cAg?#bP<)zUx%wo=C6mO zWd2r)%Iacrw9i==o2UH!l5l+q@05wJd8lBG2UH+tA1ZX7GN|wnm7u~wRDuc*NeL<{ zMP;F4R`Qpr4h-Vc+}rJ_P8ejVnZSD@n@!}1OtG44A8E9Gf7rItcMLTkDRrcY`M}3U z!cG(Ztdkx|cbopZQ0hz8n#eVM!)ZZo+4zmA!uknwg*hKCq#eiAMgc2fMV>1VwhAkG zt_^!J(Cr(>Gu^)Xl|(kjaqQF#oWe$Wl?P&P%nKfPH^+tU;GBj_!ub!xxpW2a17^EQ zdtH?6j+2GCWZpGDSm;BpS-|~~47koqll0T7h=9ck)XUt;kQfJiG19a=C|}QsNaE9? zop7EGVVKpsT{Hn&w=p0vBHEPIP{ZZZ!|~eHZyM+QUUTbdATOx-WQP> zd0RQNfVmSMx-K!hx^Cww(sdV6$rE?Ds^p1#NJ^e~rKqf~FB%f^Ms!^yoT%#>(xQng z9b;KGaHQw3pAd&hU;{-L1`WV;>0rEc7_X1$ISIFO)bkRKT*niY({rtH*wZCuSI_M{ zMSAWcD(bn1sHo>IlA@m1ipuKw@cQ+9fbb#{Vv>Tgm2zauJx@(6p|}O?xSS?xje{mi z%&sQdd5SdAMO4&84^dGQT_iokRX(S#r}Us%@~%)N1hST@cU7$PS|?idFETIdlT3YNEW+St`t z?Mw|~Di1VO9$keSNSWb9=+zR-Xfc*;IIR4TU02CC?b^uJrY#Ge8CAs2#nlZABpM*c zj%39-e!7qWK6TyAQL~T&Ci2RqkXjEt*8jkEBkG`-z?y3$n(LtPMWVLG`Dx4|5^=X1 ztL*6_YTA?!voWCDL%StrSG(;zMcVBmD%sNxSC#B(4@t?Mt`wEk?&Lf3obn)!xT?Jd zF)$Tt8V8%mh2kv-v9TZUoKXfQa>nTk37Pj^G9wiH9 zytI5J>A1O6l1j|}mag-Zskw)!q~;EylA3!+N@`vyDy!xzJIveL(uriNNEP@0KpJac zGgpr4YuEg4dDuz0C^lC77d-D#b}bIequV*TuJhZ@LkTghW8=t~?poupolDHFp4)kf z^xQ>M)N>C}QO{i@MLn+-mDTeU4S&Vk`6~*BhZ0s=hntaCM3?d}ohqY*Jo!Uw9F$vP zc9q-CQ>5H3qM~wph>FVXA}K0&t*BDve*Q>x%Q!zz#yONQyBb?N=V9v(WeoeYb9+ci zJ9nk1ta3NDHXS6+k*&SkXmWtK(hq?sv%0;J1cWxz6PaTm6GWTg#J~Cj$-ux1&FSuE z4g6(C$m3JnUnvdbd8tAzu!dIrdl<`Z`SOP%!Mpe|8lA9?-fv)Ia@O_pi%;ET3oM9Ji6V(k_hf z*udOHRJ1!hL`7(Fkrbh+R#X<68o69$BBZa+iClh1gC3d_Azr~-fTa?So>9i>MSu$@w()?)PImDT?ADDMe8#MP*^55%7UXMM zok3C5$D{Zm*)X-DvS8He3|i3V<$^v#5r+~2e$Gs4Wf5h_R9VX)Gw>FfDn(_Hsg*_C ziASGPS;W54M1kj>|wIwMY?I9_}qbo&ap{Z4Iv~cvxWXXmS4y-Cc zvIY}t9O6o?=tTE16QN3|)QV10E$KJak-qYxlU-wJWd7URFqTRf!K%i{!IIWEz*24D z$DMGui>Q<(%h@IN?lWLw)5kq7>NZPOc~Mzosny6lrA6Z|ZoH8s*-%0?ZUsFKWkxBt z?jb4V)+~Jf&mBE@~X#2vcwVWX8Fol8%=T__sfN@{&5VJ)jJC+GNRjRO|dmH^$sA{SAK=i^Yrm3TfLk|Gw> zzQ0l|YSmIN-kwzMnHj3k!Mse&z6TKRV57RM8<95}W@i1th zz-d}&3!yAgrJXH7}5aU}edaU!&RWW1>zW*&;uapU|Hi80uOF(Vp? z!bzDy#Sdu6VI^a`I>p4AholrDuN0NVxmJGWUw#(tn`Uv{N20NWs;zph91>Yg zmloC4=ev}l#X?vYQ7O`u^Dgb(mmrbHMWqyft*9&#wTiaaQPCC##!fan>j67!EMj{X zqS637MxyBWx%k=Ub2Hdilj<394?Bwayb5bh(4xwOYtmQ485f8IM|7B_w~9@#Wk- zt#JUi+KRzD;N~JKQO-O{A}y@taZ$IFv&xGq1-DjQdEUj94cs0Dw-RQ5tJciLvRbuf ztJc(XI*JVkqGeX8_(I{bWwCC4%W0WKM+~!#)#Jdo*L<(z?f=(&!-#MF4ALUMpL!km z-~RdOVpyys%0-wqQxz8d<!>C~A*xPX!R|P_5g}G?}Ku|iYtX~LY2Lj4;zn)i$WjHQeE<;#&90Nau&Pd>T zT#sYV_miUAiZbgr#GYnoj+km=hXC4|Fs3CoHxb{sCF-jv*A=idm$0N&U6pfLlex>2(yF=j(+0Ss~LqDJx@c=$k;L625gSCDY!xH*Y0Vwe=+j z?@=mu+tsb|qDnJduNjrjuD|5)R&b+)0k}S_U`vf z(OUi3qkdKkOVd4IfJLrOAebYgjU^u@e3x!CUuCz&UEJN#Y}Sfs617z;>mYvhfr)YkGSaDWB>)PGH}R+%P^E7|?uVQ$PfT zD;$|&woH&b7i92mxi|AhjTavo?=a9bm*YuO!te?Efscz0iyWt(*++*_Z-Hyvc=IDA zV*MEUnli1WgxEaH`7$l7aex|$*@YTA&pw4XL5+*32sIv}BGkA@icnK4DhoBs#MAfY zp=JYWdh+;zy2_x2&K-4>#9=tzFPywKv`i?YB2@m4z95V-I`B6jaevb*W%~%I*d2W) zPyx%%22=_d%Imh}%oi=GhZITKLliqp37~igGB|M%WMJYU$DpKAP!>oqAKpBW4Ba|B zruO#!pGobp#m>c)D4_qYYu1v`5(lkE%C6SyEJa%HASh~my`ZS|4sxQ_*9j`p`fbKh z!L(+3WD;)Z7CUNd#f8Ax;OUh!pbp{_-LyhaQvyaljCA!nj5!wtPeYCf(;_5V7Cwau zSlhS-@br3&?7%ot_VpVYM3{3j%vj*lKobd^6pq;6YT*_1?S!YpWoVcLM|_h>WAt`wcm7=n0zwq#%i`s|jipG2=G@Ai4gb(oL!2$GfM*qpTF4+4z zCO`Zea9}aF0b~nwS&{kH(|S(Cu#hHu%a9K+_0kX#5v$f z2_=>S{ha5}YfZfoVPbYQ*v?agD_U7CD&mTVsE8{rk|M6uipt^&JwDIVi5LkI5|jg7 zhyos?p+O+vFwrV>p~aMr1Q=v!4D<(8-APt(Y6!gd8@ zg_~{DSiJ|$pou&D+-A@);&G9HBAKOI^?-Y&dn*5mgc@T5bsT80$0Zxq^oP0MXzNU3 zt>0=KthIe_BTv#f6S7ZxvS4@ z$%rv?1_7P5gjB20K@MEB#sOSvqZ9^HVV%J#7g6sypws9j_nf6hFZu14fBE?F_uqg2 z@%Q1!fBgFMN6domIF$|NP~WAliq&{P|9+zdxLyp-gm4dQXN~4z$9e$?p>-o@2)&i!gp0tc5 zp(Rc0#ao`P2cfZSV#B(H{CuPS9&!v#Dg|Y+q)|#5rQ~HPC2IkZc4KmI#;MT~2Sh^3E+XkH zMTq1eC?Zn5pomBgav~zt3CbfT=)lt7G+ zsOU)P&DCC2bfjD)MMtVuR2FKKg?w}Ila|~4enmiQ2_1HX_na|a2pOy%;36@*YHa5z z0v8ui5nMb(MR0ME6v3rdR2Ez&ir8Z707}qA=%mjG%t;-$g?hZDA5IWS8Rl$FL;}2t z4HDyu@2&C2YV84Kh*v1;_Xog=pRV7F=MLe5wj_)KqooL3cK(`TxOKfbZcK~jPdV{; zTsW1!U=qRi(7zAMeA9~^4GCXl*7>-p{UV(h=`f&c^4!K;Eh9=SRgl;IX>LJLgW-!cZ4lt-2i@2{85NX~r z$4?h_&te*f_oMnj5p}sLj>BT*1LBv!y`4AB%jLJ-xZO-#F|~<-cLjT&3(!z(jzD_W{JtQv@I`q9TBJh>8H>A}In$t*9)3 zEGyL<)_deF0SNUpP``L*qK^|qq)Lb?V2V^Y!XFC@v`00)_?krj#{jS9UxPSM)hU;z zlBi#{)1tB-q^i>bI5P+-_^}^4*$3i@PV=JKLT8LlCA`>BKwZ-s2XvB{UGv7yQ-n?~ zqLT0Aa8=27@{p8#r%F*-bW)xE+e4@4HE-;mc>>6wCJ*NfASK*asbbDQGR4*+*}O6a zpGK^A(fY`JbrJQR0c4=#p9Np=Ca|Mr<@2fPIN_LJ^7p5iHe`I<)bXiT$VL?`HaqSF zVH=jo18ZX1BlCTSm+(N)CFMU- zI7v?jsf7>48>G(OTPk4Z()J)ijX!)HH=4w(JW%q0pr#*AfzHAfGZenX@}3u-@iRO@M- zhQp%fC(rB5*+=T>%uUuA=ZvF4C6wfbZNI*As(V4hPX(I7*Z>$9z)>d(2tka+v24tSgr1sJ#FKl2hqIS;^6pPVSz1#$psmP z={&T+rU46{78D?Qh|41aI+%{bEAwRT!wn&2TqS@8ZN_ba@q-%&uZF+iZ1`Jx@`yjH zji&l&GX*KotXDB+TrS$xX(_%OJe;M6YD6x-VbWRW;!23n8cCJ2Yiw*)yK2n6B;8_Cov1t}VW;f5Z{2)Fv!5f7Krel;g=`vt6Tpyh((pC1a%%mg z92*fEUKv;X0OZ&ZF;Y*oha`dn_Xl_pR!qDI!&P!Z6Wui+r81n$2eC0AJ zwJXDjps+#H3>ulwBrsV`z{^mf8<_m>)!(mw`f&MML2s+EE8#>h%aS!zw8p`Cl9*jX z#m-aYJh_O9hKh%%XsEbIieOSJDr=}@Inl2*0COf8|EENE-Wx5NL}b4CUcb_AKj%ql zjRQbQ%q~FLd5QqaMN|YR4^a`ITqH$+sufiaP%XL>3&|SbeW_AAb7s@nmC(3Xc<5Qc zGp@RjsEWp|Q|$wu&Qk_>9-ou>%6Ttr3S@(>k)%SBQIu3Ax9;K~-Ty;fK9d1;UDt%i+3 z$ORZO5v|N&h}Jk@h{Wt-h@GbhLtI2f4Dk>ZF~mhu#E@E1^%&B;z3OK2RS!`*!{8qSsXHM1Fl@OtoHO_&F);NGkZG!p^ zn7D|FVB#Sv8Y(W5qM=eNDr=}HAh}CAe63*8Ld6fX7&-eKR}noL7FiCdm`&}0R1&ir z=CSh>xl}HqB2syXib&-mDI!&^s4P-ttM|`6RQ%>kT%W>QdT#~%V^_k`UZC#hAWmyM zj4{OQLY$qa2;#J|T2wN|97H8!%tKN##wtbCL)?3dWH-p9*zfE9-0u!D`ywtnRhU`G zWQ_-8B4!`wbe=NE^bnOG(?L{%Ob`=E?{3Cmrs zR}T8L#sT_jy}Uc2I~P&!+9A$C-?@kG8rD79U-(^OT?xTm6N7SCr!@{(S38{O4%WGd zidg3%Dw=sNlA@VcD=KT|sh)o?P0{+4KisGM9ri&O`x3tS%y^p|j%bYoj!4X|yJ+Vr zau;1hC7a3Ns!|fcLsCj2REo;t$QlmIDX4j^dY*KLiM~ziiSH-%)8$7@D5GkWK1|z9 z2qXP#nLS1~6&uvX>ovW0?VpTpV?4sB;RUQ^yaCOkG+0h;SGsUXFBTf}(gT+PEi_os zfevyv%$?IjfssC)bl2q&Xb#1Z)f!KyGc!pp&_=f(rjvDZp(l%)LeZIp$#3**;q;8F zi(mAMQa2am^mKw^2ov3+$a``vjC@nSDta?0WzTGbjy6)XjM6KE>24V0rdClwa~wL} z5(Cwki>Kq|kv3E`8K#F7Z=U`y$fh?$Z*BB6{IT-e^WcGd+DA_6g8bi_byL_qYIN)bWv} zFGk7ft#8W>i$}eInK=y0rYLJ~!i=4#2xeSF-A1MAuj)1`yo*g z=Yl6Cbn>BKMz+>C;EBZS;)$K72v1x@MLh8k74gJHQpA&5QCU1$*x%lbkuU|UD&|wt z!RC-c8rd?=nb9KgI9uP_zz~uiuZB8KoDiHGZBa~dmXm<1 z5=J$^#Zwv?kQSn~zUOwq^uoCLO4FRLuw=|~^wVW#hE*wRqJ-3{^? zROb5!ExrT%EaprEdTY~xTOo>pTg`peG3!jw_ z5EoGqLOeu82yu}VA*5DR7DD=tNaWdh5;h&)W~DNVeIVe+c20F=;Z0(I1afu6?N@*5!KQZ6nVP0( zJk(h}CB*27uyrnNqct9|g_wQV(s{~Y%R^LxEeBBvwmc*y*s2s&09%CeUjVj}!9lhH zUqHGNaB&zFjVkl-Pxt}K2h9K$$H^uF1=ImepnpE88clv)HP+)nS7+MPXCHXrapnC1 zWBlFBpD<0Nw~Pp06Im4^$GAIseHeL2jT2uc)j_7?)MFqj!6XL;+Yl7uH(|R1xx&r3 zW>Z=Z7>YGd;3GhCcmaX6C_2<_P$zal1kZ#hA|}3qD%o06r443qE$9BJgn$ z6~V_tR0JOvNfCT%MP#YTtr2v@DLTD!bMVqids=wsE{V!rB@R2Cg9@&dsO#rzJekhfqqybWeYC?TYF z@+zgNgHmOB9foVZ;}E|f=4p+C#UL@em|*7-^l%}@#p|bQIEG~0^!4cuvE4;f!~_pf z5ffY_MNFs_mBoY=Zl*lx*J8=cm6Dm7spEvnn-b*hX~bDlz_ zb`W)|)b*lnmD)klty0&CDp2bFiAwz)EbZqeSUl!=oD0Jul<+LaEw8v*B|xlW;f?~P+H@FEE2PeEOwqEWN{G{k;Ow)L>3oG5m{|+bhu4VTNF+ zCKJng;uV4(3`LQYU}M7;xYwxy?lUAt@<+#+wh-z{A#OD7B={3DO)w-l@>8wbM1s^S zMPszt=&u4lhq?&G(E4A@wBO+Cn*U(}>UEi~po-Iw<3`1!J=ON`uEzky8#2MvAsBij zOzwd{P(jCGHV*S2+Dn}16+v#6b3;EM+jgR!9G-X&@0;2$>iMBi^(WeY&?$uf#r{;0 zo7kT#*1;@-M_5i=4Of5|sP;PW|Fv?p z>eWVAHc%UjNVjnObU~fvIc%RL z{JoACK}Id<`Qu{%BW6!A<9SLn(^giCO53NyRi*9ILsHs4D@A2BbcB6-UK)x`6(5o4HK0LCSM3JjO!i(4AkN4hr65j@=ZIFLma>oW&@t;xQ&p;`-jjH)9M8vVEnw3vyp5dB zvBW{=kg}^PI!lqxIS7h6S1%~)oP(UGb9I8UIu|`vqsr4vhyq*NMQFG~Oa;TSAKB3` zENMZiV_CZF3Cj5v+{^;Hn|M_j&C-&3&B_tD>?|dk~Pyc z)c|hSI?c=t8^`2xr8b%KmnUaX|2qDrX>z$X-hFaUQQjiv6fx}vj*L^$eydr<=K9hOv6f1*MC*Nw6p@99N98G4=(2{zesWKTPWTkQWJY9MSYWcEEtJQB#Fn|AiS&d?pP&CM^ zWE7+2xH866U25u%F;yohyGyhj*SF-jY80=4!D0E0jOMkpRFRoholE+ng4Lq(O4!m; znY7d||M}bH5C8MGtE-_2-Wd!NgQRIcr(@$K9lsl_yT)ow2;4 z1FJ-}?g-jm9f&wC2BPBeF1xCgw2$?vrBqEW!QczY=-c}KB_U*O^$d8X&2_@XU z#>#lqnc&tGITLkciZ5}G%9`q|sx(%{x3V%?5aTIRu%`l=WFw{2_GC8Pi1}fMTJTmY zeHM+Pd%Q9tqb`l2FQ%CW(@w&)xjeCodnzD@Ho8coi@e{i(-6np6!l^n&!SW2RKQGa zOpZsx61p`-&PRRae5)^KLWD!P#eNHGDY&1KLoIa^RK;tzH2aB8IUdFd zA~8ejM&>=!-hj3U{i-p|E9YZk@m0*A?tpDyg) zE(>qF=YnbAzyr@6wBvvar(47Q*&F z;kUVfFvuY8Y=bjftsMLek$mBo{w1}Eo;CnzVw z<2CE+I5X>6{Zqh}=|H;_RPc&n^O|la+(8u?4bMOkM$ZQNtgN5<6jHs0zb720aDwco>dL_-#ioqfY!*S7o zT6Bv+Vgoh|fUz78*@3aui05gna${>juSK-Z0P=^_GoPAXyVLG*~oJT*_?Dqqs^JQ z8d|*XmT2BQYN#30_&SG4BX7sUGTaw+u8z#t)d1}QgQ907@YG?p z(CkgeX~1P-PPX1XlMH#o13l(Ae!5@)cYj#rYYCSa(LIkE#jQiXbi5;4!+~UY6(jNk zo>|vl(N}J{>CHh3*gk4lH{!_gy^eS?X95xhWWnZm)Y|x8Dh6C6eJ{rY%{)WAcnP;- zn(=3zh91ILZ}2!5|D%9}NR%aKVQ5Lc{~;-R{)e5V#Q*RRWd4VPAhR$$zM2$(Q4HVk{T{)n!xYBk%L zU&2q>#c??ng=SeTgMtufC&$Jjwe)w8B|&4@Ltv^iKRgjmB@%+of!#q+Sm9KTCxu1j z@C*vb;_q;g!_7+A_nVy<6Ydxm#qK!^7p8!fsE0b^!e~hY7(M*cwS1lU_35)!Qi%&D z=eqz5dU1{x$?L)woRcS-GP?cVrp&n@O#yup2&X5xY>a`F)}+^AxaKwu21hk^2-5p!T%$%2f- zX&{7z-JqAC^yJs+T+*@RP_RW-MO;QwuiHWk`%%#tVhOT5=pw&v1W#6ryI{ExSs;C^ zFP^lP(>>dqZUNP^4@?NiL5kKmK#IidDzBZV2vS@`MM&`w6(Pk%QiPORQT33*yo!-f zE2bLs3&l_SMTyW}Yzih&SZEf4M6ihztX<$%9N;pHxG({~WIYkr#J$iM3U(?2mc|Hy zAMpn=iE${v9qsJOw-EYd00#M5+?&1+P$r0h6C)Ocv7*EES+zt#RLkZlwL2e4)h<1> zlYr-gFVi4OAK5FQoh${+R_Hi+8k^R5Kony3Axh^dgD4MC38EZCC5ZBnlpv~7R34&; zN$f>`yZNdY^COT?B1ocq5BL*EoQxBhCGdv%IYOW~4u>p@ChmM~|6oRwHz7A-Y!NtV zGiZZ#Ews^So{_}Ugu|jh4LPcHGb8G}5r#YSL@8#+jk0)QO{ zOKUu!1~L0kqw|zOjfbcNH4dT@)ObirP*W)?4>gd;cA zXpIAKNX#y9*m;V8!$njC4i8ZgI9wz};HVW<4;*hOMALxi1TT-IJ>LEU6KO+Xl?&zixmO959GAj+qow8jO9GKn5LPazOFh`I%$dQrDP zSlVba6w9myDtoF>doV1|6k5j0_XA=hnpYl=wA1qGA+PZ?5*LVieUy zl3_;m`^%aeD#JZjj!6rfUYtoq^IAfP?O;l0j19{CJ>nuJW>;73JVgkimDQpmf_R9E z2;w3sB1o;MEQ0WnpKAd1brm4C0_Xqw>BG-g|NP~0TuWH7-8$y+hBftZSc*-?3`poa zWq9KuD&dWTsDw8jk`mrjimJw&Hx!R;_(lCN+e>-h+A}GeUQ3v_-I^!RX^jhhWe9Y3 zonwbG^?cM`lz6A{Gxq@?oh_Qdwrf;7KvUkVBDbR={+>h#Rw`P?{?Nmb(c#+dA(22 z2r>JS9-XJm2=Wk>j35V533@yvB_pU(RMrSm&Ej6z8Mu9kp1Wt(Hl|fIK4j4pPt?i>L@I9-<uAANs$nC%#uJ zDH>Gv6XxAY7pY~r3F^v1FDYuL4^+9>*R{rR=$|x^qVqSCfBNG%Tx|^Ipev=iR`&FH zp?h~&Xg0IbIEVwF(bI=PT`cLzpyP>VRTz^X7#+2P`h+vq17i{abb{c8-k0}#KG5#r z^V|^H$IwegWi?dZ@E3tHY&FnSI|$m?sG$TE#uCZT23l)x8iZscg*1el){l%*Qj>^< zHKQ8hPzb)MkXyeXt;l_$ae1dE6HwXdg+rrGjX=_ZMZH#EFiH!)o?htARAc>Da{Y3Ri zm?U~g(W4aMT+qm%Bt8!28gU<%ZMosxqdtRqMKZAaw++_M_sBDSuqqOMYR@rf4 zxC&RM=Z7{N8&}H&CC(E1n%btdfN9*%T|UOGH4Zo?F}pZs=g~9DXY~kUhUZ|OF72wT zMMWI*xT=U_E|MaS)r!jE7&C`YJKG%00?qvmjP%SBQItXff7z?!jmhGzEMnmr3P(KFeW8j-??C_j^E#qv87i>QFn+yJIlmp`{R zw_8~Yppn~LE$W;BW<07@oOS*uO)_Ks%df&Lqp7Hlcv14JCe56;mBXp<`kcbp^kw+)Nvk}ofM)s zvgfz1>(xe+(rVQCWO3j|)|m%|9Ip@(eRElCY&&WxHXbC#c)Ym`dk`WQ%!OjIj;`m&8LKG-QS$ zd>nIL*1SF+SWPsFJ_EGcN;ua8Q^|9gd#!OmD~Z`fD?3jSTDgddXyqX)qLquJh*q_t zvS_todb~b&OY79tT@R{SIq32bhntoU?Oo*dnk0cvP!C^*FXj2vJV8+owep0-Li%?*RATRM^ zUhiX&OcE>_t`*BgvH25dMW0lKh3O*_7*!!oADvWLNCi2|FxwO@zgeKgKAT545Yu<` z2nU+slUV3(m{Y3e)DH&9EjX!(V9JJY9A(-O!`BVP6vRLrM@za?nQU7L5qvD5FKLYf z2ujQ@2-W%MG&kNl?Or6GcN>!Pc@|EOKo6_(u9*5z{leR1Oh$i zjFMJVKi~ucLbNt{#0i`>^?nC&c&51vAR~Wg89)3qORWhgNsbBNI1zLX94OZPaTs6d z4(ua%v7jxkt)a5Lud>j`Es;c`fJ&*gOv%8HVOWL^m2xQE)VB z)U7F3e^s}poP(rWQ?5=_7R8>0vY;G{4cc5#V$BH`tYZJ z>;855kLAM;6!|FxO;8o4fKIiKL^@BAJ>?=QA(6vXB_#5Yl#r-WR2GS({rAaJ!>Zv~ zM7DcXVk!PR!a~qYh<)x9R*3df{v&X07=*3!JQ%bX@d;yxF!g5)nz&*aFdPG?mAm(S z0`yoMHmwjl47&>xm5f1vUB=8FGzQ=W95JwVC{N;zJyRflgnxAov8@tn_{a>U91LlV z0}M&bE)3auieSh^RC4Pat}3~89+HwBJ4axMudx~ zlhqs!8*<**M>3 zQoau+4r#RyfBEy>tn|9gfBpCAb5@$f^<_W8KhGIdTH^pj60-|LcAg?2auJmrIESlB z4xERietL==RE&v;jaT@4TM13MvoMH)zSgdar8Z)Vx5EY(bgu4vqSrr|# zIM2`%k;J)%jwVGMAudw+N(2wm(Fz;su&VtJtldt%wMa;D$*Q}hGNa?v)S`~7T@Q3e z$cJ!{^g7bMhy`~W41M7{L4oG|EhpI06u3f6<9$%Y!7Zc(^_6Nq<`Xm~&I3PDf_T{B^kU++teaK1s6cq3riE(Zjare=W3tjB07?=cld30ZPGrZa z7yWpo6;V(1FKhUW_z1>jso)<^T?zkK4DYPf!x{&`(5ZH{TnozFFBehC>T$TLWc7GR zN>)#$s4QSu*jn{aJjy(ErY5S+ny(~TsXwOK{n**t0Snjcew7~Hv-_nR)cTs; zPhB%MKSn70ecAnFJIwCK^2O|@u1>~s598jR9~zpf0)%pHiWafw*AvAU814a+dpxf6 zdC?IYUOap?v+3!QGh!?c1C}!FMk#aD<3U>)6;a!9!4}6R!3xI8UQ{rt-kTGKBW6Ek zjJ;ZRs#$~@>C7wfOT335Cx&-QOHckeY!pAzUuKi}ji*6XGXGZ7895}F-&pma!ODKG z;y;Z0<#X4WZlv%W5$aRj#bTC^j8^!|pLzM=|Ni&t@7F(lxcu$6UkbeS65{EIsg+Sx z`abz^Mi8^N(Z=(XXsfNP7L|-|hpS4)w}+%;d{>IfYHie6Ie|lJn*lJgGHa;5r=)D$+C{$vS ztK;MPt`-XPY?$!0=_t6MkNhq7V&kNUwRiyKh#a%VH<5*jS_Rq=fKt{Tc?4}JX`HPZ z_yIhiXO`+Bff^YJ95IN%AT_;Gyko)}AMn*{@t}ld$|I1)1FfmwyFu%WGj8W8!UGpk z5f3~>MLckk6!D-|R2C0rdd|L>1+G9bAply@1X~8|3$5>H ze??S*U}ry9Mf*xfs)0VzIfFxMJOBnUyHO=$G0xb_ z7!ZWivF){)s>2=|I&U_pdjR445nEgRf^=L>fr9#^5Pc`x#jdMvZ`KV(kI8*ELE&>b zJkW1J6pB;qxdl-04=`0|6T?ZBu>iSr1(?#wbwPo(tCPQARs*m1%?d04JSPNM>|nx9 zCmN_;DHt=fg8~w<2{@iKzriL>9B6$xozzeSI|9cBe*@12qXqKhgBIPVivfpdQNjg7 zN$wRvMon>2tP%dr!`=%H4VNZ~N+57#8iQOWyc<Oz%zW zXs`(oDDkIM;c39Rn9$Ox!(r%Y1Z&^Si)@XD^Ms@VQE7BvYJDe9$is-4p? z8`%f~VBV-#8F75V3F=g){wGsRXFefONN^ulfxw3J8@ey%%W_5Uw+TuQr?xIiD5XmO zxdj|a6sp*bHn~a-_B5u$Q!A*_B7qjqWu6I=82)5;B<}kq$6LHBiVEt=8<>^GBtM)WJ>NK z$5gyhP*%Z7gQMW=Vr(m9^-&gWk)+58i=j+BdpvVW_LEwtg|j;Uq3GDwY`Myw&v|rU z&JK`3a*anGi+~L<(AtcU!gypfkH&HG0r%e?U;q_lDX{zE{Oh=E00|*J(1O?=Z%j!5 zDgVsl0`zD$6tg}EYjW{sL1>%j()gEN+4;X_51`P(tPzDqg=N-Q@RA0V*g5R>;1>24 zeJp9*&5a>IIWDJ1qYSclWI&+Gy1F_ipf4dhLIBFCa<4V@x@=G&qW_#9>dX<)xJ>9Xhlqj@^ zAX8@tL8iDl=RLNRATImq)huloWX-rOkwENsT2P&+-Wfor~# zuV7!7m=+#{8%f#KU!A2$e;oux{jC=i_18g8)ZaQmdHp4;l-J(}EM(vtn-t@etqtq8 z$7dwvPRt0OQDoE=!8-OGX>QEx2UG5kSjf;_v2_nK2SvKpF<+%Y(;v{?pm)bKz_ATeOU?ZI?|CDuE!rY0Q_LXQhXg2=)JjHHH!I$Z z!y6G9j5avK>3V6cDL*1@t1TU~1zAewBPv?GdUK_B6|G(uNzv*p6_r%Bm}?i~qf>wh z9(S))_OzJis&=^w9?q6o0ofJ)d8`u>dGw34!=CANz;;gsGEKRF08 z#dWwNQ(F%?rnH5Ek}5krKfbII6EZvWomN|YLNEjF3P&5sY(;1p@J*~rSNIQNsXU&{ zemcMmMCjpCx>zwU(me91H1Pu7Nnl_&bT!lvyH(?{#jnTFR&WUxjrY6}OFYqHmIIh0 zS`lGXgnAM_J>pJ8r8QM;fM)l&V^8*pkt<~3&>DpU5CD`=M??0Fz`#~m`l*aI*{qf- zni-3rw}~lDUv#WzQ0OS+P2qx;l;eV=Y~h0Kl7kB#f(#cN1Q{-P$T3_f6qLk;Q3v32 z&Sw%YFk8sZ!U=AEG*BQ9LaDFri{e_wuP{CPk7vXNuAU>Kwo$^350pHc^pyJd8KO^8r%pSEhW28xGD&F~CB&KY~a? z@#sE5@JA!qKpfjWl6i(-r%FLW-{2{kgQh9c`W&KM$L}d&4iK31hN+ zsA$aV&6VC&H0E6-MPt5HR1yK6NKDDDB{8MQ2`4b8K9=zEAp#5K-! zal`PxA*dl#hO#aPXk)A*@C*e*;|Vq9xSN#wRqeRE0a@2Fr@7ux4lm1tpAe~5KcyKJ zs(?}9JXJLM!@pGnplkdAMs(>1NF^hMlzX742fv2%8vlj!Tj_JGeO(bx9G%tNR@@vV zCp!35%$=K1a)14Te8Z7Wy()=rlGiZNG`&I;Hf6-=CJ-RViT(_RCfjwk z+Al@#N461(eoP^|7MUm+bxXn^9ybviEub;hwT{8YEZbH1L z0jw2UYCw4T8WaxTNpaec_5k}8xNUBYG^Kh;e#P*Gc_awV5Q^5YTds+yt)92%W<@es zeW7oXj+Cu&Kq+mtiBejSl@+l&Di#${%HysgO1VgiC{-#diBgot;T>GEidGXT+v<7= z6Ded65kbRb>sMRj06yAk6EU3SQmGh+#Dm@RHI~8JLJrJX&5)oHVr9mXDNzV|#rcmIkBrgt=x}srQs9K4s zt^*~7vOstlCljYjC5wth^B0U3wRBKX=Yg6Gh0E~B6d__mI9S!sd;ji7MwR|>`|n?F zhLAzLB$JS~ptQyT#3W`D#B3i{@GxyBr|qtbMMV(vxT^?aE|MaMm5NG&SZD~3B(qUs z{mbGf=wX+3oQV@*_2c!`I1w?U(}@%5mtwgxLThC6fJtZoTuTB)A%poDGCDBY8V3ML zwM~rsWC4hasMQ5a!J76;*k-E><{@cy!3sqs0p$7uMNes1Dy9F%AbJ+To{&L-4QjHH z$eP<42c*$foA!k@{K!HY7f}&uJVZsLagh{}rc_iCY1)OXP&HL9C#CfikQSLL86;c+ z-N`ByTjKyA+G-O(v>;&=kh-J}-0rAYR0I%@yNUqfA}In$si-u7%oItVA%N7F3v2_W z*k3BQ{vtq>!TLoRla`FFDF-4GvxOdUpBziZM-)As}fk;IM6%zd>cdNf(AS<%(}xZ7IGj$g@DKc-iPq>TH5TIozq{LVw|lfpl7s5@m|- za#yPh!=9z@kNWHm3#;_~B^Cd)gC$RC!^!2>p9ZS)2y$eQeyOuc_tcIZhIM9_lnUBb zTN-2wQfh5JijOEm2p3V&G|ymsBFwM^sdNZCZL)QSn_QMW3KlR9f-X1@_DpzXmEE1S(zx zKr*@Ac)ykRqc}pAReMt0C5nt0*HsC6+j9_r2(WTLiQrj%_}_oUm_yd zWpGKU`b;aY);K7y#B3_B?USXvE~29HdWee3>mn&CZ>gxH@}78L;3;)@3ChFMXmb|M zeV0MDq`o`dx>jo(v|M5~wcPf}(sCD3QOi9a>E2kQG*JuYpHgYs&tP36^s zJp0;3R8(FMQBiqaBt_*d6_r+A^@e|Y<*h#ULm&G^Kp=yIh$18tc(%p?1hmyA2xvhb z2)KxfAmAY?f`E&p2m+;|(jZVX_ovZfV>7z;%illUy!*$Gx3}NFKm6aXzy9w}pZ@mq z?a#lye@98whn}9p^eJJmu$qC;UJ-LlmX~VM=yIZObPrS68ewnR2GdkUz0v3>!i6S` z{19DATCk#VvIJ5Z+&1$edAn_H|<>o4`9(;C*G_&7q)Ho{0xLWSJnd zR-Q?5bGa*wW2xKTQ;pp=@l?HUt0DWEhHM72x6*e?nKEX68lJjHih+SrQR%=yrSDu; zZMp;y=68ru?AgVJLsB2H5aWZmC4o`ha^@hgGyFmtb;d-+$Q|kEpG!EVR)6FdfZjS zL>EaB6H7%UF|m@(ersm`biAPkPOms)l|!=^TPy{hTH^qorNp!c;OQbNf~SY52%avI zB6yaHN`hzQ@cGTjC@?5%@bi@o%08!hK_t8sCTfiXCYJL39$=!2sECOkq9P``NQ#(P zDk_bMl^S_+y{QYZwFWR>8(VW~MwsTA#8$0wz*dRb^ssH8gohm)Lb!;E*yAKI@ zANYwlH-T|-h+_zl0yMhzqB%lWq(hKsj7)B|SC{VN2i^-pb^IfeJ7~nj{K)lACs;b8e7dgIxb+xU1Cw@{qI|K!u`` zN;=VN{S1{xq>_#l(VVc7woK5{7*!5hjCw0C;t}L5-ebIC)NA+>bFdhr9H`ULp!kl1 zm@BU{ii;oR^yM55%s@t#R`Yj_-Rj4EoQwR`QI4I=bS(~NOljt~YVI=e-N4XK#xzre zgfY#yW=bw)8emUbWe5g3!ZG#12@NFHcSaLGW%l#2pD~`~km&h+BoBS9aljLa*~Amu zCkszpM6JHL!(FYuxre0HH!l>G#FLb7jth(C1#`ybeowa){P7el-5xKOLM@bNj&86L zg}%Nt;sHChrQR=k*qG%uN*=7Be39|;J3M%7_T7XVfI2f??^PV>92#}srl~1fMAjt z>T3IBsjG{qsIDHOqPn_Bit1V_Dygn1uh&Uk9}Olaz0}jys2px)7t)brt#QyOiP_XB z+b2t-Ttuxds>5BaE~0yRDhEwcUX6bAGHy1(GU8@51XRlXK-Qd>l*QKfQF(19)#HhS z-H4)zkaF)zgpq4oh!3>H0v28+Og8C`m?q7Ij5hA=q9htQHD$Fe@W-ZFOBmIVmeq>csAZ0mdEvmV0CE*yDBpyTj`Y7mJUG%~PwMklC^g>Zd zkV?7eCkj$0=<>e`+hr30V_9BBz^3``?*51O?|!5~+z+?^{^e#EawvJqDyI-oYaGn9 z(ggMcGtEU*G}AmpMFez_6cMmgR1yJGQI8Wvz~@C#-X5e{;|x`hdIY3$D2d9dr$9<; z96+ixf&T!cTtuybBnJk@8c6bxv<8w2MI}Kh6-atxkhis#=!i!aXmKO$Qnrd z`PU!5BbxKI8=1pK6>B7gD8@l4M-&%=N<PtI+^RgHQ*30FB}SFuV`aHTa44rM8U<$*)#A}Yd_ho}fwE|Q`FR4OV7SE;C% z6I?wnO7+HwQbSZvB1#U~SFE8Fq8JCM+yHVRC`ALvMbsLiDx?*e*v|75B~ZWzPS1uHP*f6LQo*GYg_jcyR=quTEgI|S1UDasVA;Pn$F3Y2yqG*G?9v*CNK+|k z=s~2(MO5?)Jw!$9a*!Am=<*Tb8eMq>_vy)vT;Nl0Hj zFAuubG3-=$Q%Tb(6?S@K)97l$SZ|Mnv+8u5!0SVA%`V>_33G_-mD5y6ANqoX9-OUX z465*^l1P|}L49KY{+kRV_D0t>dcnSNRQnPGMq>_NTx6V-)1@^IPL~Jo2XlO6l9P+5 z%0_y+&$JU3oM3?Gje+J8qdQ{`ky?zE6wqjm1JIO`V;)3zTtrnK(TfAkS@MW3G8B_T zffm;!g#}vUfCZ(rmIqkiBC0Zg+_2zkLnm)+!dztBB!db~#YeJFldUO-EfcfVq%H1~ z)1=Kul);vZC`(ZJNU{V~v8dd*i8=w%b*E*#&baFqweF@jvpQ(gv?tK0hc4aSGU<9~ z$Dp;0(_v6R4}XOAK?hPLFiU9I4X>oz_u-MjJc!U(9e5`+4x*1Qvw76{hZf-Uj^PIA zGQ@vQ)&gAfd&1D}XBq=(S~5;L9mQ$zyX^WMt$i7qLj!cKv=^tjkzKp7)!dzt3^Qf+ z)?$b`Kbj-Nk|=QA@k+-a9SP(~=70CyqDJHNPnzDmr!j9#OddXV^=29val~gtvn2H@ zAJoB#hUw~Z&WE7J<}6|kQkZC-rY7nWxi8*l&|6fq^O-S4%v759{mf@dXQf8(vRA+6 zHr(?^pVop9Mk{sd0@bSvJ49Kd74bXjfCb>w8m{ck%iAgKrr()9cG3iWVQ!fB`0sKEn zz{?>}&osYF`Hoss4tPwqN=#g`eR7O2A5qbF^th|Y5^|9gSwf|vl7P3?qgB9rKH&Mq z$ow&Bp-1LPLQ)3l8bdkRbII0}Lz0QvHk>rUF9(u*M6EU$o0i_yYJ+)5T5YgGQAtQz znMDs$b(N8QEOPu;jY%O znunw{tX3#037;z+>0974(3G2i7G1Ozlo>llR5Qqy@mf0~Kh$v1xciZy8qK|%{XpDo zW-K1#sc{YHr`>7fE#s_vLTJ6hMT7E9YY?nP)h;%wHf3SkMxc@JT}PeZ zz$Jd&C?cyTNv2lGU~dz%4N2NZ+i)X9a@9`!k8Q=*sG9DmSkwwh4x&~_@{qJbQlY4P zNYbZBx_7@YoO2ELLQ{-x!~BLYIqo5zxH zKh>&Tjr5;)q<_j_ZHF)=nVPo70h6@VCXi@B9wxbnikRdfDq@n0q=-qSqLP^Oj7Wbq zlgNkmBNK~f4N9qj{!`0rP8rN}a)cRCHP$%bownM6e4L&xe3-v%qEQ3K3Rz5A}S)1hp321 zE|MZ5m5RzoB>h5a7>o!VlR3#UFu1ejL?qVNHAMJY_wF!=C+4RSpTrH>g6qLQTX?Em ziz$bL-=-Vf1+6KEBong*NpYVXNb(W2dWDHzayfUkdW9a643di9UlNj@!L_(jBdJm? zUKBh}mTEC&RSPs-%An&6QhAABtthW4G27^=ee%%LL)40%4x(1{^pLcoXQ8Nk^wck; z8gyF*U4_pph0mPYgJ~w=Z#wiOEd)Nm2RO{(^hUY}G%QUc9xyuvN$BjAg*(DL?_!RiCxlhO}UGKpy3obIn%ZsE1; z7X0XeVp*CC5$_={tD;JHe6wQO{2=!Q!G^ayilqlNPlpxT$1g}Od_ELlQbh~T2C5%E zd8?gxn_-~bvKN=8y@v(S>!x|b}|%16{1 zD`V5ryINyq9+K8rS)r&THVm+{DmL&OJ%tU_LsL|ZUIQ5YZU6~XFKvXkk)m{=Dey6Z zcm34r3Vw;Oi`qk-Gv&W~hyv{b9d6f&X$SR97}78OJ@xg1RY#rAV6L~ln0R{TpQef0 z8V8-%R-4+T1$jE}A}Z>4+^b%@M8FMV!C!15TGdr5NPrB`QPgN=f_~Z_WK2u@8Q)ts{EY646iC* zs$FWRb)G7}kfQwB10Y}^llaO#0L=K8*Z8)Z#OL%oW((;g&ZH@+70`v@f&CStJw9ZJRPe%RX&4y+>W>>DV5h62fJQkHuco@VMUsW=OQYq zyoacG$h%02c73U+q+Q=Bm{jfhr*&Q`uO4<5rz7%+~p9h-hq{p+aFZOr87Ra^qNE))Jf&H~@R_WV(Oel*ZYZ8s^jN%RofjrzC| zj>K!w<|2gfi<2+GeGoMeM~C=k7`&k)hs3Lgv_c2J4cs_l()_B2yS>U*;}@Z2eL{&q z#d$(UwH7V}Ie0{!BMUiX+d+lHG6gn*iCW`ebV$sm(P8^!867U7qS4_YDk6uAq-b=M zib@(CzRAUA;>ZjQ=PniE^s1%BDXlI*T*cHalc#JNVf8ysXD;yzdaKfd7~3`*Sq)=H z0{We#)dXRBH1nLnTy6CvRsG(w4D<CjaA}Q)^si>sh`sVOYRc~J-E9akw&!OAt0jX-c zWlif7%Ce?Qb?t#QT`DR|Z7+D=Ly{>n?cX@9MGec_r{_ng;~Lv{;Ox?`o*I6#BMZ2ASZ&(qKQ188s& z75xGaQPD7Pkre%cQc+20m|=@N#gm-^B^rMy5QhNB#AFqWQ;U7C0SN{lb9Z zW!NvAA57zgPs$t?5m@XxSRyx27YZMRnsDkxtu`DY1qJC4UHXxEy%470u8iY7=>JIJ z_lKTsptkT7GEZJJXe3C}Oy%B2~rcDpTc#x^cOom|LToxs@RHxyJdz;J9bP zE!%3)aL)~~J$vg~QeM8~u)})#45UtBt#ME_iP=;&+b2uaTtr1x^AHtP%|%jFwNg<@ zRpYUIy4LgsbWKA{b}DICg(f^*I!d(6L20Fe3;ho%+2r~)QTz8L+8SeyaxQy*tn1J| z>b9VUQ}xYHBZ+Pq9ql6Y^0z4RIH9?xtjIYuuofD7N|Ck3L6Ie9Q;}_-EJbz^wdR{0 z?kXy>$4&7-Dg<6CDyhg56%uE3W>Q;y+NzdA$7 z+BRz6^v6=h4=1l_IV39CK`Bks8izxz)Z}{L2)c;6dh7J{RP8j3(S$#w$G+D*6SiF>amBYcw)LpS`)p6A63#gT__TI0pqmQC`+O%3}U15 zx6wRHJv#J%q3c(mK*@UDQ`^gx*L%&m474{K2)rmf6qHg_z=ntn6~+n~X?pJ;+kCLDDW+n*B@}X>)zGIXz!v?jB#i>i< zO@kUNp0b;o!_?B_n>x|8rXoQ)=Ub@0vRGC(wG>pckih>yzjPpY!X!9xAQ+o0?pH=b z0~MHh00CmQO#U?ayv+Gak`qnP7CEsQZ8)ODjd zP$fj04tf>O`fkmIJ7(BWW8Bi}PcPWXE(3swFy}poI#tFa@#LB@`qw{if4ckr{mrLO zza;C8$0m!l#UqkD!C6xkH+_N^YTLsTyiin@;y!+YFEB7KLv5cpZ%;hYJ2p9VtD#Ag zEw#o$Z6#*&ytRF@&RZ8z@x1jA70+82N%6cb6_r%mtwitXAGoIxnR|l&apIA=vB{xY zY0gCIG}jsjSdf@aSg?JvV8KOHgar>#Yc9*-{jL6Z=}jeJVIysP`lwJENIUV=*x2L{ zxAcfq#obIo3%0i5+G>r%d0T2*%DY@MVJ@Ps-V8rey*&*h z{0ZOu1OAND<^JiTso>eVXd4zs^pOQR0o){R!S}83#eBi>kh>F&V zhp31uE|Q|PQYtEGttfN1oLvrCZlH`brDm%o3ydH0VWZ*RYU{~z-*{_Xz_@8A8;_wS9)(RDXWd{4JV(HalEN6fa~ zYo9#5_Yk$}y@RM#?>!`~x%xs;Nxg@^e$Z?Up6L;)I;{bEsOdA!3Vfg6gC^th_|FW- zf@lX-9o0Ud1e8)kvqSG_lR!-w8j9NPCnhfG%e0plO)n|n7So;B;4ts0C7&SPahDSh z3q<*54_6(Ao*3(l%z|3~X2_yR;M51~MnI|y0L4OZ{f|`thh^qP+MPq7W1d*@RM#2@ z?UtBL?Y4cgwA)40YCk*N)oMR`NLuaZLQzTW=1hB&L!Hx(V{QRRD2`FD1^Op&m2! zpIy)dA@uIy`3+z+y8->2cdEe|4&A(8`W?0a56TYE2?!A$v5N1*E}9+!7+zyow|b}S z=>Z`*3xkPx7g{&m_j=dfM|Td*jsl~!aFi+}bBkxjjU!%IzR(Rc;SSt8y2L zN-H<#;agbjucq8;iPWKCcm=A0i(UbxZ$Jl!Jt~aL5E{9nAjV|VHwP=M!)*BDX^UoB zVcnv_y6FH8p|UtvnEL!t=OeBMCVZmRp;r?pmf=P$*v4EXd*3 zg)yDh(;62nNCdiVpG+)p5Ou_Ya#2StaFBGwf-+G_ENGi?0SxrifAeI#-ui}B4}A5& zyMDaK`vDs?pqK7WOdzz$gH2y#rsojs7y_I;$+gBodnIP`B)5ICwAV#c)Lsu!QF~n^ zMeQvWmDFBz*3}8$c!bXlB3{>(&S29mQ<6-lCFL3_DO(C^yX5Gnhal5V2SKKr9&$`G z3k4B`b?xCu2v)ASUcSCrQqcexkM*bpsbZSkxVk%X#shPGQ&k1%B6^~92QSs<> zkra>4Qc+12oh@zkJiGU`RP>Df*q74i941*9Nv`Px+!!LSH4YjrF zuB{#tT5-2(wzQB@qI=Swrr31Ao=7DtwoIo7nt2mGnrQK0@nYF&!%RDG;zxmW&1}2S zGg!xjS}!3A|4-iuOn((hwp%2hOLT}k;$bBXO=t>lkwCTrR@%2459F}js_A_Ml%7Zk@l&)q&ySxYg&u%W>kM5^~CjSm3B)PXOO_=u}_`6T2ijJ zlCq_?wo8uIdI&O|br574>mkSVwNOw}TLTZ=iygO`Y$4JX*;o!ZJ@1@)B3Y3c=9s*f z0_Z%1h(*4IW0)hco5|>`Nn99JR!8)CAG;xg$u(m}B+O(-o|5Tm(P~}k%3vllv<#Wda6vd$jbFsS`2aA)`3%H1TlB>9mNA$4H0aB!@0_v% zC^nHlfPJo!JJ`p#1jvSFhO2|UBGDv%byEZP({&}5bI74<$p%g6Fu&YtIqP=}ZCT&i z;ZELF{Q79L)@5QEhKD)N)2_i9rJ|DREXx^#`&T9`jrs9Qyk_sL$Qok76M2oOiy9p}m?Fm}xl}AEKs5qxCL$#z;R5j>4mQD$-&^vyr)p^RPj0g_Pk-br8&TW<` z_NBJza)oDB^2lS5um856KAz^>37pHIk#+bcT)7#wQ`a5y$>>JqHxN?blTaxLZnFmQ z#XFYep!ZJ&hVDeHEw%&%h~Vm`*dCD3J;Uo5nj-DaAY|!@s@koSnMe4JUzz=d?>BpW zG>Mpc)$Xd@Z>HTjgslOXNvJo0PQkSfRy+tEe{*i`Fjeg@d^ZewSfBM@&3{h+J^fan z1wS3@Q)0G`@3>FS`RyYrhPXZM%Cy|&rdC6}^rn*Mc+64toL?B8)cwito;jQbY|9Qz z1MF~ViSeqSiQhYC)%wLTZ80$pHjdhfYAY~MhY@F`X2x>VcO2W@(!)DeS(EAoF{gFm z?B;t-fSp1DEM!o{$Xuqo7HEwJIv{2n9kfp#I(Ud$(ZNB~iVhx(jTI>8O;Bp}N>91nyy$WKrR zW&wpxv)Bj_z?ng#nRw4iZU6DZsHP6v;YC_WV3q-_>H#8PRXmx@h)PVULK_G(tl>lu z7x8RDI^gxfi8-`68Nbyf;pD~DdNl5k<0ze@OG0Sz1~qqbO3*6C4q}-qIVPt>RtrWA zL3RG7h?~ef2T?~@C>M2v1qVq- zSSS;fgoRn$+%pYeyqL0`FsJ!tV;5Zp>98V&pfX|BNIbhhuPB=%K zzg9kg;Czv~b}2aQGMJRDf>BA7@QGq*t8J9fK6xnNA!T%+QeU}W1W=lDA8a7;d`q)<6u%UhOV1t##qK?Kzxu~OY;UMW~T$G8*fDO*4 zmw=5|@Lg(c7PVQKK9e4V@9yq@`0HQz_U>Q*y#49!`}a4WKK=6N@4ox|`SYJXcYpf% z*B`!PC|9Fp@8A7MU;H0#|NYC&*yV6Q#mh@t9pc?fs3ewH73od;5-^|&6xpcifY8BUSL-ntq8i?#3oQpk8Lefi>U?o7WvX2cYc#;C zO+tzFu#%1!6|!loZ79(`c~IgZYK0O9Q7e>qNLrz!P*f61m|5c-1EC;})+!LPBlld2 za^#+?1crDg7Zr6^AX&TDyd03wIS1xCzX)1y!IYaDdN=R-0aum!D+SPJ~Xt0=~SPkxqw`I+meA_NWrIRH0V$5U=%O6UU9Urv&K6rlfz@C zWt@hJ*;rD(Ki*zOg}9XPtE&t@#PBc`jFF9|+f+d6JRF#Os3KrFPZKx6wO1=?S_5DV z(H^&_w!Wxs@1qTWYQ5RXs969p|MX@RlXyozYIR@Xz9b1Pl}BwR-@jBRyKAW zrslpM!mXNOY2+wPc=@#1XQa~&KdCM_d|G_ya5E6d%rkwbELjZ(em5pj!5VIt`_ZsO zeu-9lM`nvo+)P_UE?YJ&qm*UJ$-bZ}nUC7ON^FWghiy7#(808Zw_fV4NX#bs*gje4 z<02}ekB6v;J}#0X`jm=FqR&7vT1B7Vnp>SD`V6;}`{HxZ*F@74HNUA-n_i(g9Syl2 zp%lnaQxuAKANICB(7hk%=`^Ahm=|vKOApRit4~Lq$)TNgO_~{^H4ZoQb*9-<=7xJZgPQz|NnGh!`PoH=crk=21MXMIsQ=&i{CjsIj-uJLL*rCKv$U=phf zi{)!82kVU=z~01q*)IYaY%@<|CWo~;G#Lf^tZ@JtZM6w9T96ldbrBUo#zRyD85cTqchiEH~XfA>76n zpK|E2OP4l+w8jCSBxVzzY@aM6$VF7dCl65(pIjtGd@2={#HSkSK^eaVpS;SH3<=a( zMR6q{N4fWjDPpvHBaVYxM36}_nHX=YaiqtoyL}FIcVW0pD(kH^9?*uEZD`XzdC=w| zYK1ljQ7g20NLrz-P*jCBO+b8Z6dQwtSg`e!BtVSyG55!$@o&x49D7@;KRbi~c2!(k z9pZ`K6Y5rbHO0dTqwCr=>Q+~y=1&wV^cmFS&?pxp4B}j~_S0kp?)V#*_;o|}g*D}9 zXJWR{F7A_qc0QsE?Oa3|+WAN_v?~^sM7tU_zj8zFY(nxGoM+Sp=Qs&s^2LQNB}7Hr zDgk2blL=xp6a{&o>PcyPr9>S;tX$L)#2h3YL99$v1+i+feKXPFY;Y}yfIW~HP2d{S z%QX0?6xU4578u2Sa&XN@RCGo4=1T7>x}q+UqAOY|Dv4_~)p+H`*?HtKbBNwU&-6-Z z@YC*Pt2G`7hL~-v&^~zx<{@fDFb7d9f_X?<5v)*DMX+j_eY0hD9-x-PbDx-_nF2Mf zaR4=m*#tG)CkxbEL`6{Z5EVhqMN$N{Qc+1ztK^L9Hp?!a`7vbC>^0I?khEdZO&S(l z?vqMP0{qw~6Z{-R9l@_$)Dip~Bpt!8OjHHGYSDeGMR)mlm{SfA#$*Du)fxvpl$cFC zw0*Mh&_z_lLl03A4_zchJS-KJ#KVzVL&n%MSWYJ)q;u+6I%eDlF(Xt=2m4bqf5Qw# zfw6a-mJ_qb^ku~KMuYd-MdWmxaSHh2AUhbPi)dUBKo>nTjheF2Qk&IWC;<#Tm3;eY zzTeODazkb1fgxNpl7eB%4MCCU?`$vqjW4qIOSq?+Q1ykn4Us6~7lYST1*z}Tc+ZNP zSkfpCD+E{FFx7kgoyp}deBHGD{m8&Ca#oZnssRlAHj&OK$>AhcQ)jk7D)a&7WWvt) zV+mnouu{pngSrNBm7C;)WVR+ng(A7~0V0X|NC>r5O+q%|6Ydx*#-cz^b=1#AAl;3sq>Z6cPerY6o$YH124XC*&o*J6=`e+4Sng8ffy|* z*H=l|I(coE9BuUwWV-4g$TZbMj_GNkprn>|RG(kvf!oij?~v;0po9;}Vc1O!)y448 zp}W&*8mrk9V&&ka^8qI(t$n8UzMt>=TRyq@z>f_gn`nv6@6@$OLo?XadMXmp0xhW; zD(h#sF^^rsB<_bilbD7hC#sqYlLTk!TRoiOI@U;aA-B{a&>yC;=neFRxS5ad< zZVIQc8*YkkDro@^_@h^80mtHM`b*IVO#NS|d?dydDZq9IIXDjmsQ|!Ziz%tkasw;R007?TAXe`^^pSA6%?_mfQve1+ zBUQ%@R)ieC7QzDAmG}a;1`#t&_@j$vLS!1g(}}@g1#}V7Z*t5-bvwJgHvC5_}`|dxPZSm_gW? z8EcZzFD)t8FG<sb3@9nlrNmPc9W`6DYim%M99% zo{g%f;>(eDpp=2{@#|)GAJdk_ z5I@IllVRoRTtRu*8>Q-fa}cjp9yaE%Zl*3xl+~JY+n5m&iJB+dXZulKSvM}C%szIx zD?538B$M!7#{606&C`Mi+ z_}D^4gI5LMxWQH*J$=sep27Tce?rClI(A&+#K(z;3TcLS-hzlPx)kI zOd!4>zlW&OF%p0)FB|oRZldg>X3iwgDIXmeBc70IF&<6FWOQZE43oe|@Z3VrQH{LG z-(aXw)7q+>W$vudGpNv$Tc_Ls@X+-jl3z^!jO6wy%F|l1|27l_eom`dn)5uTYJDG+E}_Lf zd>bgXC~Qy;Hb7l89C@PD6Q-=`EG#_AWtr{>DXBj|n$<90={Nt>%pzT1O}{fJJuTyR zlLorhIOw;;Z0fh|lXa@Qh>H5{Au8&(i=?RErJ|Dhy^ssMM)mGQ5z^`VoMO@z=AGPV zPGT&cPEY{xj_Ye_^pwFBYR8#htn_T7LzUJzXtcy^YP9W>rO_^;qDFg&iW==ADQa}7 zsH8??95OHFDo$*wzTrn{3LwMaF_}4?P(vo&4}1E^FrSd2JoJj8KTAvB7|w28dERkW z#FeLe11`%;%qP^8<`5`INBLSccxmrDc79vT$lyPbR!CRWXpIAANX#Z?*gjd9;Ua3a z0vzsYwE{dOtyVyxs5EA%r^}M05H|ARrAmW_Bw-PEBmOzA^Z}<{6NfQt`H$;#)ztwj z%rG@&3Gn$We4d0mfqNJ4<$y-wi0WfJSFxJwJNcL zs8xwQB&|wZC@MpVnFn_PO8h#W_v@%@29t|&zGMp9);OrEw%SxzEyz<>7g14NJw!!y zb&(X+wNzA6U6)0kw_-_K6>TSfee%vz4^iuR z>L6-8Pdy~9=V_s+q=HgpBS-oSHS|*a;@5$I43?Q?S5qc+&3Pv*hX?^4iTIViQYtC~ z0&33t#B<)i{Qc9-yMO$6d;9(S!~gyI>;L}r>2E*Z{`~9vcmMPK`w#s{JVI0)!u)vW zP!rUXnQj&YFRbB({()1jI3R7B)%ZrKx``e;r11hxar81_4IKDD3Xft-z8?tu^AZuo zR^P2-0J7<}(<64U>EiSsXvy)1Ry>A48ZZzKASu09Xn>y2x{wLPIi|4&K>^|gY&eUQ zz@}Q;ax-Ets5dp=EqutvwkO;2RTN0bA??+ie_?w4!?Ag#Q6n}Dy9`dl5%mghDg*Uu z&i`a`{@eHl&7k5NO4fXLcmKotcRvF9KivNNmz#0QVKOSap0et+#>26zoQGt`h!x)| z=i&Zkh>R~5s`)mS;wGZCv?;5I_9&v|ur$RkNFkcmI3QXnkwLc6%F=WZ6+=}XqN1Pb zA}NNdN=2nDw#xaqY|h6fX7)@Qs+jpGW@a&8VOOLuvvOXtVtXD$oTC+3IWMPQp7L!0 z`fU)ap}Jpx`0gat!Bq~=SnQgV&80OCerhR^=YgN zlme*A`O0$&3yE50nN`kLqG!Q%a=x}*${H7Y3IcO@>0(!K?N(}9^V)SmG#jXTzhVZ7t-x*q@B@t28SHg?hf({P51m9=yI_+b!_ z%}JP^Jkd1%`WL>v``15jf4ckr{mrLOzx?^T?>>M2{HM>|pPn??a%lRMtyV}3`w{}v zN4XgSt8BHm?@RSMb#ji}j-|0iUrxxRMyDr$OgYs9m1pL_ep?HOJS45oWTB{}B~^Rt zFlvN;ceMNKrdxFf&;ZJ?qc4WF3FKwsXdT>oCeV&Mnqy7vyGP?q8qTS2{IXATHXFupHLAxx5 zf8}J@C5%7pr=56&gVf0i7cdF3!UOwfwpRZ2X1 z5dSF^m9&fMtg4frRka`!eCU{=v!hp5==FV^7}cd-UDJMKzD}zbh-~%ynFY)Z zqa&BPay80c@iX-IXOb9e`O70?d&oT!BBR?DeOPG=c4(ETq&A_W`w`vxcf`5X$-AV> z){;Xtue>D>w$U;TH?_;wIn2|0ov4x{Z)pZ>$ex`)8s)IQD_5zI7W5!w?IEdhm56um zrtyk(32!(K-7%jxUrLB6hxA=}NR@{~=IvY|=XD}R zp5SsR5u+TAb>$va?$P;T%ZoKdcZ8FR2>@krrYqm5@{P_3Pb%N&YrfH?#B*}E*AotL zs-jkF94cxhW-~Ty`)tRC*O?10qGCm@hp3ffO zROc=*SZNBRyc*N)M&8H3mMX>%RG73wx9dBIHiV+MG7p+YLfjkt8~&3^JBNE{I5Ric zA{p9EV7oB%x^k2JJd-^J4a|doGmNlkMs9UC?=@SGZw%z)R>ia-1{S{#%(ZKFjOBxT zGxGMv!_42+iinwdVdjGg%*LDhgNEiIn0MUSg$@Jvb}xLo?8uvA-X9+d#333O>9_d2 zoH^M(tQ_EQTIJWMcsFi6tm@}qLR9g?i@m+C$VF~BixW( zhZgj0dpk%y#zQY{3%dnkTF^s}KJd_ws>p1cHa@%H!Pc`|p=I7L()|`J;m_RN?9~uj zcmmyzPgUU7@UO19-Ge#$+<_=C3|s;jyM~{psR&mXe0`H4Z2tF`Fo1`(&Yni>S5dhQnP&l<>HzV@|v9rjjTza&T4);esuM9Cq(GraRqh zjfd_dW?T2QPoD03h+1{uLDZ`I9+IMkpijKyqe|-jz&Pis`;X}Ugw=!>p`jg|;{8q@ z!%V+bc}tl7{2vpz$A(U&SW>MVpP@xLF#aQ*A5VsP*f9M6c%qBW&-u>rzhg>vcfdjb ze=!nx87B*mf$L#ZSXLcSndgmZwx8z1(y#@#807>q)hH|&UeU|Q;pC3^a7p_?ex4S| zf221e-@ERv#SPM5_%bW!LDj{7{8#gz(|=EKP`YL@Ekc)ogt<(vVZ5jGzycl$FD||cgQ@6{Fy=Rdc>1mfbaeLM{=%~bO>Zt9LrK2vQqK(K*lNtr8N zM6`xLMv!0I9|#?_v~OtfUil~KYr;CbeC7H0tsaprhgi+Xxt;k>? zhR{ME6LJvbwTM5_|2zIB@|bACPvvlSs3LaDq@s}sEAQ6k|IWxib`Ts zj8;?-c~cO%*ceQk!G9!G)FzQfYaEbAVm6V-_Q^sX7f}&;JVZt0agh{}r&LrDd14Hv zBF~8-PmL`7F0#~Sa5Fta!>?c{J*tL@|=X|8f|Au1w-i=>DUrJ|Au zaW)a4D*&K#h}5(hOwK@ir=+!^H4a!JF`HOo`>;YGBWe%fz7BU(73#{@NA)qK>Si2n z?5>MNt^Sh3U9J9-hoseCDioE(62C~z6)5}VS{oTWQj{*8Z_*kEgpim`wYGh-5W+=N zLKJt;najlhUg+*XrI=z>clbIw#nzmF_5^0#1 z!oU-zozNzNP7JiFpj?Ve=)ysBf+K2x&Z$nEtimqM1ATbbbqo}*%zj@2L9w_;0cC>6@6iZ7j z3LUVa_HYxb;+}VuWiiD_g)B6xK#0CigSt=f(-gpP)3M71+0TZ5sd8+fDTUfq44MT) zVVSn=cT9qz&jq(f9R|%eY_(R=aU#%f!d?eIwVIw9G_~mHV$n6cnXsdkh2AvxrSh0R zcCS!B4}FNNTlREnQ1y*fm9ZnGXKb$Pfe%Wbx-4uJrE%?g-iiJH%$ud*hn90a><2q} z8{IPRblfirLh|`?BUJa$jYHol@IfLUhZXo>$V(bEZ`yK)z@X2zr7*4?_-w7u2Y+Xk zeJCs%tz=&F;rURgo^Koalc*4GSL=5wUnWK4|xFe z7M!HfPGB|HuM1-zwz{BeiD0x-vV*G79`Nj&U|mZF;2)Ug|A7iH2k8@Nq|QWF2U;1F zWIm*H`GM9rfR@B;YNG9v1zIkmB4~MtilF5pDS}q1s3d4D7!wtR<*@W=}7# zPThEx=~gz|jP+hIzVA#05XDj{YYm9$SDDtU-nQOQBnib@`mR#Yk!l}4pus;Km|PiKadc{Dh1 zv{VW0t3np{ujFGHA~2OtXrV zo2WGo*d{TX*k=1=VVjGnh;1ICBDT3mir7{vDv52q8kC|E)=-`32eyC(YcLI@VmuL{ zAzncfp$@Zy>mi_hSQpmvbRsMh_A(2*Ju`iAm-rSGJ^Ev0OC3lRbO{y`>vcx5xPwMd zl#I@*BV9@PVOo>&fUyBc0#s0rrYjLNg|@g6MUB+AbRkql&qp;w-O&t6AvJ8H1*btF zBnxeEZ`}0sXlM(dQm99vEdn0|u1MD^q{JV*G_Zp!Hv+h@E%#}mEk)kAZ-um&ii~Hd zsE(4jy0ZEzLR%%_s*pi?=9ix&J=+=&9Ac|&9AZJ9jitLT7PaD#gQyjUJS43+R46Km zLmbNLCw5T7WI`yEqY_%BC56=LAajA9N&*6XC$sQ1zz~H+SBcgD3_B?=fp`Mz7G-T| zA4`Or{>8+ak%1t2LTY-(wWB4O&}H1s8sh`nDR2&oy>#F_q6-b#6on=@JOX}(EB|gn2~5!6P7L zVz#g(?!yXBsT8+}J1Q1su;g-A21`DY43>&TC1EM@6j9VOj_Ov^uGqBm&lMB_Rt~Yc zZIiL8pf%-ol!@6!8SRq?Sgb4-wE~uds1>k0B&~o|C@Kk9OmyHttaj9sc9g#=pMBa- z3it9>RtAH+ouE`CtSnno4q7H=3u)p$IiTeuDms7q07~yFI)5&bqVrcODhXPhe6<>c zatT6RU52p8lFA^Bli468Ev07u$ zZlHstqZ?QzDhX|ELqexoTuQG1U{CQIn zvk7jtPZqejh>GCmAu58Ki=+r{rJ|DHHcem~{PqJgR~1Wun?UWGU6-l9-%o9KAmOi> z(JH#rAZus{OoN6JLG~X`x1NRHW>@oMJS-e+jWX3yN2l4XoLG>;Sqqs$LpmiTq2N*DV#6RYpT67DtWil1d~C=)%LD99MP^0E;#DWThonZN~wx`(u> zy2DMWWT7EpF0IX?(`Y&R{X!-zjYTinq>NM{{{!5YTuhBCK;88vc!g z4zm-k7EifqCdCL~A}vM!ROV4&!v=Z_`e`^Lya=g;+R6K1Z26g;sGJ<81@=7DQ?5*| zW9&AhG>C2p8$=`VKNl%ot{woyj=}A!$XKLQ!dy zQOxQ(QKko50ft$$QRY$u5J82z)WUp4DF0p29wJ7lTX!UdGtN zk^n{~tT{K6#C|uYVUlz?%x*obDU(EN9HKg#bH6{x>M>!Y9IZZ`W0b<{W$NHr_aC@YTxIL8VGuN6bF{{#G z@b3M7rng7JL3t6k=T!luYi?EIrjmHIRcYxiFkryY-@vXzhwF!Nq)!<<;)CsIMZ)#t zho0ZhZ1XGBy+GEF)gLSEH>vD~?kEK1@LYPt%MokZTNu&L+M4wEqv~tG zwZysUGRWAJ4p!%8+pf_klyJGu&$$^XBfUx_c{|tU`LLp2)(OE%24$MoR(Nw?rMb<4@qmxq)=4S$C<2z=t?59crIcH($|bmYWOVJ zOxOZ@;;|I)LKeYOnd$Ckjf$|!FcxB$H|p zoRB${!<(KIFi)6MTH|0&NzA7H**;n3l#8fnPI-um=9G)12vwz`l2DaQbax#UQ?eo` z)~D4*Pdc}!xO<}CY6ozG3;-mgv8N) zQRZlyPV*ws>Iz)0B%LmY=RDJWDh*sNt+};T0=U>G6Sy2i9f7M{)DgHGBprdPOjH`U z=-aa8%r)aJ&C!?uK+a707jjyP$q*vxtvwmx5?CtWlDK*Lt~kk8wi26=v>`FGSL-8s z+0)9J#`cCmw1e07z>bET>Yx zL(vws!y?+^BI>GLv=ji5t+$ApY#+=W5rO5QktJR|G`hReC-D)~>3;8_i7zV?Yk@E< z{2GBQbJ2u2vk9n(^X%09i6Kr7FL|Q%XA*I&J*aGvqUr~2wQ2HbL7vIuB5Fk(hr3#X zLLQRVpirTxw8lQEhqJu(jm%o2jse^u3Cz2A&p(f9yZc~t=H4a9M#B4%}?UUz4 zd5BuQCtFcx?qC1B{ps%e_cxzD{qpDU zzWe<7^PfIWE6^ zcXdQ12T4a%Dif7Pr9=hkRk=~G3M$X{oKCB%w9nxy%SKP3i`F=xOQ}2XAQ|o=>Z(1b z6uMk=GQ7gcb7H3fvMsmDw--DqM{?@B5B2z!jCG6Ey+st z3k&jIaw+I@qR1yytlnqQi|2HG!^9d7m_p1pOlhAynDP*{!jyxk6{b8StuR$6svM?j z6nQg>Tw(7Iy_eOXIi$~qK>fVAn6EuWulU> zm+H}R;bH1aMy=<^!Szs_PElB&!>5)1{L=TxekD&MeK~wxSm3JS z)nnaYPYbVx9CEcrx1{h&YaH;ZbV|$vymAp0%`Fd6D=WZZV9>E8TA`>UUV(R;RrD9z zSNhaCbv)lV(y#DzjH4lkUM*d#V6)kOQBeD|9r7is=K@>Nw<{Hu2Aev)t4{Cw{q(M1 z{{HFa-9LW3z5V|E;s1X9^?!f*^tYdHfByCTJ4(YoEOfGMHG7DT_%sRSUqig`*E{}B z>s%JZKX?3vehPYxycz#L(65C7X6rvcei&%2?|qQIb`)Z?#N;IT0}yR zaZamSS}H1ugvmm@%SFOh<&r)J{9d98Zxj4RS`vHV)rS!LkhBE+a=7#r{H_!H5?uO= zjmf<#^gTb|_Ci%T*N1^Q1pswQU7^?cAXMlf>6KjJQ~|)nV&L03!p{f97i#db35d%j zdc-+Z3u<4G%$;a@lNObhZzl%A=w1?8inZHtY10ME`L2mtkBL)O5#@1H$3$)6O(i|z zWYxkYdBm5@DtV5}{SqY$o9H@g#)ngg@IycQ`R^qzcTTZIMb|xpx&GqJI+yKkTBVmrx*T&VVCo!6hv}9_$W8Q-&}W?p9IsYs>B!AA8| z^osBC>t=7$HdBBXyYzWTiq>lB`zwde3oCZ6Sjiw{%5D0ly=D0Ebl>(2A7%7ARX7d* zMTHH2|E+i5^d}Yv>^hoGsoI_k>pJ**tb99G)3bc;THX_jC_l;scxIvF zm{Z6PP92s<(kWhlK59W@Ne+IE1v$bb=xKO z>=^S3h|+z(ZR%}#D%@oxZX|BHh&tkFV$_wr`y8j+3q?5X^ptK|PAvoaSAgf$J5$%?$d zT=kSwe51KbNd|cxmzCo->!aMvRck?ti@q|*3q>W}=44l+3roXXa`TPn@);!NemE*mxdg&IHcQ6>(gFi#U z6p^-6RMN!dfUPsfX{6EbLpw6EwgHMYtajhgyKd0;G0;|{Z+2bSP3za8?dUI~<{P_C z?KTeMLLUx|x8)xLE#jDN%hS{^yu_ce-GxR1MqLkW-`Y<%`;ixW`qGTyK0Mzb)vxdc zW{z*dG#I`Q zH0=R9_O$B(HSCLLXNuEe02t6@JnTV|ZrLvrdcJS_dDnLBfjyAKpJCp&%d`*r)AWbX zcKa~SyRMn{Jy4_TFfDA;_QEIn0`<#246N=IX$kDr_F=~?#?ba$kgSJlK{WSDZy^wn zEAMdMA#&th@%?5WXr;xiHLL{~?G1pCfMpAO1|$ugbpW0D@ovXW0E~QNaPC)l%BS1x z26mfw^WZ>r&!!Uv*j8yJnixxnv9xIgf2y1}j=KiC5_O(c6;y;(kLWb-@Km8Xc` zPS>(a82Io9jvH>H8RkRKYZD^*;*BGWcirqJb$se}ORM(HLD!P*AX8RtQZpuVRs(As zfKOsJfzS5I0zMZ}E0^Bkt|IVx+|-dvUwBhV;G0lw`lMIj`wjSb!UdTCT(|G~9XJv| zwy+n}0@z^7aF1pSnd#CHyczO5GuI#`behy?0piU1K&P+RD1+QE0Vg3S6 zO=kpr_5htK@Z}T{wM$3>pVl}4pTukepY4+cd@iCQ@Og-ez~>?ciK6`*p75H+hgxV#|Qqme1;7hQSY@bZva}ad|zH(7V;B%041ims+Y2a)6H6kca zNKDI{Xy*sJJe?jNiB{hXJ<>sBD@&zK%JgIH4{63m)Js3rSuQKHrv?i%o-P z)OR*6V&2K4<;U^)_9Jdmk0;6u#DI(0;UES4!+;waX8Br*(cwvR?Ps}BxW~9o+|zY9 zxtN}cIGU3?_cA}_<#$-^17@OrC1bzi<0WW-r;powP{a~zQqc&0jt`6BHjUz$EiNz- z$hn`32 zcacfN$)(objeb|!s=<5LZ+^m@p4&smYK;RLO3bDiX!~TLp^K>1|8=;l)&KR7wB|<&MJ3U2B8an$ zq?;|Sblqrp`kwDeqoE$9GeE;Rr$i`Zj6~BK2Q-wJO*FK9ve3{)R767$Q4tMYBtZ{;5>g#01+L_lEHB;nN)>Tp5k(|=NFoDUTDfP;Crst$jG~A3z@4ZQ zJ?E7AVA>|5hg#zSl!(~|O6`*elpdm1pmY$m0;Pwf6(|cuC4sUhV_VI}WTyB`A@Zcn zOg(z%U}omj-3(*85?yN?&{JYI(bM+HLQfY_tJCdpSF6+QA!&8G3q>W-GlOk2V@8o} zh4TV!WQ2he8j_~4Ghkd0NL+SA1EEMPhmI4Ec$2<``H?83u`vd0B;uO{xy0OJd{!Xz zgf&eHmQ9Fajl>*{a6?24{s;1~-4<9POIHauiXB$M&FxQj-@m{4^y!yBfA`(z&!7MF zx%<=4zy9zYjL+t~yZayBzx(ljzJLG2?Z1DyndY3*myxloJhp^i#qrYjuDj!JT;dn> zE3I+BK8e}HKHDb?`&>jt?DG&6vClu+GFZ91leNp`$750ZFXY zfA`@4e~-{Vd2;+qyg|b2EpbeiLRXo=NKq4^Aj2_(8fTdoSa6K%rZwIpxtd;-7w{0@ z7Y+)X7m^1Pz)Nf%`B3$Ue3JqYn;FKQu?)!>D9q1|iX6BAq9hwc;){;3oMPRQd|;6& zx$0gjd9h;YKfeV_vx-}Wv==_G#sNzuW)n+opDZkO5w+Tp4tKTMksgv(JF-wz5=#f7 zURz!`fP^X6iDir>*Bme%!9a41dsxOTRADlj2YA~QaI~PUqIlv>E9;OQZ0 z1&9NYok!NR*gO zNVI*jAkjrsghUTf5fWV_MMx|am4w8MVwmfTOA4=RJxq2X;3?O`%sKTi6JeS(_PN9* zwN(Q9*e4VF97G+luUym-`y3=4v9C;&2linRDlSQlvc)A;rM6$7t;js1oVHgP+(;$i zv*L{;WvHA*fEdauKvqax1aYj+-vWsQ5f?Fsr`HN3R`C0#D(I62znq$waY-knwZ_5l zlbB8LvwgC_&qY)OKMzq6{9GhO@GBLS20sqG8b}1*zr9by=_BMxd(G!U8qX=A=^#s_ zEJv+z08fe81W(&13p`y!Mey_x6~WU*QUuRZQAzO3sHDC=uer9*`6k2hl#8jCoPwEd zQBmx65=CoVurJj&O#5VFpM$6)_LYk|VxNPgBleYv^1!|;^qMR9T@Lu=6v3#jI|+WQ z@c=)>Y#V;sClCBQM6KZGAZi6a4@oQd6^crOU!s#lrQe)!cg2(Tn$M*1#FA43(}``C zv>a*9p+%yj8AY7n_?@xF`3qmx9^*kr-~afp=0B(Zp5DKMll}pUI`rJ(hOTvqfht;% z37#IJj+SHjT^%h)2T4cEu}oAkcvkw2+U1^9!`TXn<@B2+r!;12(}6^-aezdL*|aBZ zpDcUQMO1`D4^a^kT_i{fs0fK3q9P=^NQ#hHDk=$y84Y=AZsoyff-`M6LBY^(T^?K71-kS^QEQD0Rwmp;+b0t%9Yh_mvRu>=D;*>qv9e5*2UgZx%)>b@6)b6NQ8@SI zq`@+$)TO6rD;0j!8V|5U%(h{vee%H4L(~eE4x(1D^pLcIWud4fSf(17)!fZ;y~?cQowOm9LLt3Z9=b zkT4r|bUxJ>Z#qY*A>T+VzI*yeF=3mhpPr=+f9NQs(PU$LyNAlcyfFne>HJ570ZsAH z_n!4T4f^dEN*=!$ScY6i)G?Za-m2s6$SmM-3HP)%wIRT?q_*)JaHFQN=o!zU+Sg~? z;TSrv;f}xA&_;cyXEgn&4?NB4&P&(Hz~kEmR!_}s zP-YpQ#`>z!XQQX}WY2gRT_?u>ag113Hch)9_5*D_xN;CM_7B*n^_yB|4h!I}X^u4f zP;1N`hsQ+6;o(42c1^BFi27WP(}A`fLESFZ7i6YmJGaA?c5bLE698#m%#Y~WsV6aq ziW+jVj()*CQ}4%ax}~v*dUJx=njxr(IvsDUqxZY61LqXSn5I{fKv$P?yA~;74rRM4 z;Z-W(1jJ)?b!eWRIy$`4(pA@iaWkkIjS*?ZjjEvoYLr7a*LH08OnMI*qDmWBU3+W5 zZJMSZ)m&B6G<(KJG_6-#Zw*z|Xik|c@}~B*_|`Y(Wol@volvHD6N)E9u%QKN!OgvZ z3vG{;#$e9?T=X=&<;qEh_*L=7sCa`EC@@e;qorW~?|Yqo%W|{tfD#zCLL2e04PyYD z-;cBB;5K|aaYVn9NtGTXb zWAS#m1GeO+Y16B>h(Pr(M=AqCJNmQmub_5_)_9x&s2WKcN+yKPO%5x$YW-De{X%!r z$E-^p;hS!mQs*&C?m1BH1&$NtFzV7&A&$#Tydsf__@w8rJelMfsP+rb+wPWE* zDpI45`=@_ipaA5EH#Rc~KwceIF%2p?PbY@R@lR&)+L7Ddj6M6!Qd9wnlku8EVyzl< zl^QfHoSRJQnI@f^@}g)Ttn0|f!I7XD5j@+3BY1^~1!KrD1ThkMj@3e)6&R_@EoLnL ze}lM`(#;%#YP*h8hgrz!q6yf`h&f3Qb_QzfasSN4qZhoLU1}#I+tSWVn|h()7l*Kz z^T%vp29&E;vAWOdfLk;k9Sayu#zxi^Rcmx`brVxMI7c+K{3M4rS=I9@)pO=ClUd7nc+?Yh3mO#9b)d$R2bu$k zF5DbWOrhb)=Bj61b|JI4%;LnvYsdb8*T=Df4Y=%Q+BweH!(6v@6+hC{W?@gdGw>^PzG~ZZ3AK4M=4&Loa3R z$3q~bgH)`>)+T|W&;h$0^H*-MX4`Q8`k!Ga@*s0qcU9G{Qq{(hPznd36ivZILX4Wn zq_aZ4CDWA#M*nhdFl(v5=`i3D(H`b1+4HXP^_;2%=Q%d;KPPHKBk1o)nU%mU~ z(lvN|n@-)$GV1t6-vVbbo*a6J-8tysoNoA020?8(g*P3lra4tX15PH~LPiM4^PDyG zLDSEI#w`Oq zNSF}0;oL?v=5{+{w<>zv@z(ek??N^#0hqogFUVmV%%~@{tFcN7@#_8QV_;pJicZ8! zHaO##2xJ8qhid4&E6bGR5QVDdU!~>`np`*^7+8enFSwLFny)JlxuUc-bBnmBj8$fB z&Zx2uN&X+D;J|_ttBkkCzw)z8ry2P>S82R#UjE4ehNsGPz-{EwCdZ)zZb0jX*{+Ac zh#L^0VRQ};|DZuOM1#>j;Z4 zT1yDGSJ-)MZ}B^sCbx-=8ELIC);AA3Sp<*p6qe;(*K?oln!F5H@ z2I6vjk6#!}T98MRb`iC*S{&|bO>%ljT3IcHqSCAulm^v(5mpPylhb3hw3XGuujNT9 z3UJxbwMqy1wu-VKp`z!P@fXD_1XwMKK#pK|$J||A7gFe$gq%*1;-yqOuTB8hNE8Dm zm|b~+BSXQJz$wEI@x#PG=S9{fpL)k5vvXx2tR7V z1SCYGOa?BF(q44qHYfqLejfM5A(RPGUBX3fo6U!W~|J%QbRVi<(h3YMcbPjSy~V&l%V>Jd<-e`3)2HKRWp#98i~&FS;D4g zjxGm)qH(ydiVHx~AjU?b8$ucBtdWC(-~etsPAO3Vv9gpF)9%*#FJ4B>ksh&u5Azz5`$yN4VQP8r=CjQd+Q<|yK9A!J9G zvFM=4p@(p&B@YU%;qG_?Mb*&~vw2Y1K3NBai>RnY9-`tw;UXy>6s4k)2SqR~s@!JK z<7K(cZ6$%!qwEO}OL-i^4TBiMkfrS4Apr&hgd+)G13EE>ibxkw5kV`wAO1DtsBkpl zwSe6GRj)1376~BZb>W_H7Kw?7*QM`}pA?hknA^h3NgZ72QatF=Rq!x zw@#d&4-0Dm-WtcW-lv`Vdt6a6joc{j89EKg2N?sb;sSdHFOl#{3w63fu);W8iOtKh z=)?}dLDZE$oXVEVUHpO;Kj9%^|;x?3;23wZ`L|N6hv)uYK~)c@I(RIqx89J?A|nt>=89 zsN^|60v^iA*YXMKDEQ)&5Kde``9xcpH~?$SV>}kRoy6kgS;vgvtWiZ0`mZbHO?KvS z7Lj46aEL>ivy4}D>bIPQ5Lz%CuuH5UP^Ty{Q=_MdDXN4tR}NFloDXLba>I#G+_0NkU$#5l;9}i#*6xAE?Zm@0S z7OS!g0{{k*l{$$Pi{q?`=(zVh4H!T=!pyu;OCJSijohl6Aqx)?j(9Fob?~+a;?D?G zC6?YemI{W2((TdAYKiyC+=_cs%*6rDxlJem>bb76DP$js(Iiq6?}^Wa{dxcJ7x-X_ zM?gU0mSmk^l<;ZjyM>z-5Ed;j)>p}9;^Xi5TsypM0us6wx&JwY9YxqvW`Wi?m<1BE zX%^T%S!RKYsAv{=h>B)`i==24l!{841&f#}Uj@*pnX2_w?|x)_(+{`*{^e$Fvv@NA zT}p$LO?S{BkEA?+uS|=JsHj06qM`=5NQxR%Dk`Z#93LD+(d*<0<&@+5L@@+s!wm_2 z3IRD=!pvz3z;iOF2%oSn5RaG0p+>IM>I?DAIVGm}#Z#hcWOAJ_YR?v1is`0Ny;rlJ5P0=K08X2i1RrMdT|<2{I|2enTBqB95)2Gw118$=nnAwEczPjYFwf#@9TeCCf*y}Sw0e))?y zf`lx%aniU@@~||N$mM3`bTV8na21N#pLzDVmb2;@ZzJzy2W>cc0Ot4iqx zzN{Q>4n59G#j|mrADq3)c&h@1vxa-*ec^OdzR7H8W0WgGqHZblpPLBB%NSujcMpGw zbC?sky;XdGLj*g4BUQJIFG`JzuDn+@80z_PtKa0>Lt@0R!3I$6ORwf9@`~xAVDW9< z3n>if{M39Z?7*v>?Yw9FV?Js19O3T8&-%?$iQX{II#TU4$0e09AlF;*cai?FD7Y3K z+&Q!)+(c$TMkpv$8;*< zRt~I(0i|9E^4Ex2<1x~?hu!ezbT-M0i@m{c4fWqBl3rATR#9KMkdV97i$S4Svhw(u z`Z`!mHqM_|YrG2`kvOXK$rJrdU4#hvS~~;op3-XNK4DZ>TK>+XKzngoqT5m>!y{N<*Ufe z%pqfOrX}4>t#ODCOU&jWZ2M##!Y-oLoRPy_tvMqPNo&riP*m~|o_Ut#W^xAU!Bqt1 ztQw@C`LER=1=KmW1}UKuvZ__^gjGOWKJ$9%RD$Ni)8^!}>(Hx7t-6S**N~E}1b%UB zIXDUQs&tfY)SRuH`ds_i^O_7O#3P!Ez?^0kS23p*s2(_l$-dfEFY5>;BZ||jgH`cs zjVNTXN}LpA=0GHptE)9>Vi%f-aR|~LoBOjXZm`nDv36a-YI)AG8FZzSJok@(#wHxh z>O`paMe}e=KPK+%R{ee#m zvtC9EXFVU9GQeEnwP{m1@1mCzAMVs4iA1qF?{f?4U@8I?SG~&CWWi~~8(^>#o@RMb z)qKceR*^nPhLSDCpu?Bn4knR)N8KG(mHmb9W{Ldr_fI$P{$WqnfBaYTpVNO&u|Qh` zVU`~6k;KOK8LtJIIbaV_YYx~!)EY|mkhJE23q>W*_+G8ZuD2BuyvLJng%m2Ks~*x% z9MU80xzzoIiXLT4IUa#wU2&w9xgE%f29m!sO*WM_<|=BFa+#v*1`cpt2U=xw2FX{& zB_)W>A6_N<%8`y_dZQ`FJLp`8k;37(Gsy&i8G&brJZ|XbU7@b5w3Ppi`2%d{7BJO+ghZ3^0df9)T%`eqE;>PkQ9%U(vK>sMe65T z%kgVDJ{1Q=R%;IXiMHrzh+&Nf#2{uHVzf^l#CV8WA;v+}3Nap%R){GSm4p~5BNhj) zg}I8~%1gb%!rU&0r!^BANZBA-;{Xs6vk4HkPZmJ9h&sBp<#%;-YaJvV-P$ryNr0dY z5Jt#X^pRRtc;RJ*T@IyeVwz716ST$w6C`F66KtO>OmGnuF~LJr!~_>f5fe&9B{5-A z^0?M5U1{A?mqRFHN_H9W(VMI}*IFk>lOv@V{n8@};mrYaFmaVm7hC_Q}Eq7g4JN?{HVE1MeYeb>Is{C9z>< zj<}BGGi7?JWaM?3p7bF+U8ZN3Ll>LKaiug}YaBFPVm3A1_Q}$87g4M6?QmDC@$DgL zHNFc)B{hAdp7*NgVvxE{nl9Go(8YQ(4k=~T8V6;Sm`!E1eX^9*MO0K)4^dHBT_i(1OGvlMRLreY;F=A6%yI75&rRxpNbhHJ;PK};1VyImYDriI;O>Q*3 zT37y88$iLN^S+w!*o#9bNl5oO%rX52s$Og{GW7{1;#y~@7t#VcA(M52^9-|?@^~g1 zHTTpftH_2fj@0w05tT}9hCt;oq+m3J=bSQLxY0zQuo)>VQt>bGC?rrfWM97(|H5#l z6Gphz96%;R+}ltlDt)wAovHLy^n~ZIy6O||a2}oC6W%JJy39AsC|~=Jt7J^$IL3+Q zFmU(vH@0&83$$(PtnE1!_pSBMK_}I9jTW>Tc*&G9epK&@Cbjxrq-r_r zrmAXJscN)gkg5UuGJ88~E1|{;=!Z%@Y5hy3DLTV>A)QeZC#q@~luZ4Dj3bq`w$du~ z@mC89m1|P&!jokCf ztvh&Iv4x}9Qk3u@SZ|z<_Mj3Sx(L`E>Xy_HxvaXi&!Hz(4ZlhaA5=f~sJTcNH42ft z)Dg>)dzE{m?{TB(gv_DxRQo7!LntFsUg)E~C>o+pCYrZ}sYhcJby1=ITcJTzfezoa zSi$_`esJfAJ<1%GTC5W_(03Wr3O{xS{k$TKX7Z{xsZ3r<#C1$!vT|!&Y#OHet5UYj zAua9IwMe;gC^S{Mu2Q)=b<{^;c&^a`g}JSTF0mFlhx9Ap{NUW9iw^3Sc7+!-iCw{uc8>L|a?|@SmwZ-ApM4Jv5l&*~$B7RI4{+A;P8&|WdWUA^li)@fAAZ(-FAnJ2wBbt;HLq&N-oj`RmsyEoU z=s45)X{j`AK+aD3tBb`xrDqE_q$Z`B zrqSudv?l+054?G0C1lKEOmg9LK`x!=f!VVIyZ4y-#E2a$&Lawl% zrLPwLaHgc4+K+~fNKUdF71&2~JUVv485NMkFbFtX*;PvLUM$^4HEJ8>#CdZXRBm{Y z;Mnu7&FHH2r$Lh_P>{XaOBlnZ@T1Yhy^Np4vRL?MXv-(9WU3{WUO> z_7}VqF7KSI=~$$p_W4Vy`_0|T@NIPhZ@WIOhuYRF>5Y88Ce1|{33x2QSUpR^Cy`1- zEQ})=w_w#-I$s-*WPc5iZB;(K5VOZ`Daz@6QAAk7Wzy8mcVC&%qNV>7F8~gfVO5|5k+h%e0bpv)XEf=g2cDSLw zZhZ6$eDo|q>$|8Rv^bagt=Nb+MB9xy+?d0{4x}4i{x?y3@o)`*@RtAoUFQFP^Cj%x z3VD4s5wB~Ygf~L_J_+sXsfqtpk<2x?z#GYYmn3s5vj3?A?W>~QYaoC(+WjtR_g1z4 ztEt-mHL;B26?jFZsxJZ-$2s#6i=&&@AdAy|uE8uW)769tYXatu>f75>=eyYk;Hx6Y zYe1Seg8VKC^0u!)MJ`3Le+{zoM*QC;@!vKoXrqF!idwG$65gow zyQJ3J&Ij-BeDGCK?KQBq8`XZ7RD0V>VH9P5W6z_%=T-_|6??b_xOQU?-z9sv?alBv z?9K315%o2It6Oc1@3J<=-(jJmPo_;_60e-zTMgMd|NL=WSF7q(swy z`DY)$`+xuE@!y{Q@WaDj{_>~){QKYk^{;>Zr@wCh>EHkS`FzylHHfPl$$Xb2bIV!$ zOwQuhM7!4@u5PsZUDEC?S?B9X*7=H9#_1Zw)s1C*mn`G^*(~F0BFJkHS2u$EE(!9s z`GzgH=RmHOc6}|rnaAlG$kmPdzf0=>mNxTPn$W(|%|TArV6JZD`dyOiZF7(}AAqhF zW(hM~+^1_WS2wEtE~)mL-E3rG@_PF{Z(ee`26c5~5Z@((_|0uzvNYrPYBxhUT>-l~ zoX?jwL+O|GMQ_%-yUnrB-S&QUx8s4b>ZuaN9&EfR!a6EMKxszq(j-Majt`BMeZ*CjPytkpu91Hpi zkl1Fwx`OpMX9?D$o7aiF`&`F*mgwr4^(@fUGwWHRr)SnPv#T5HIsdJ!=d`h#m5W-T zTPntyE>OEUt#HBf{%&Xcz_BNyW9#F+AlH8N#_=_trP-|4&Rg#>M5@Q87}y%iJG3d^ z_CWpc>zl*Q(cPOhetSp#uy^*GO&?p=e#8y$sWYp%rcJ>Qo4c)z;M}o&>o<32U7QVS zcfVex7p?J6gQ;0>Vyx%m-EsY94CcJ8eYo>;dVQa`uVfR4IUMf_Xx(Oi+Fw?-oU;VS z)6MG~ulrob@s{Z7nd2?c)icLiqNit$H?ymY9B&_i{DbX?x0}t5vUR>`IPYmVZ>`GX zjrGRuH{0WzJwsHZ6xq{As3mrY8-EiSXF58zw9dZW5FG2(HZAhvS%G~zAKSU-6F1gpOz!o0|Da^eJqAEoJl<``=i&I|w>y82AA9~D zx9{%O=M#mKZJno!#oo`;dnK;c@0`JLv^w1%Xpy(ie;=u^v-rss2+PfWzrM^*oU;T!(ar1pr2AaQ zPnPKFnV&4s)iXa?qNitmGPA48{N(f%sB$|LNtL@OZHL zWn;&99kO0H%|^T3Z@NV;v}_o*PocXV$ClsYEF4|{YPB8h2)4Un!?1cfxZljuGOmG! zu0bd+SS{<$S%50)=2fZ~_qmEH7U^oDiY2<5sA7?xCaRd*)n%$+ZGTRt{N2N1jr14R z2{>N^qNLkjvA!4K`rYcn`gWfy*Y^Tly{zx~UA?UD1$uf}-}AbMgdow)>x9;Qt|PQ1x_TzG1-g1Bv?Y3aCbXGdT_iM?;?2GN zt-H6cfF+6;(_5oDu&pn^xW+k4(6?K?PTx+rlD?Pd>Y2V5=<1oim+0x4zGrrIk-qop zo_&r}Gsc$TfJ`W$JOx64axc*QuxbTqhlu=<1nz7U=4kdY0(v znR;e+b&+~@0djd!gCA}Oz6S0_yItpeSf3zqcA*lBZwgrIpc5GcH`=6;>? zL*5*mqp@ooFI)l)dF~IciE%QIhXAXGI1WUzNQ{VW(TFKx%Wtw95!)HtlWfF)_NP=v zWA7gr^ejF03e4boeYhCL9p@}Tsc!W;r8?nCN?oF>XG&e5t7l4GqNis{o!Ql8N<}g# z6&L}f?m&LI=xVpXiY;=h+iK(i6l4sdZ&eaXj&qhE zEw_4|wBl9Q3Be`0dNC2_kLtxlT%e~H6LDTw7fEYtMN%PidBb{I>jdC_e;=;iAH>Io z%v-O~8t@pD{OjZbAOIM&M|ojWUKNtv~MF>_l05_3AZz>z&h+kYcx_qh2`gfm&q-03W@d zgZ|4&?7X@HghVoJF6)`jS%SoL^E!!jpX*3$iLPFx*ZfhvNUsHYdXZl9y1GbWJCK{C z7l|ae6>V7RQ5NAdD1}rZ#Hf_kHU!>1<{#2!qFP%GfT0L?+z&9t!4hDhdNUqTy1L%BimktR)N+h|3hc7)RHI^Ew zAz9rc+`54x*!4N`KMZRh|BZp3IGu1bpeXgVBCAxa1U0tN*ayLmbt6Qq3TnARrX!qNaKQ|?1NSxTA zk}OGW1S-1C;6ja?!)Ujt(JF-;8Hy|eG;G{k`wICNz(snRC~$697b!4E$3VaRx}cE>;Qp1NM$W4nYUB#SmZnE^3Q+zAAfoH-T(gA$HzbX@SjfS!+-n#_CNgYfBxZz!2-8iYzs!=Vr1Dl zOV~Lx;SfVL+MEtC+aY3D*=;@i%W_ERv)NVNj2QgtONICky)zrxI>V_S; zMwrfoX}qT{F45C7h0pBjB89__e4+Zz4L$OV9+4e>jfCW}y(l4_vxJ1435j@LLN3wO zvxHort7i$hL{HE3GqbCU^aDNeoP~G8kGz-rJK!kWHv)7Oj1gqN7hDL`aw@dFRossE z@v!B`60sL_;NV;aKyqH)03_E4yO~&x_k`UNJv|fa%&smID_q8K8h#@XlIQXoBk=ZB zU`WoZ8;0Z>>RJGf@?tE`1AYuTeK8j2b#;-tU`Qra@`fUrmCJKp-%upi5ZMBNlxHGa zqNf)Tb}2~zI^gCak%h;YMA$coBYBRd{hC0M^?q07ysrvLvc4fnuA%3dppExb(j|I& zrstVmU8LuVh)2)AB`gW3S~U1|fl1a^fJszHy;x~soHO5vGrD;VwlUr3b=Zbn5MhpG zx*ATLMYM!!}6`kVrQ|{;HY*QW7HSqycp0B;CSQ`s?ltgw;_8 zH^5R(QgnZpuc927AH%>23v zshrnWKw`#1y5OT7=iJEq71-I0y#GPuy;lOf(u_Hp|FQcd#87`(64H5n1+eEvr|BVc zm4h3d{zK^WOrhT$54Q^2%b=6iSD=$_{NlzhzFoDwoF)w8R>$?5##pVdz*yb*)QwMl zyL_r0KtFGP+>l}~NU`-5NU<9ixN(7RmkU&Fc{mww^^!*NdwXBBePo%u*WlgkbXf-b zVg-}V>nreXHP*zNad9wfNig9hO zfKcAp(v2;ByKHHt@?C7{w*mxJ8n1Maudk}u<^}}4jK&_k^oBrDA^qC}f}R!D{d}P2 z@4j=`TV)U@w)QK6QoF_12}<2u0ZLV*<|5{NoHHMkI=Xp{sHgi}gE?QOtC!L`uY=vL z8Px#0Ei$N=I&Bvac$Wq>10uP(0wTHIU9oC9XMt5yH?OXmai6PJ%_3b*t7eI=rd6{@ zPgAgH8mGwyR0uUVw4iPtRA)x>KS z>1pCMbGw?uYp#H~oc0$NO{dIXGxhS?k{NfoX2mSg(O54FbTn4W68(&|GP9#OE9DAw z!v3-<(<$>;O1-?cQpR1bSt(0&G*-$29gUT;L_cGt%R^rGShdZJ><_RIuYUU#@%}4({kNt5 z{Vet02Je4s7wknTc8=bEMO?&|Jr@=Kan5|re{}PjJ7K!d>-x-d1*b+myQ`u7FEXm3 zWi8XwuoY)_)v9@2(~?0=zxiqf%Ujz?E;+tAWOPNK=zQ6H?v(jNR4=bB{Bf6SNN9jNMSQbWNT~6K97fYZOxobvfDW3!1TjpQ>d)Jo%U`z z#kT70Ml=rj{PC?mzn0a0MS!arzThnCl-p__dryA64du7C+IMf{U@pAccXXuVeaz7U#6#_ z)XeVcqFQr+3LR=qFT~c^Hr}Sfw99p%UVCKkWa>JDg2NXYGqzp!x_#&QQ^#KRu25gs z-}d^}?hcaty&eBn{pI4df~#c7sKu&+>%LvLZ9#8??L9ZGascgoqd36Oj8^xy?Di`> z?9j8SA5FLUz zXzLD*jdsx3of6K5K>fQj#yj1J)Ew^);w;=|ihS%^B~(6y*=Tn6gWG6;pDaUG$gO)Ww`R)gfL5Xie*XnsW0_8%Kb zUhZoDkpKTR#`2pBfEMrB3t}!6@0lTFc2~saZ>ai9sGc!H*Tm?@iLb5ot9p9Y6)$+l zFLiZM$m|v8m!Nbn-cHEu&g&5$uT7(;TdDoOSt)!aa=ts$B~Rz4exWbY1hwO|H=7vv zYS&*c|K`~8yDNg{kOY_2qRv@BEvlPW-{`nc0*~Pou7e%)2_GCgR*X^4?rKttmKfEf z7A?}#v|{IWb#cXR?GUjB{8&AH8loiM5k?HvF>wU2dt{C zzUW>3SaEF;!4`@{P|E$?*-jO-nH9TZ$Ioo&>%;Dm*0g^_X>1Xcm$QK}(O5gP^@Y>aKH)JBzK46&Eiw5WSj zo1&$l-5O}d6Phf;^2F|~loPWML-4eD@eCo;>KxYQxSoDy5&0FcfnhA)To_pM9LLJH z=)y>Q`dnmY#AR|@Snh0{HA(f2xh+r-R|%g-P`DMwuzrV92Mc&5+;qguNZVW=!>3XV z>TB|3?5=<)+|sG$W-h&jCzz;tk)9@zJ-4gNB70Bj+;hRLxZl|HMB3e9|Hye@yR?V> z@l3L@=*gG6Jb~?;jkFVeT!~+}YO_Ax^Cs#T(Ig~^%BS}w=mT-PeLUSI z_sE^H<%UR&xFhq3*ZNJ8=33!E+zc40v3F#9Iz8Z0t6y>%7Yr9k0kQYw{L^@l@!%Un zUOnD%b~OAvHrJf~rCI#(?T+*Ius^=cN27l3e3l5m0#LC&thN`U5S_Dto?bVvD%aya zSLx}CbT#SeOLR36{USY0L_fEyi$tGB*^Z>tWU4o>BH~w_bMhU-Nnc z9p(2%K0aqH>?&^KhBxszo0K4v1ud?e-xZrXtL?HgWNLLfPUZSgsT`$tpw6N!P zb&*|f_9D8g(}O)cKUv!!=~bQbs_rstja~(8xD0ikJfjN$8)kZ7V{^}IbO{gh6ir#i z#Voi8xUsTFVfS*N#}NTah0;j4x4{CAKl*q)2~Jhrxm)0g#Pwq{feJ_ zzvJY~e{h5^Dlc2oH$w|HNsNo*KL8O=0O(@TxdU+Gi9?_kXinbu-TuI=f>o@r_nYVA z7+#ntP^S8v`Vf9=S9;w~KQAG?BPYXi2ye$Zw>`i+!6cqe?h;0EhspD6tat{wHP>q% zi|6Be;X?q19u`lp8iSGx zz&}L^vzX(t%*~r#rBcAQ6^rTV0LP&aMfB zf^M|XDacEST#%>%rCJZypRj~;c3q{!30HXScHlnNd(@dj95I9q3A6&wlAqh3P#&X& z-PJF|Y~8}Gyj*`5VvBdZ+iZ+{x?LnbptNxScbi5AhQIaPA!Fd?#}fz`odz;x;8Vt9 zS8j!$l4u?C09Aa~#uzw*aP>4iR%6pP@rdnlnE&c(0Cdk%Rxnm1?7 z@mRANFp_mL+?moTh3_F$#D5ND8}#YndOy3Q8QD*`I)ySc+O3Hvat%iGpCo_ove1Ch z7^)j@&Sqo`Al|Y$1y0L_S{0hcdYmPSuZeWuMDY@SrEgAa-9TH#UtqOdl zxmJxUc>9pJ0s;u65OYYgv*viL85H6eG3!($W%&lrwxjzQF#raCzLRT#1R;E|&>kT`>Vg=j#A z1bjD!W=3O@_`K|f=SL_F9Ou`qryGxnqZX&}DoBg*+zbT*1(P%DW42~-m}|o7HxBb% za+n>u7Jqy=tUirFejKOSAKqaI+vCHYzwG0Hw-{S)Iml})M&hs4m}*LR;r`R{2gYSNXs^Mkkife^ z3tUFOVrXc8MTq@Y3yqBYe46-gE)A^A#sk+16DaiV9iJxciwlyCwdUb0jb@wcP`lrx zjE#(F=SZWpTY72Ud||EuE>j}Y zc-9Q3@*q;L_DrI>8p@g*@KyG?J2`Jbf6P?@efb<0J(tdDd{niRtUkB5N(E-Z&yPQ& zsY=LtH8$1>mpnVqp39kCT?|A0MyTWMf!pY3Di78_5RY84B`a~Vta*60EV(r|(8%6q zBH;#p2A!988laQib1FsW%$piUk_>M*%7Md7;g(v<3*T+) z9r2(Xz`4ymuTRP7o)H%6DW)kP%7=I@^Kk=ec?JU+$gL(W7xlLR9q*fIL zR3yop!3nAvVoS(?)l*iUB}{-OwuT!PK?zs%nbi6uh?mqYwLm=-rvC_V6ofFCGcQ8% z5A6`U91p~alPcfFSD4rpBTOhdsBS?HT`>Alz8V<+iw}a{Wy_{v7M#4}(LtAak)ulq ze+cspk1xV>OKu^A$rDnL1VlQw1&8Ywp9IZMfN1`iysGgKtc4tmap>5*=&3XSj@BN9 zKO)ZZ{3tnCGvzj?IR@O}8emDYdP$;p&H@s>ZeEpm<31@4m$P%1=xPevFEOeq!m>zD z6Q$4X>as*%O)j<1le&mPMM5IibUEI_>cMXck)ZC{{bAU5r34g2K@Lbi3PCHr=E}qq z)c7GUy-yDPQt1lq*IiM8=!za&Gb+C;G@nOsC+e{&o93CWxgkRU(8hiK_;xRG_lpcl zOrkQ7Vhz#tC~0>fxQB8c3&FA4y*Qs}q+IOB=ndOo-*`m+MQ26SoQgk}lk^O7?(YO> zDG8+mM%3b`a1HE%%B%DYLo49*q~qsp6$`=d4(|6%(ym6*WhTuc>8p@9B+ez09?IoS zN&hmVc@CO>L&96OdbDx;)@|6gM}^DYdk{qV9jfVvtAIo>85b!%=+y$0uA5hdw-nJ! z<|>9+4oGLt?&=wHw?J3Vl)gky&uaS2t}Y7iZT4qsy3phBRz)D3P8LIugQ9OpXh#XJ zO_UN}l-n*MaS1uEiiBs)l9{=ud{TN-y~N;Y#6&gWO(O0ouT0i3K^n5MU>vALRVFC? zVryvvpSY$f8}^aO`u14JaE!Xrf$WDyO`9Mh3$q3rDAPE3PpBq3h4#V^jE5y(c`5+j8N;|f`xcC|3Yrb{$#TnW>;L-(l%FV8MxdS*?y>cUcX(#((9M2kgFQ_-X z<{xF|<(&9AsFxFp^L%Zaf-NU`LA`w@w(VRih)%!rxt5@pYAc~2Sa5h__RvN_uf5xK zZg=hIdockU$Z{uqHq!UeLx!6v9Wi{iu)W=7g(s>#nlGY2T=571N}-W){1-iBk1?=6 zIvkri2u+^yQq=KCQsjp4kh>mc3Sugh#6Mv&1WP*i(}$eHAFjdmv=T3wRh@I=53g{o zZ;wA5h2QXp7dPSrddrK*>!#rBR^Ttt8{!itM`D8BLe~6<(W#jznm5uSBI?p522qc5 zhudz%qP%SevI`tT%W^W+B0{^&&Nal|JaS(O) z{+l1Ncwuq>qN3ro?WGXAVc=qJ61X-cLzn3Q#yx#;`61^ph-&~rYbhd^7)0kRz#!`8 zRRv<)=PCtak*+2MVu`LM2C+y_lL9fftD6D=R4{{dj@KY;dPz6ZdCg_n3|-}>nY-TK zbJNW2>LTg1dC#k|RTOK;R*||d%GR{+7?j{huMUxeX5&upQrbuzwgEw0V~HvuJiNb+p+(`qFv6B8&`lkZrMj)jB)+u zvX8#5#d!rxL1O&H5=P^k`HXpV^BQBG?sE-eUZ$(Tm>214Fy>`?8jN{%R~H%cdR=O< z`T@}KQvGAY_-n0y__A$x+2&LUiVMKbZohu4e2bv8yyjt7JIB@t+0`oBXH)yfIo6kb zGnx`a`!dK5*$#S~r*Z|W#4mAxKFSeAC6a7f;?9-{UL_IjQ=a3{^c_%Bz=_-HkFcht zs}c&57_>)rJ`D)Ycq<{t&|m)j__ilBc0ePQ$&B-G_BhgUYW?$!9apWO{j?<$b@ce8 zbxd(3ZToCYvW&s0~d|sab$VkXg>C0+bYk&HB+3?kPGZDxi|<`W!nJnH89= zb~os!jTeo{o(7abcqyA8fi}6+bb=!DO&CR=UCXh+k@9n;^|uEv=eXZJwAX3_(B=4E z$4~FyvO9fY(}OWh0m1G3@=;GDba1l|$4x-zL+5-c)bJY*OkHt2ov1Rn(m`#ES%K>XbO^S(bwkrN0-=Ych0(^R&JrG>4 z<{xzX4Hwz*yn5V5J$b@Q&y8T~_-=DDaz5FHq%g!IAO8OQC?RM!?SB3HUxv#&UI9EBto4E=GS0aP zyh|SP*;49fD}HuY7X_Z}tG4UCmBtl|EN$#7YFWvivQ_SOk9*{jIaD<+%mil&ZECOe zcTlC9$L%2-+Sh~<6Grte)W(;5c$5OhiWvpXAZrIpBakfk$Lb{<)ce8nDt3u$l0xd* z*zoNTci-*bA(r5+{DJrzlr~0N&RYaU zY>~DyYow=f=vQkK|Hcl4ew+yTS3Art#^3i<3kH zoy$f`l8!25q$Vj$_|}^cAdU=X+yT99J>>3SqRPMjv^Sgfnc8}Ls*6`TI;2wI3VO?F zq87!@oce=rgBiG~fEoj9JuY|x}ZcDSP#_YIl z;o{HT*12xG@3tgeakQUqyCv_byDKjnjQ@q2x%YNTSKXhV^*NUz@2twb}%;~%u4e!5%PiAgB zf|*NS{pn5YbhJ)o!isPOA42p-IB@%o*4#I@qbOtFrK?&xX2JU-v`1+!3`NfFaf3AN zTW(IaiTA27p8R5cVwBcp5yJ5hB?WJ#&th+>c9&A2PoVnYISoWOJ(ITeB~O9$=M$+}(dFuYy=n7l`O z*zRy}dOcC@_DtM6kP~+EsKnRZuvY0owDX8*ibvNk3R&4`IvdG_v6DM!!vlJpcM3{Bkoqa{RJPQiNBZ7|OG#Hq0!j)Ruv zT8QMpf4`GdGymhWccG)X^ST zgy@zO$1uc7TGWduef<~GT(~2Y6Bk}EEAJ|=$A=tJF z6UJ;83sC9u8FdVbfL^Vm<5j-@Me38@72YxYk-i%pq zrUSsC^rDBH*eS`MR_E-oa0psCPn8GF$YI5g5*MIjlXQvWFig^f4H{Rc9Pnn7(q3gU zW3;xZb>1d-dD0@s0*9^EgAhRtx;qj0`ehmtZlin*`HUGcEry#RQ-Ctzz@3RSumlAu z%uBYZIQTBXT6G`J+fl1mv*FP<aBV*Nt?k)GGxG6S0-UmPI?6l{>DkaQ%*|nC~Aem?vP|2 zBFdJ%@GL~Wy}Q%BWzDTLq1^`yK%DZ@(_T?WzO6Ke75erItn8xO+h|2V79-i(=(03S?!%Jp( zuMuO(zmXed((F8pI$${~5IJ1!0T*hEkr+3Zk6ASB2B;?n2lkaY4tXA<tWRY(XBg~)7319;T7=x8(;fg`5O56iVihg@YtEfI=LH$qn4bu1nEh*g*q5Y zTOzQjaKH79LO0^$r~)HFPC|516=x$_8)1W7XShr3vUqvBniQ7ntkgP2vqqQn9+vme ze$q9kJJ3Y2%1w-Jw|c;VVn&(%v>wOVi-IY4%KGK|sFJznMN4!dM;=Y7$i5agtcsYu zk1!CXHN{twj56ow6TxN6<0llQ*mMzo`c(cuyu>CZJ-o-Io)!eaKx=tMQ+aX?QerTU zPzfRgc?>#i2)Yblpxts~p>|wqYr^;WK)<-I4=HawEO9O&DhN0%DpT%P7Jlp1rUNo zrEjaE<&<+kM_z)Pct3@#h72O}FjEtNF?$7u=M6GaQsDV~{muVC?0J(@LKKEOtnQ!! z+z35yZhW=}nJ2WhVwNX_jKLpqZW3m!XtuwCaTzJ)sv!dY6mrgKB1XN=K^Z~^_gv4` zfH!W+yI*kwnyJN?lZWcfd9*%OoRRs2teU!V$D*Kpa~7FT50e}u zop-!3jkpy%lz=pA63w>bMrk#)?AE!TR-1X%j$>|~L)`xpoUHQ3Mzv=h+G0o@*dG;b^ZHs=q zB2ncg3cpuTh=1?eTyF@&O<|%upNW-WqT;1Fz;}I~507yvI4n$*0!U-U4f$kUPP?2e z`N1AiozYJTqeNkTRDxr)VrrP%7BAQ$q$93&$Qd&p^vM;GBsj~`B#4}{DE3BYXVoZw-2jZc8IadJGm&|u~TDU2hT zeX`Jt^vT0Op5kT1g11LIAfU|gc?ihB3d}Jtdb@hq9t0E3;Wj2GMB>HaanyADEXm{z zCbY5A3V?IsVBM)b4h$m$`|GB>%-%V5qNKq+7Jr~l>^aT0M7Q@eOoWbN^XF0O9|J77 zQh0#262c)(%R49e5*w}?g@JdTas*gTp7P@fbJL$7a5=Dl#Q@7Wzy0U^Tz{t_@B^Ys z(q_T6WBMpqA5ZJMvGhJR=|AuXzI!d`(5w1~QP_;2!|95wwVNFMKIQ1X`j7eL*$C9P zibPXB6=Q@y5qA_=;3Fb$a8M@D_~lGFjvF#wIN#6k*)&M*AAx1Oe7La+p9)CyMM{6R zPMbZp737{azezBj_m7-O1TcxnP=ua~JC1hCC=IqT%tq2W_Y3x#sm2&3DY6Vp9ajyK zIOHzkS$|UkJ0ugCeG&<##p{$jPM01w$U$&4TLiZme=`MioW6^D_eG}G{%M@wuj8K% zt3M%-N+qt?J^n4+pvj}uG|(tKXHo=vIoxw4;SurtI`H^(6s8M@Vd02A+nKN(o+xjml3*6kTjHW~Fy>FyL5zuX@NYxAe?3f=Te$0_+#Z!sgF9VUWl zZeOORfcT^{5JIetA%BxaOuP}3C|XPdIZQ4zA%rF8&m1iKM&@wBD{>HTobdbPgvf!@ z0n;1CdD#IWKfxFgAytUpkLIICZW@l3!2Tzr&V!BSp3Fy(M)gxCv%{6|(W5CCki-PxDlY>d$?3U3B zwSDx&uf@TUU!0AVPVT0=^W(uug`q{JO{r zuG=x3IXw4@+}9h={XTiF(qnH{>^}PjPy8syX$b-rIv(K*`~Vc2>KB%vqu6o{9|>Cx z4^B@UK79miH8Ug`*6eurN{Me5Jl-~_JRjcCD=(!_<>#SX;X?esX;nVaXhYhS`mx`i z9>@N|yO8CbhH&vI-YDETJ?nEwvQMl@B4#V<8D;B+N*0Is+q=nIzIrUe!Sgjjp1C1@ zK|h=&bUad+=o5$52aZ*q z&CqYwwn)=h;ZNfi7Pmh?xt0o%7HP&Au=j#@L8<8?-T;2K8)`4xRCq7HYd<`vC?#pAIKB&&U4Uu&N9POXj!n9L3h_l9(Q`mhu!8Kbc|aKmu};9WzYWxsQQ$ee%^GgQ_j2XICmD^-ZDvV zbo;N5kAL{#{{Q~@&;RS+{_@}c{qf)b{KM~T0W!rfg7XT}Fk3P}SYWwej_Ze$ItL%S zr>$nO{VY00M7d@b>N7-wKIDMV0^dwH*L-d)#$8!Y&Mtc|IE0JCO$^jl4m`SiP)z1X z;H=C9e|NkVA@WdV(4scxrA~}eCpqW@wMp0Uc|zO`qvM=Z1?Y+M6fhc*XLv7gGaidY zSc>VuObNbwV#K`01}4Z@5<7dOX+X)$UC$C*$jTL50nEc}_{H!WhN6gB1|!!M6au}9 z$-^iDIcZM$<5)qtE*XS**?8u%qS1V36r&CgFtEZo?{PD_n)5F_9;NZLpYD~a zgeBq_+-2-p4o&^1jTZan=L_+m^)Of;?XNc!_w>5*W9FyxH>*31FY7obq>Kwrz-gEp zJf|uOdc?InJ>~^66MTgMr+*_e3VzPM&K6?|ZuI4SACImbGnFBjGhpb+rl;hXpe!Tq z-%4Py8(y%LMhKy8!I+4WG(tl7sun6Gak?`d%)D-=`&sPpmLzv$hhJcaaPB}~YQN;B zifdp-XtcJBYSbMW46cC2;WB}Lu(f?;f$dFth|fSsqgV`GWz{di)1lqQ(x!;#nGeB} zPefb;H!Q;GE=RueBL=H2{G8|i2$nW|1wY?mImZQ_(ch6`G5s^*z@&H!z<^+hs6W>A zIHJ01W*WYRCtwu@#$6Q}MjuF*3AV?w{JW>Z`RREnMV?KQVq5rLi1|6lO)}t5n6qSF zGQhL@rQ)|_$D=Gj=BFsch%2CQvzT*f0vf>d#4O?iIqAw^X8ZC{n!K^2t$8fqfVqx2 zHCoI!DB3s_@sFu~+UI_PNvLh=n~adK9U;KR(eo@8aZ7-@v4}6Qh%Jvt-XKz+NRPhx zAExH4N`f!KA`;?(&5=rKO;$-4Sexk-Gz-p;8dppg6da83qRS3v2cQKmh~Zf!>q*>H zAH+jaVoN9q(V-(Wl4FRzgKt2|j-T|Vg!K4+h+0RI{h@K8%>(xh*vDWoLG{S;8vbLQ z38jLY8+10Vhv0e|KJ-+KLVP?$l0x&ork$i`0W7Jyk)PfD`I@Iupm@+c$`SIUPw1smv;Es2X$H5gw0`q9rb&{qZfchy!0OAY-{NJJ3oNu zzMvv;BRU&RXu@I?<4C70P%;i0DQuMI+gTHb?dAdclaA^)p1;I^#MBD66byBOptgHG zhGfo(u-*IBQpigmiZc}uqSK>F)&6vnfml7S^fpq(1Nm)N_%s+$9a7dc^i7he(8Kr= zQY&-Xi>Ld=LhDG&B(Ge14(_XT+$urK?K+&Y(CS#>}l~z(y4mHy86rF|FHv++PD_ma#r|Q%5^oG$@ zLT)It&O2?5XKVp~{R`e_q3l+tmd1FJ)$xHip|Dd*t#aTzqYork%t&~MqTc5$(Q?ZO z^VV)ow9gsie>c%m&Q&{o42XN-Q;e@oSxW*yOMkm)32cIlX`@Mz$`A>84q2C950z=? zqZ8eZJgE{II*9d>9m!A9O@q?mWiri+L1IlKDEoP?heO2U@RULjddr1}RLKnF8kfQZ zvD}19z@C)E{0HYDTt=WcQG@w7s>SqZ^<*EJ#J;vpY2&fZ5V_Bz#}LM->B(+n^sui* zFvj5N0mt<_*&QAvW!}+TDKW*(Cj#M&dsd=mwSISg7besrf69oVf%TtUaOdphdvc0( z47ZsQPfGAG8l00##?ElA9nY9B$J&y|F=D1mB_(JYo~%GZ?=szFBtIK51!>IU0^&LX$mEs6yq>S zu7%`nmC{XGoPYDfY!mE%RlO|NRQml=Tw>ntwKvU?^=jVRs3{{5Rg_+86WlmYgHD$iNc4g1O21{RwU3zKx z>3FUrhNQ|6OI4*<9aw?<<5S}12d|X9pI>a{<$wGrc<(5jYs|pLxfIe$l0DP?nrU}2 z**VmGdih?_2iep6RD;KQOg-V2d&fKf$;q!+u8c@)*(e{jz#|`z^rJ~ov!n1q4ge*pn){u1X&NfYl_PFmgoGa!Oq!P(5Htwppkg638oi zvuUQf66ma5w!Ha|2AZt4iU(z_J1jx?qET(9tET^H=N$)8$m2O6K z(Gk!lO^&;A4tC;}CFo_}%)Wo9*_ZtTpNh$jyanqXLzz%zSqznn>%dvEQF5nG`L-m@ z;3dea1K6=*NEp!ZVPB=-kGxSI=>ECRsH>gxzD7I*%ukLcIDQ%?MDyHX;b+-{Rlm(fWB=$A2~cwIk(Z#&6gKb@_Fi+LaM;>P>(7(aDaFP{+rSs;@$ z&*v*Vz4^!gRBZTY5{S(6UMl0om+X|z&3X6X6ntO@y>kXnTbYrsEr@a_ojR!*A3g&2 zMAGlHerWr}kB9rw${Ra0zILNI?EHL7R=ctDFIXgCX{oI&g>ZYiV~*n+yB7enxZ zHqEI`hvxmESmsrsBbW1CXr+dy#S9me5m`{tJbkG)V$U^IDbWJCyjv`WM;eLksj?vB|zw%bB*_jM<}-Adn_}*L=O1e6a%c0x1*{@!+D~W zJ^oJZOqV-n$1PBxtH+`n_GmBv+_mgBf0~U-YOo}BtNmlj{cZ>GThd5%W_!l`5HvT& z6|GiRL0wb6OFqvax)HHQvO5<9yD(!3YAo1gg;O1k$bk6h*{1z z$|Gxx{i40+r^HixR4Qpf1ST8{#+}NV8=gpm)UrIhOvB7olM3B4B_mT{#hg8RA_4-C zONoFeOm2Wf1r>`TZYY@CsSL1Ykc*^ZG4SAmPS65MWeXz>cg_^*prx9pl+|AIcxUwV z3Y=symMD@pa*Qams<=o2cyF%>&f{qk)vzH;0L8WUcYo0kb6Fp{4NYk-^p(l5y7&71PQM4;Y(eeb zou{(2y)^&4;sE#JUxO5^l&-hpGpnotv8viBxYHC9rOiM|KGh#tRm-ur&mgsI213CJ zl0k`jZ>8C5rSfX;OnPFBA>+mYMqFQ{H5=cRUaotCCRh#442w(6!~{QeD5~WQ99XUL z??*wLsD!zzsQwHS<9tgS>=obO*`I@XR^>wke$Q`T9XmV=P1l}>pmE$0ZVyy=<{;`Q zUXw%KNtk9iVVqK(JYY9ll<6;BKr5U!7-h9lQ3|f0XAGjKEvZ&}5}qO7a?WFC{zAw( z!sNZ+%8_-B_}Ct1)VcTs-5W{!OAo%;DzkqKb$VDmp7Ys!0!*d;Ri$J4vF!lP7dK7> zeX)Yanb{v32~k<;Q1tJ!4IL-%L;@Di>yRI2ktgVHXT2L|#1_Xzc?d>H*8S35&fy5R zq_!JJ_>z|TcjO4U^7sMKbfp9`b5Gkx0@=$cVWff!DF^DAVGv}gRwd>yu>t8F$;~zB zPJJZV^Ws&=tuSGL?SjHd+ffbab9`rvh#;2&Oan`PtIRov(r&3yH%j{=r4d5Z-QpPp zS)Z1y3Yi&8umQe7Z z=Y(w5PxO#gmbEvM=g|VWG`<)$RJxiq5HO7QTrb%MjjNCaVa#SbvL=fSkLn;OL_u1_ zLWQp=RD_rApOwbi5ReFQ9MVo&y?dqkN||7DFjIUv;y-lakrY0PfpFZnjmVDB)GXi@ zRz*kbtc+J?ifKBqOu>j}(f=*Q>PG)xpnr*lZ?=zOc&zocmO3o}=wMD^WRUQqhL%ar zKIe;h-0>MHwZm4e3O5?6>|4xY&k=p#r8(FoEhzB5{RB8iFo-}pwA4W*<4eGMP8Qpv z6tcBXA5)f)OzGDZyZqQ~(9iJXAp88Xj8)+I;Rl&SvhAqej^L~0^T)!N6mz-S0@|2Y zeq1E3_C}vs`+}0b<8vY2Lx8BJ@2SCeLT1sNIaq!M1`PVWW$4U%@O9e1fd%-e}R}UK{T1M z_rdhIs2IK+Qu(#y))a2HoUQy3l=^AU!kN?c{$RU7<`8UJ z|0vTjj(?qVK0@|b13jbwaz3CtP;MN_ggxzVVLIaG1grO@M!@3GDegs zLG$RUfL#q1Z|bVDXzI#vvL6gC)R9*8F+=bebeidxv~K2wi?K75+&Qk%&3GC;`1x{- zdX6x^L6JRcpNdLskx0M?BzO2Qb}tWgF+}pKYIqiIBtRiW(iz0jHtB0V^O|=!z{EZGawcLtjVJv(0*K&nz5<; zNzR0LjNXdh`Hk`+Q0KQIWf+iKnV9|zoLL5$=&u9W&7!!dRtvfqnx&Br&%a zBb@ns5PI@NMdt=b8W2Zpjj=!UB$GZ;hVw57n-$6wkqqd^9Z_J-^ba3jHWOXQ%z>Wr zUTA(CrBrt%dJL?Gk?@aHQDJySs?^}&tBO#1OS=c;BQ$r6jN;+k0~&=5y;<{COfY`~ z#pBVvSC54~#R!21=_-}*D~?N95eC%!`1b6E!850#3>-NnsIj!pY%llpS_%=H{d73o z(2}SeSlI(@Kyl|7uDC0z%29z$_JEc}NG664v#IS+u;zy6C8a+Z;(q%m;2;oNWm)*i zqKhi=8QU?7O;}zptu?R8tEloraY=1EFBFTh@iEX(ELl3lOJyB@o1|ouw`>H5OR6a?pr9X8A_xw)P`R4c=Pf@*=WH zEwaReue?;pke(YxeUVuFaNir|BikA4?YtGLfFHZ2*yS46ZDHUC>-kr0yQN2ESom$GpropJU z1(Aj6qe4_`wBx&C$(^IF#dv)@&4yyp(S2vxr?+&7*4Zu4`&$n5=KsQM$XVo8<`PY^ z9fl=TV-~UhSQLJ;J3MU%UFFR3U0X>ae0(IcGS9IKrvPtCZ23!>sJLJ0T}j7wYYU7t za5gM-Or!m-OHv!+*{z35jEamk*w+e|M#nf?G8m6ZljUQs@9BqJSUL>+7LsP+VD%iW z`UYpev7j$#)geK?d8|o6Wf~==KMe{CN#JvTKl24jz#IBxA0w4Dpa@eq))IHg;Kmz&=%Ju*s}P>m5HEc?1WOh&Y z(c8F(#%(-z{AcPGcdGY_4Q*MP?eL^bO!rTfdA^6|?DiPf7=WqDsvSe~$%;37+w+(& z<_`U;yvku@j{BIqqL`-7CblwBNzy}bQJodCrd#rK*^UWu<9sh$apSxZc3jiV`gufPyh_G z;)>nw5jI>ch78nhAAoQ~IGLECmssSvU%cANTGq2qldjVsZ}Hv?&fSVe$8XA~Q_Y>Cx%Bp4AhZ_q-0o)%sx68iu=RHrd@% zw>~}N_TBW%d4sd@p)9~aEC8Wfy85`T!4h^HSEN%t?jJdQrfKFnnx4I|Qxl!ntLJNg zxkb9xcUELlR0O!W9*cO*EDtQR1N^Yk&9n_b8Qz@bTKghA`J-Qc`saP|?06k{{HCuu z_sQ?tab4}y?Lp=M`igj}pk#@RA|vOg=~o?CV`?UKN`JJ_Yy5i}LO-v=_?vr*H^JG` zs~*cOpc~}WaPIKEpeWA4!=p9CAMscMs?wQA#Jro&JQszw_pY@FF(W=43D;J%6>^C9 zQL}cfycF>HvwNdg$WwLRTO1P`;*b+p>yV$Qb~WA7Znqw=MPZ1nqm-QR0NrgwAWfKW za%yx?gwOpNr1xX_wdQiSc@;b%4TMw3Xvfp126>EuRtkhqdm8s0D{9=MZDfakO7#>k z-sjnqVglJ+k#;PZd#g3q^SNhsSKkg$Jr_XJ$nJ7qGkpa4s$M^?ZVEsJho?EHD_Xt~F*3Lc|8rf4i4&y`3s_OpE~YmfJBgk!Ax z){u+5j~0o019q4RDM0?Hg1%7(^#XAAxm70or+5x6j^)YWSPn>6dZc_=Et0&yVyM0d z9@cVOwHR2yxokZS2!|;o#Pn&T?~Zmg)(+0?#Rn!sBcgk^g3j(s-Mn$Nh}jR2BJ!%~eqS^Xv~ zIe4l#;n*w{W(k*Q2eulNf|;B!BHu;=;s&VG8Ykuvfd&;Y!LX5X8uYA7g3G7U1%4gM zLVxvx>m^*uhf9%kRzyH}`}O%}bcdx@HCH<`Gs+jd)J=#O2H{B|_1&!m6f)gvN3t zd{T8WBF{p56xdX9R`a8dJT%3Rk`ufw2A3h6%8m!^S2}u{oS|C<$4I9Xj&Hj-}Q?Ru%udNW8t5sB}_vc`1?lt)L z=E9iHc()nwIzJO_4cl%BjcBV;n*|Tz&-l8flqt(Vv=a2?ndv>f?bZRqhrVXew33wM zW_AB_;B}~NanKJUuR`>hrskTurf(AqAzy1Z=1g@@=MV+8k$C&XZXIZhFOgR?LCIe- z^4c0MZh`_$wPjS`b)rg|rG+>Guc$JE(9o=mBH;<8QLHG!YRkV}09)pzmWcW}@Cpi% zy4=$6q^IUHFG?nEf$WUgnyDz&OCY=TU`MKu5a+ND?5UPfi`Z-6?#z6$0g5|kaJ290 zNwOZ)MQhJ`bEsa~M3132PU6ihmy(K8NMkRCt-Y5q>|WLsMVbB$^)OH5-Lid5^G(J4 zoQip-#T^-q05&`3R$vuYkuBr`#{kA#tf<6S*6Arv-C#*A=WNiJ?odSIs`0bPE}ztJ z{rhZt_=t-@&0w?mQR9|G6RW`QF*x1>WPw(Q#wcd3YIX|rKBiLmms_sD z4E9KPrguLk4yX*tf`eiOO(h9Au_rV8TqVI{9tCiY5<9q6a|rYODpUUGD3tS@oFba_ z6-h;eilnGK+=h)LeQw#@xbFCEteA059t6Ion0ud28fW{(&)|lC`X7IJ_}%{=n%sZ- zudDxZ{O`wUi=a}y&bz&eZ*J9{^e~Ap#=LnW$NB+-=>*QcS9!zc#Cy0*SIR;x)RjfF zR8LR@3v^Xz{=N6{>Ap>S>k&4}j%yS|OV|6Sj`0Fnp}3Effqiv>tyFYNjw3wp440q< z`hrXEw;yFMIFHvb zRIxfP?8mn4C^ZKm>Wt@jup))*3tEj&7C=C(#@$R`X?8%@$~%7pABe=+E3R87!GY|KcSASGGKkY5!&HhzjZf7zmgZe(ChbgOOLLIp3jKkExLD5{wC! zP{YDTYJY|ZUXiIVPPeuZmTMDf)U0^N=Fy#)aY}2As4lg?=z#~5AdxH2P^S${QhZqA z#mvxnG#ist;;Mg@mdXr8e0XC{3B0FVrlBerT^@ow+iGwPOf+6KsZ{tN1StcOuO2_h z-=5m$lhtP-ikVO<@Dlv5fSC!DsEPBicC*z-DAo5TTa~Xil#n7AK-*v*4VEz)hbo84 zW97%ha49WROzbv4KVJ*J6nDi@!>Z#`71K3n{t9|0cI79{G_Sk)R`gUT$+Hj{z~Lh} zHbT+r!n4*5z|t`1;xS`E(7Ae-&hGtLH>1LSwr#canf`h<5)lM)DA80_*XUmW!YWOfp}UFylv!#m z^^;m{lKXrKi+G>C1}}qROnMe#8ES_JhG`ozjPP4-FC!)}^TLw=^ zK-5<*3Bz3xMYIe=VF8$rzOG1B&uDHe9dseZD7pERQ+lif#~piYS-B*~*SK36w+n=& z*5qjhcCkehJx|nJk!XjaE^DrxW0K}-u66UO<~r_kmFBugSCi(tL|2pMx=2rx<~p~l zi<;{xS7(~*Ad}&ki6B~zcs;`ur!9Vw35S1L@Is%y#hV=Bn4&dBKDDgLSm}V!hs%*z z9YN#U?4B^f{MTfs1{5U;!fwX2>b{J-9M?tIQzJ*iYs>K^qsVaeBD#-P89#3A`m|*I zdS=f^ggbLXhZX3@sdSDF!e$ug)H&hn+NzC=W4K&z4)daC4@zN@C#1t*Z`5G-dU~0S zrmT}%_TUq7W)i0t(~L+}A`GbPm`o4qiqXURVRMh!;cB57c??N^2062`GKOUM2s*#8 z?I)am@Nb{Ry`>8^`zZ?Eo@T1`Ez|%|h2fb?WkIyW5=FSj(6QY}@pgl8z!2Fhqjg%2 zS_~8GPtut$YB@(F96+Yldy@Q#%ppmpA6f$+W|EZ6nTj&n$=81+| zK4u*2mb~(r*4WOnpx-y!6EIBQ!RjUoNEJ@(84mPYM?2 zTpl&~AUbdZl+JjkN21RZPcntV#Q#@NtNiJd#llRev^cvrHj>3Ka7tDhBVf^xQM7iB z18!Kxd#J5J#q((7mf&@xkuQYQS;ImDpOgs+4X+#JM<&vdTg-~ujUkHoAnv67@v?pS9 zSYZjrhJfCfH_yN5g#>ajwF+5xj%zZ5dz$HI9?4yk&?MpDlCPb1v4q7kx_QlFneKCq z#j;FSlXI+xn>(suu`DtuoR$-Ic2^fImU9Z_nd!jaL3gtQTMG1O{r-+kpB0i(K<%^E z#q>!mfe?QPlhFk2`x90rbR>1yvMsok=X<)6%o*tYag>b_a#w2e7cM$Xdrbt0p}Za_ zc4__Ef>e#dufsV~>mQtU=1C|^zyi*tejfO+-*pcfDkn}u%kdN-t*_sWk$vu(o+i>u z4NhAR>QE{aVcp06-IxvJoGwjRQfuuoRGS0c8OOX2ydiE_^`8{*T2;YK)x&NtNkRX4 zlJdJ$h`xg1{;_TnvOIsy&T5>hoerN?pzto9j_#jN_QE=M>Q>9(O0<`tF?xWTA3ap^ z_`RdHaD47}=nS2_dA=RrOIJ!(yx+pgA^4x*IDbQ&T0idnyN; zr>u5C6mGk`WR}?|EWVHHQgZfKoTDxXU=ygMcUAWKEQYtfCU@$J;G!We!tm zTEWTk=O6T4B+dd3&VXbsevU@;0f+;H8b%-(>`SHaEY|#vAUtEIvmNKlbcFwP9HnA2 ze?yeHGyT8z7@i98q}a0s@@McnXvGi4I>F3xHRR^m;{(c>W7CcF*<5F|Kjj5}aVm5j z=9woOumEZD#_BA*9`=x#jaStQS9Is9n6Xl_Pq?pZsa<*cLogIiX=q|9h$eLW@ls3O=1lB2Fw zg_TCM_*TnDyedzn>3D`GmSr+RILsXW=J+o&h=(J06o;4AzHUMQR5i~!fid#Q?6>cN zF>^3vj(OtDuRP?6zs!k9uCIaWuZl{<87#1&(z^AN-&%0vhY0JO`EKIT&8s|U+~+DD z)S0updQrOOcQx^#B?k4A(lu{T7kSW8I@Wqb3Ccm6FBk+u??SV9@sB)cY0<2L7~ zOc^`_U8!8d^((t(gxp#p7zNH`xev>MszaP3a|?#w89U&E^lO*~3yj08Kw=qMWmrP3 z=APW~L8jF4!l44(Ek^PI{+{j?%R}0H%k&+)nCM$4sWI^^q=@!+)s*PI9C{%a-OsRc z52EgFoI5huEZM1i#VlhXv1a5E)E z7U7qN$&?Sh47B`|rY1+b8~LNh!O#aANaK*-hJ$7Q37H1j*q7~-7Us=NY{ib@-J_sw zuKN)Zt-GAh5X>Hm-Uc((fbwn*zigi2CMkLrwZdiE3Z=l703KG1^OTjElYPV_$4kx~ zV~l&z%R?@q5sgdV%E24E@=|LntY>f)w=xkGvxF(B63eWJ5ISaVPvXTq$4{KI`&`G- zmgwr4qb<*(E8XkkLAR9l;=n;rHJP1F$>ldri8I%PqZ~Q!E>h&ik z_zt_GnBg=aT$Xz8Q4C3&fk4r!-XarWIP|*!D-znRVBLZ85LZ2%_O_sP?#K6G!$iwR zcfq1EC$SEy9}OX#RPDaK?P(7gX5vG5-Z;9Q2XtItfu{!Nyy$!x=gg;?(amdAGu`JJ zs#&J1K{bnXHK=Bpo(9#-?&>1d9J4%xd4X#2v3>B60%2M!olq|SBb0y2I+;oxPJ74k zX!UK@HByq(*Ru|WplTC^z2EopEzlLgOh&X10LQ&H)O60#Aw|fQfqY~bXvL({Dz=4m z`5<@5fD7iH3PN&~mS0G(a6qz#-p6Ij9fcHjpB%3~N8g~NHoBva0la^!gGjIOa0gYmXwl$|Vo zd|OC`G^PY$AsJyqw;^LQ0?X?6oq0D!g}DKFYPW4RD;Fn&tZXDE4&AKejg)}iW#Mz` z$jEgX@!lShD9={Wjt+`+hIMyW3q_cIo{4e=23um=WfP@y=Ch`8tJhf5IN>^h-iT&* z_3S2DpsPusFEJ=Q#$Kc2NcM-2Wyv0hFsBB$&QMA7 zx5mvV)2I#L52wkb2~0RZb@2&f_zCl1QKxXAIA%tH+8(jUY^VzC4h}@)EcDxHc#ObM zZR{aSCuQ9Yy6e>5mpYebUZAz)54Bti{~-SORq8t`%!ngMvh|+Q&c|;) z)6t!?0PComSLuD+r?+Gv83|tIQ&z+D^W$6o5tAozF%L z7g+}e6-!XiB}m&T=xR<4tw4sA+^(~U=o7!hiCos=0mJ*}B!tq5pxO>o8HUJ2mJhy znlYk6@EvV_lV>6g4Tq`SPIb54OwLAr1}9)OBcD!9Evlg>#zl1IGkQ z(=(Yz1D<}&SU#HLc~rGBawFlN<#|cf>iSXVXRxculVZ61Fq5}twDY*d6_8oE-?`sk z=N6r_0Jo@{S4n)_=PGWoNLSB_#sZ_7xWy8KdQmiH4(cMe;Icw#q~j-v1fm*;?MRvu zY^)Y|Nn2QeAcgZ)EfKsx4U)75obbaX|MZ^pe21T8^-x*d%|GNQaI%%Bg|q}1#xHbv zwvi*{d-Q#=l~5SFcjNL;XsW7~Ul{n2Y!eERNfF0E!MMwrTjR-Zc{j$-1AtdIY@HQy z?;EE*jg$T2=Rw`BcRCwf>H~^yUVs1e?vMZS&pv+l|NhV8zdilohljuXe*ZK;WB8};yBX68DpBzUwuaV<) zpKHi*nXV?6L=!M~RD&EB8Pr6Mv%9)Tj&>F#_X^)9Sp#wtSqyBgq=p1p7()*5t=Qf; zIuPEYzM~UD9(JO*>hM5k*!I`Y|9*TsZXryHlMg3wl^deT+JVnD03_ZK?R2z6!=!gd zEa1`l9bIJAPe-^QI)5`$v%LbJSo-<}Q8i__w`S+~xa;M$H8}2a4Ph+N(IATjIvPZ= zL_fn6p4rhwf?&NcN|PWBlY>TH(ZPbT9BL3jITcgn|-V;1ke0?XHw+?MBOV?s^M z1rO3Uw>&8!DoIg)K1kkphbvBAlvmd0bjru;^X-?{ybC7t>dR|>I_2X&=dAh7HE^yY z2kV7J&y!n(dM;BQ-Mq$?r~6#PmY3;jG9P-lxucrQhedjt{FHOMy2zfDdk{$!Yahj| zf&;Lk%b8OjEW3iMO=O}^duQ+qr1t0WA3ywMBRJrDE`nT&%xiH>VRN*^O~fY$G*PvP zkq?H?S3YJ17rPya&XelGuorU42dACV=<)z?Dr}hJZWsnY*F1nFGmj#`{2nSF@PDNS ziEuc3m^bysna~bToS35wTG)&cIQ_t;pR(pk#bsdx`?v=rsfJrFg$>WZM&7PgVlKuI zFo5HrhVSv+e(WFpY9y9^W=ybGs{Dw?(%~2=TCgsvSzQWJ&HhYTjuI zynuP|!XAx?N9SQ*+3A+(mo1`BdDSA)-6-Mn>#C^JJ-%8Ub#n!_3>xQR;AWgNpCOKJ zUSmDeeXe1M%XBpu;v!uQhPX^mgCWlD>LNoFV-+41ri~$rjSQGXEi#-OkvJGGScw}o z1~$9Lm_}%;9YBWAX0hJFkhx$nCe@{s&J(J|3503;N;+u)Q+xraQb`Q1LUr+Q+iL!? z5LY-@MfGI2aX=17Ce!g_WC&jfP8^KG4-hT>3;xOZk$pHy031X#n0#WS)wB`<#z;?{ zTOozQ%|KnQD^H-CRk=QQ>7f`5->+?XvBje3Ihc#d20$wmZK(N$g$!7>g`!CazL?SC z?gdQF1#t#0s~(%vGG|GI!PwoQfP9>`l0qThg?RXxRS5Lx`Jdrsv3h^S(fiyFV}ar9 zsd-oXab?{JG>=Tzu?4XJjTkm`9&Vq2@KRs{E1*!ciAPp2+#K_*2j~RBvUtwfA+O&u2 z_p5OA_)4^Xh^(GsTyBB~&aSB3bdOz0h(Y5#e^8u)0$P#&Zj#_0M*ttk(UYvOR`k{y z41!l%5LExU;l>dTiE(sZRD5#<%*_tY7fq~j&V1%Nx_OPcPWQQnxh~Vy>ZmssEf??1gHZ$^9e7@*g~TtiX)a>0Gqy4d{*{8zKA2IYQ}e4-k)fpMVWJJ zV`l<82#VjCkF9MY@>q}3D0U9#AYR`iwWtFlhIcc2{<0Q1zL3gbkt68)JVXQ~M4h_p zw%8tqW6w^6Jow?rJJx-0e7|#_c@PnKBTQ}mi92&@ptk-Nu6~DGqFk=FK(V-X1X#PH zyCKJcz7=UUz;X1vg}D0^_$S0Bntk$Ahr!ZuDqJ;eFx>NKQ@=3QRB>NW^ZSw(Ix7^l zxdM)-I>QyAs6^m=Te4fdMn_{T7d#eta)Ikbx|(dsCAyky$whj4#=Oj&s*BV;%4;QP z$QdL`h(!~RRc0EoQu4P|m;^$s?GQXF;E{3Ul5?p&c5TU=a}8={PX3Zq<>`LRSEK+W zGRT4QQ#(k^s$-EM*;JZQS7z7!j1dcJs5FJh-lv+WAJcL|7q=--)7MT?bYl#bIL?>O zz3&NiEC7aa^n{p3mv}^;P)8e!LR8Z|`O^}>agYg{;&bpXTE+-c`+P})PMBjCB6v-z z399evo5hGy8a-I8S$xurnk6FY{_JjDpzD}l;JE_eK6}KEFvUNpVvYgZIdO%2`Y-cl4>*$jU9i;9lEmb>@{agXL8xrw?D{GuHpZzQ% zd?)s^OjqBvauKnAR=KDqU$W1lq;&)Tjn-ZQs5>uGHBjwzKCB(NbxQSE?wfa{em>D+ zVxr5`4~E{zgQ+Sp;d}|#i=bIdDy*Rvk@oa(8P{yHPngPw3PL$95)6?uXkQ9C_moyf zWcopFDF1@=c2vDN@%8YdvCbjj={-f?k$2wuT2>RB471Y^oQiqjE*^nO5)4_lxI(rT zb;(nWnnOLf3>mmO(-uaUcGJ*5VHW4`0Gngeg^`N(l((pUbTLed<oQlb9H8!~-0>k-vkh3^2_}B`fmon%RqRw~Q z2WG*=t0nM7fmn#G93=0gs)5f4gH?1bF99Wi!L>6C9FK<0%MsfgrO1@e{MZ>~7U(?K zKy}f0bU2q7GI25J{j`M9=9(^Gz{7;O1>?!M0%PSg@?CRL?jN6vxm^e3>6d;U&K2U5 zt%->k1fz|`#<-)m!%AMbcGQ5Q714my)Z;zR<1ZQXyqc$rT!G5FF_7<*fs_GnGclgr zOHM_s1~!NOp7SqRUB;y}XQ5uqYU$TCqBDK6@qlmJ zH!28nkBA4V=Ip6iS=`cCh1B3|*Wdp_xZma)xL?csW^-5{ELnWH)kmrIIsJIe&Cmr$ z%(tf~*d>pn@6+InvOt7ZxZ4ZF>Xgncvh41j(cSBmQg3dIGCqt=&s+ajAo^}{ z?)#K;MG;~2NIFjF3rl^R^XmGYw@j}<_T850_qj|1TT}l(aZTs+@$WGZlz+d--TZSO zqpx4)Le_}^sLX5>{o}TooWjF-lOO$yPGM>qjgeWj_833)GJd(r**ixy+FpSyywTkE zNplN}hPUlZTy;A>l&k>mlBx0Q(-e*6fpB>I9U^6zKXg&w7aPvG>8MuWMSU^2PD^w) zi+-*EqTT4{`=uXAJG-THtG5xP4ZWA@Z`QiMVT6i3e=(E(dk*8}l;Snwe8=ZUh(2K8 zcK=v;8ezDH!)LO}KSJsqRQEk26*Qg~x#u+4ErwMTx(IHp810 z(6vzzcnDAJ$kpcVb=2JK{b8 zjYXGHj!yTFHhiCuE$s#ZOoT3l=+QiS5Mt|`{9yj-`srtugJFBap4^1i7k1uIY!tKt zd0214CGZxlxT&;km6pM#loJy9wCK;J8y#D~LBtNw5@E6uGEkqL@+@+?eELBi;lqif z(eY^_9HfA726DU40j-Da2A+f7;tmj3B0vR`+K@&v)V#%iLrdHi{}&d&A{$aX&UQ?t z6Jhfb2=5?)!Vs!(P|ZblcY7?+Q$Q)A0gOM;Ge4Je912wJq8GkTt4iUb)nMVFD+3u~ z^5o0odF)vVc4>$20802itDcsYBdpKDoP+Pbrxh`NqR+3wQN6w425zME1yUkMN|*XH z#!n_tr`l-=C{QgdGT>Yp&GiOBpdoaSoU!nQ;K`9r`Hblj#HOT(bR|`LB11sN$Pg`! zf>`aoC}tj-C^0e!xZ>&XGwAxwPRbOy^|g@FEi`{4r7w_Dq4|RvQXfOr-Z4s!SBK{F z9=sl!ueU2h^P{tmL-Xi~d*dq+O}9}0jh?v`V>gYLQKp zG2zQ>cxJzKT~%AYt0|WSOqEKuf0T4Gz+h5|;a}BQfNT@Ote9H~Ec8SIEr2b|t z;6}cn!fgV{gyC=R_)*#l>5xup%GOG{);pckutKhKKI9ooo|c*dwMI4?mO(V!atYOW z&1(_tE;Jd4?mZkFMV7M4m>Z~bQKta0?K)aEfWGVpqTQD%V^-YyHYq<($}AV;4aITe zKwsuSskLPo-Wbp`1DZo?yBm7rMr&W7HG3*aBZKk&Bn+3_mpb=YCY+3w0s>r&{umWJ ze0~ybOUm-gi<{9OczvLpc#P~n7%6c~uE33%S2zRcU>OA^_EQr`M36!)=PXV&V! z0()WaD0N7Jz0+s}AAEjVg1vL*r;?6ay_(5B?&FLGV$OJczf^*~GiP@-WwI~P)qr&` z@_f{>c5j$FsFuy2{>NV)e)qq>u=@AbTOO5^#)?wVSgDBT$KmEzQDIeWG+q*G+9G|a zjrMVvIK8)R4^oWfdvUjj5>O%A1zL7OS!HdUP$I<0tF+4AcUkTQ!rK<2Wa^f`GbL=* z?nJ;#uBr#F(>68fXtlql?OH}ENBO4I)#tJjWly@hOGl!I_Q$u~!EP)_O+_GsZL`^t zF;Xxh9bF(^&b~iJ{CTu6lFf>=4^KcDE)7<~Nk>%3C>%a=LTYKpCpxov{MDYI8{}91 zwVq%WgSi6a0+_0Z{Ob&6oHL)njBZ}z3e$bAVKB>dH5kkyT@41aOizQs%BCh}(Rf7K#iyY_7XOW|u*I49qpKDm;GF?qNSQ9XJRFe+2 zNKcavHn*#bEK*sCH@nYx@9nHry{^<5gp+>JCU%v%kv2cF!m9&PbuFKtvqdsPf(FuR z6s=8VVqZZ2?Z&or3==w8wfd^}1=JMoBK%*~aE3kNH>OG*tdCF38OpfK*ftCVrsBI0cAL;fio)p32N(>)2z63wG=-#Zc0X>Rq5Q7Izj_9z+r@NQ-*n} zn9zEoIvCKQt8>MIR!u*%z#h9RkWOQPU(j48a_OYz0|=&B+5Uo^Y8N1Y=OSNom+f26 z#Am!}PpJh)_3e>mB_W8bOcGWCoDmyn`*^G_g)CO&!ocC5&lk@{uF8UP5Re&`zm?B$ z1xd0A=0Hj1${*hNEDb~%c`<1aQX53uSyF0w+sGC@*xy%JLg2b%$jCWtuYS-WlS8Kw zrQr8)GBDQ!wcC)%AS=uYZgMP8AZNWB34nLHZW_w_U|p1ijDj+@A+PZcZ)5e!JVPa$ z`5w1$jGk6)R{bIR>_C?lpNG4O7CkNiSb6e(=F#F6z^fZAexI~><`1ZR!tl{0k1EPb zoMfXX)(DsIu7>-KZRlJ|m? znj|jy%Pjy54_Z8es!`}+cmpHc z;SEffej+gEk=YfXtQ(nqpJcXIM?_)>iI@Ht#E}3bo{|v6O&TE28l{wXE-_b`xjQjv zPVJ!Zh=Zm^WKrL&ZMqO~G-Bms6A`6mZ6btswP7mN$rTIayAmtF}b+k+`0< z&#B(ThtA7cezPk;T{lwvK1p#h3MaEe-TRSgA}0lMama;$?#P80V!MrEYY2i5{6(gb zXJjOKR=8?df1eUqW>+-pq+vm#fh1BSWc8z}$<|c1Wiq^8t=lq;Rn$!4^3-=VYqcK8 zwa5$2GZ3y zpYsId70|F7ReqmTDcQ>!{+v~Z$SiN>oE1+_P$-EEX)gqo)J}qmy!y#_M8=4(DvKl< zr1L0>gfe8oWWD*R1Jp^4Wb`>z73CK@%msv%LzA!~RYx5{eGQYb+yDRV-P>*>Npi;V zeU!oYb_S++5((J8S@=>fFn5M*uNDxzi_y9PzrBC|EUKqRYDt_fZhP7)pqnWc$*e=h z@r%fa;UqpaK`~ewyC^mmxlOaG`bb3&&oj+V--YN*9xPU431GP-M0I3S!5EB-YZ?lf z$E)`vDM1}m>hh~;bq`12FB`d&{4lR@>Gq5isf82YCnp{f`nn2{Pcrik|{_X zQBVnokWs2BWRx#giDG>8qch>#)L_^8X*SBO8>T36I(;@2DJ@9`! zu-uJ57L$ZW1qH~^i+)|q;YK!)$+%K%K&q%jg6!!a6*uh31 zl4rOPqZSpXU8ewl$&XQMwS%Hol$t3j1UL&fa*~g@(H3sBRrP1dVE811VXHd$IEX||vmFJEX|9wpF#0HQ4~+Z}*h9_% zOF-CZOYhe_g-O6c8o5uLko=5ar7h_pmY-4dy81b_PvE-jU4U$Mbw+sgoGY6`wMS}V zMu>lTF(y;Az&Li4@?qS8kBzt55cw`Y$=Bqj)NuA=kQs!KXr=+S+M47lxi1I9f3W<5HM?bbGt+2bxh)r2;ge%vuT$sbCvoJqPzJQa3Y<4&9e8%7 zk;hg6H(i-+$YQqGXwn|-V#wNnfeQg^8hEi@aEdL{iW2f80OIP0v@>%!{dk!DPo$6} z7|owJ4BxBn<~-y?8@J=ftxS|AVxDA2yDBtv3~0P5*( zU@hCx4^ot0M1dudthAfv2tPTJGRAr6#yJUIi%_@#=JE{+g*t~0p%C7L+7wqn-$qmy zwQIVgWsg``VKR_lF|R2}8Kvjn`y4gnKEPxSARmQKU zQBBEGzS$u1YFtjijVBqOJq*ceuCE9lu}TQkXNW8gDJ55#3FVG^$T0Bj_$H~7 zML;Cs)p(Z92c?7wy3}DABvx45WW-_O{`w9U2-zA~LYOc)Vahf8esm9H9vpF=qGSYN zyTfJUbPXe_p~}nXkPcEXr{<%)hy6VETawTg_Iru_DtJlLB4xTHFIjfg!~%Jz5T`T{ zO_cpS*d=o}Bf3>cEayY`6CTV`awv!cggG`QNGNN-ce4L1(#Ux#Q?w zYgLBl7z#A?WarCtr95SscatK3C$^u*f9Ir|EmrZnw2F^_VJR+%jx(5#ra$*l6|oAl z58a2V19zFaYX$mu+DHGsbsv?Gd&t%w?3yP>GB6duLLDCMHdnj{-$Gvh;S2qc+zk%qovJ&li(Ynx$LKPPQ&5en~8D2T^qDBlK^aN>~e2{6&Z zJ@vIqmjiE4_*NtSQX14prTGB5(6fk0unxnU;R}Hd=i*If=>9sCltqoFGQG8b#6H>R z;au=7@`#-}5@EneknVwRnR*)GT+LS&0QlzwZ#Cw2W~jrrnBkgW%T5w;C$Lut&FP6{_rK7V+1D^HRFwL?DbB$6=U@o>ZC!5P05|6!|!$kw+@~`>K z!CbYn3+Lipu(ff$r*cYh-m}x$>srbiRUGQ-4rK-(Ucb* z$WLbX$2_5MP6A(0b#-`wP|8t3Q0j3joPZ#PNuEshUY zh~vW*gy6sq15iltUCp!Q_va+fEo%E+s_k8VDHT@%!c?sUkix!?no5E~@!pK%Nu^O- zg9B*uN$IhXOTrpi7KMHBNW4PYx0%w6lE_ai)p$GH+t`ksED{uVjz%!Z{1Z-nAOyx+ zZf=||49vTI{#}zpPFKf^9XlIdO9PL66Y4O7F% zf-W6JxCwP%nxG8h_%f%9SeDG_ohc&R^-njQfe|@U7IGvHm9!z=8xLc1;*Q}MjOrcj zQ1FBX%E|K%CvY(u$9L^^!dh%D@66zn&AcH0e#!lLji8ww6p8Tvx2t*1O3bMU zwLd2pZt;B<6LOf2-<}D1ld6JbUf-6H0|A5#u352-A`LvaZ98m|Wc5rNN4F3C0d9~| zXY@g+zp%*Kwt>=br=#;q&Fs&}g0q|PP2hffXFhO0rg_avn$GjOmsHqfXV>=|+;Y}b z!#=&pRKs_>%uK^Rojui?JMYQcA2cUXf^>?MY1cO*W?S02L{ZQ@18N(_Cs<|_%j?S{ z0A6puoU9IqnF(@>oBL@~G_qbRw7jXH1soo{D6_4-W{n#g&z!;urz3#Ek@~WQm8YaP zP`morHlCW36gC@2vO~Fb+j;4s`!mwh#uB^{(Hh@b7~?HaV>UJ43}2w;L9?fNn=uLk z@9wt<*K?d$oW?nnS1W#BN5x)4~ z{ZT5-!PZUz4^~WJkD@3Vb|O}Ud@N60ebeT#L#+HWhW35Oe>m*y(#qDZzCwwu8RhfL z?&~wsR2Ez1ecCF!+CZ%kDmt?@vC;;L80gu_?cCklOeiDMMi4Sr(jcFcnJxBsb<30v zae>tL3WG_Ww+S-gjihyo#{-h8@2g$r`(u;xu*`+h_u{lH{PCApU$%wn%IV6(meMZ8 zE9K!DdL4c%AXNZzoU79ba^>FA4?JQQWQyrp$CY^Ff1Qqq{%H)-GwW6?{xt5}SFw)hA)4~9Bi!|c+ z!>gwt*U@XYn0qoFr;~NQ?$9x5ZR3iZZ(Qtj@gup8uiko1|K_Q? zB~NCt@LsU+HVKD2ZKhdpi3zQ5OYmwq9zO`N$PqgF<9;CRAjJoZDlOaK z7t;@9%t&GLzKIO;$al$>S;+VQmV9qEH5%M*F~okezPsA5_aFLe9$hb)E(=}%PU-q) zSH1EG6;Y@1kh)p_1Z zn>o6>b2Mi`vlk@6CvT}b%_i=)aKt2-Iow_ptpAUwkUy|x5_d7za70Tr$b zWdVrTI@BNvpzp7~Z9(!rlwt!3sd8LDZJ0-|OB{Bg*B9t@UF2U>h*2OPTwXBfuIylF zrf0SVJ0i(QbL<<3^Hm19l!CGcK1An%n`IIx_XMtMQ|l~ZJ)99oU5wlJY202_a&vQi zPmGe3f=ZBGsJkLf4MU2e)F@WGsphxd5S~8{@w>fiV+}GUm(e$}?SrDF^XT=AAm~D` z@04Bxd{=^?VY@_Vbt>5eqB^Bl9rfAzFlchbY^t;^caaEHcPp`5(yfq*&G`aGZP8CA zGYfX}=yeHnF2=wM#=tqoYc*G2G+wi8KV!V!fWUIW?l+mktM&ax5Z^eDkk1ImErR!b z3f|E?fY_}U+e=oh4D#P*)dCXQEVcT;XS=%JGj|o3nMcBBgya?yexD>9av)cbts5%v zf~^~xu*=qEXp|};^KXJ09&O!`7@n=G4$1^1jNK3NRb;_V!uU?p(0NpRMgVT1;&)2L zI;?1vmM9+9tW*aELN+dYc38R}Enpc>B}U}2Wf^Ay+qW}B^m7aN=GeZ5Yp5AH93>}@ zjWgx(lfc^TfB*dRfBe_q{`i;szx@3DcmMv+-{0&@LR8b?R#mSodD*(t;LnFbD;+xh zfAEK94jmhHyC3v=@R9%Ht*UAxnfEf2&DjKdcoLd87grm$>cfW?X8rS-1TJ z#(#d>m5;jAYR|gTCjjpAE8WLCn_54!Nv0$D=I$DQYObI@Za-W zy{=M<9e2<2F%_REcX9fsH%z&S)zhy>T;=>Usu)U=oT#{;JbSN?cUiedez%AAF^3VP zse+gmomI{4&+-x_YVInxcbs{fPf(-hx4CvRV?`y%@SR*9!2+E1kS&hz0t^cfTY+-< z)8e|;Gl6>gXO~y^pLDYDtxE} zX<6-@(16fdD+6cgBY{RYTejUNiLMWq$`3t0aY#RNpZ0-RQxz6VSyxuhbBFk-EkBZk zK|9_^ca38epR}j7K7?8@ID`hReup#XB*+5XZ8r7#j1fE^bJq^Sw6=tF(@sot$=p>j zVr{R<`sk>zP#z(<45f?$lQ4Me#{3S-c{hoj>1^pFnd=rK>-8O9^;jLtyr)vK%Ql(NQ21R_q6Q?=v} zzlV!Jy^I3Qc}rBEtC7>v;788IIvmR)z_B>(W|3m@2>hG($!|GQMu2#6n+P(Q{n=w3_Ds}ruZglswmf48rEsv;zpPU8+(3XybU^*>1 zVSzn!@AMC_qKtyb*1ETmn+h#*ka?GtgJGRk{FXS6I2yG4@{I_kryaepC8du=Una0n zaaTr!3t~8udKL}))Y7+&A?UH2ZDS%S_SuagG<)6ip8TRtq;i^Y6y ze~I*1KKEu#t+7aY%6wC0c6X~lIu7mpLvLV%IubeoE!PKZA6t$Rq884H*#gt%orwV| zujzm*88#hism>u{3e|M5&n-+$H5P_hzCWpG}2^tS$B0NRlM4&J9CLZ58NhMcjeIn=IT%&zV)0xbG z0@L3Qzbc41ohRYe~v)gX9<2qL%v1uedhuM-!!jM={V0>1b>mKCW61jR1?8p zWTuJW=T7xD!RLwnKLBc&A`6kfrXb!kk=rgj5&5@{U9rZ_pmKKIo1(n$TtJjJ&8wn( zoaZc2evzq8w#x;s>SViIVy2VrGIOdoMR`qG7Br6mzxv0A4}bdpyFUw%{ptRH{>m&~ zJ%K_$Zvm|!LJ{*TCjZKJF2FWT^D5hn^PI&t7n$m$94>HGCkyBjGo37;nNz*VHXE+& Of}s4}5tKjt;eP@APPcXd literal 0 HcmV?d00001 diff --git a/resources/customizations/fonts/MarelleLIGNES2-Regular.otf b/resources/customizations/fonts/MarelleLIGNES2-Regular.otf new file mode 100644 index 0000000000000000000000000000000000000000..c9df0b4017c9f17f2eaf8125bdeedf73c7837f19 GIT binary patch literal 1512168 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⩔(ya0ys2(LsGc3 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

    w&M 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�`tcWX5_Xb>+=a^5ZDa|2JkdE?o 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 P>=irti(@DM;XnNU>1g7u literal 0 HcmV?d00001 diff --git a/resources/customizations/fonts/MarelleLIGNESBaton2-Regular.otf b/resources/customizations/fonts/MarelleLIGNESBaton2-Regular.otf new file mode 100644 index 0000000000000000000000000000000000000000..99c9411e83a92eff6cc2d1e758e3237fc6699f2f GIT binary patch literal 1193080 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

    nYzc>bs>XueOm)P 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

    X(T#5~8c2;R!o9xJk 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 f)stwrMo&-b&xKvROEqg&> literal 0 HcmV?d00001 From 03ef33995cabef919bf51d672ff2ca1de0fbfd87 Mon Sep 17 00:00:00 2001 From: claas998 Date: Wed, 27 May 2026 17:13:46 +0200 Subject: [PATCH 131/133] Align left sidebar with vertical stylus palette (#6) - Add an optional left offset for the for the left dock palette - Position the sidebar tab next to the vertical stylus palette - Update the offset when the stylus palette changes orientation or visibility - Keep the existing behavior unchanged for horizontal stylus palette Closes #5 References OpenBoard-org#1483 Signed-off-by: claas998 --- src/board/UBBoardPaletteManager.cpp | 27 +++++++++++++++++++++++++++ src/board/UBBoardPaletteManager.h | 2 ++ src/gui/UBDockPalette.cpp | 15 ++++++++++++++- src/gui/UBDockPalette.h | 2 ++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/board/UBBoardPaletteManager.cpp b/src/board/UBBoardPaletteManager.cpp index 2155e104c..931748463 100644 --- a/src/board/UBBoardPaletteManager.cpp +++ b/src/board/UBBoardPaletteManager.cpp @@ -120,6 +120,7 @@ UBBoardPaletteManager::~UBBoardPaletteManager() void UBBoardPaletteManager::initPalettesPosAtStartup() { mStylusPalette->initPosition(); + updateLeftDockPaletteOffset(); } void UBBoardPaletteManager::setupLayout() @@ -501,6 +502,7 @@ void UBBoardPaletteManager::containerResized() mStylusPalette->move(userLeft, userTop); mStylusPalette->adjustSizeAndPosition(); mStylusPalette->initPosition(); + updateLeftDockPaletteOffset(); } if(mZoomPalette) @@ -569,6 +571,7 @@ void UBBoardPaletteManager::backgroundPaletteClosed() void UBBoardPaletteManager::toggleStylusPalette(bool checked) { mStylusPalette->setVisible(checked); + updateLeftDockPaletteOffset(); } @@ -963,6 +966,8 @@ void UBBoardPaletteManager::changeStylusPaletteOrientation(QVariant var) connect(mStylusPalette, SIGNAL(stylusToolDoubleClicked(int)), UBApplication::boardController, SLOT(stylusToolDoubleClicked(int))); mStylusPalette->setVisible(bVisible); // always show stylus palette at startup + mStylusPalette->initPosition(); + updateLeftDockPaletteOffset(); } @@ -991,3 +996,25 @@ void UBBoardPaletteManager::stopDownloads() mRightPalette->removeTab(mpDownloadWidget); } } + +int UBBoardPaletteManager::leftDockPaletteOffset() const +{ + if (!mStylusPalette) + return 0; + + if (!mStylusPalette->isVisible()) + return 0; + + if (!UBSettings::settings()->appToolBarOrientationVertical->get().toBool()) + return 0; + + return mStylusPalette->geometry().right() + 1; +} + +void UBBoardPaletteManager::updateLeftDockPaletteOffset() +{ + if (!mLeftPalette) + return; + + mLeftPalette->setAdditionalLeftOffset(leftDockPaletteOffset()); +} diff --git a/src/board/UBBoardPaletteManager.h b/src/board/UBBoardPaletteManager.h index c4b96a39b..5d4f07c88 100644 --- a/src/board/UBBoardPaletteManager.h +++ b/src/board/UBBoardPaletteManager.h @@ -102,6 +102,8 @@ class UBBoardPaletteManager : public QObject void connectPalettes(); void positionFreeDisplayPalette(); void setupDockPaletteWidgets(); + int leftDockPaletteOffset() const; + void updateLeftDockPaletteOffset(); QWidget* mContainer; UBBoardController *mBoardControler; diff --git a/src/gui/UBDockPalette.cpp b/src/gui/UBDockPalette.cpp index 4184011b1..31ce6450d 100644 --- a/src/gui/UBDockPalette.cpp +++ b/src/gui/UBDockPalette.cpp @@ -65,6 +65,7 @@ UBDockPalette::UBDockPalette(eUBDockPaletteType paletteType, QWidget *parent, co , mCurrentTab(0) , mPaletteType(paletteType) , mTabPalette(new UBTabDockPalette(this, parent)) +, mAdditionalLeftOffset(0) { setObjectName(name); @@ -160,6 +161,15 @@ void UBDockPalette::setOrientation(eUBDockOrientation orientation) } } +void UBDockPalette::setAdditionalLeftOffset(int offset) +{ + if (mAdditionalLeftOffset == offset) + return; + + mAdditionalLeftOffset = offset; + onResizeRequest(); +} + /** * \brief Handle the resize event * @param event as the resize event @@ -185,6 +195,9 @@ void UBDockPalette::resizeEvent(QResizeEvent *event) case eUBDockOrientation_Top: // Not supported yet case eUBDockOrientation_Left: + origin.setX(mAdditionalLeftOffset); + origin.setY(0); + break; default: origin.setX(0); origin.setY(0); @@ -505,7 +518,7 @@ void UBDockPalette::onAllDownloadsFinished() void UBDockPalette::moveTabs() { - int x = width(); + int x = this->x() + width(); if (mOrientation == eUBDockOrientation_Right) { if (parentWidget()) diff --git a/src/gui/UBDockPalette.h b/src/gui/UBDockPalette.h index aa70a640d..5f9044ddd 100644 --- a/src/gui/UBDockPalette.h +++ b/src/gui/UBDockPalette.h @@ -143,6 +143,7 @@ class UBDockPalette : public QWidget void setTabFlotable(bool newFlotable) {mTabPalette->mFlotable = newFlotable;} int getAdditionalVOffset() const {return mTabPalette->mVerticalOffset;} void setAdditionalVOffset(int newOffset) {mTabPalette->mVerticalOffset = newOffset;} + void setAdditionalLeftOffset(int offset); eUBDockPaletteType paletteType(){return mPaletteType;} @@ -217,6 +218,7 @@ private slots: private: eUBDockPaletteType mPaletteType; UBTabDockPalette *mTabPalette; + int mAdditionalLeftOffset; }; #endif // UBDOCKPALETTE_H From 548537f49af7d1f673c895f009b07bca06debf6d Mon Sep 17 00:00:00 2001 From: Lamis Abla Date: Wed, 17 Jun 2026 05:47:15 +0200 Subject: [PATCH 132/133] Add Arabic translation for StartupHints --- resources/startupHints/locales/ar/1.html | 95 +++++++++++++++ resources/startupHints/locales/ar/10.html | 94 +++++++++++++++ resources/startupHints/locales/ar/11.html | 89 ++++++++++++++ resources/startupHints/locales/ar/12.html | 91 ++++++++++++++ resources/startupHints/locales/ar/2.html | 120 +++++++++++++++++++ resources/startupHints/locales/ar/3.html | 73 +++++++++++ resources/startupHints/locales/ar/4.html | 79 ++++++++++++ resources/startupHints/locales/ar/5.html | 102 ++++++++++++++++ resources/startupHints/locales/ar/6.html | 89 ++++++++++++++ resources/startupHints/locales/ar/7.html | 102 ++++++++++++++++ resources/startupHints/locales/ar/8.html | 101 ++++++++++++++++ resources/startupHints/locales/ar/9.html | 106 ++++++++++++++++ resources/startupHints/locales/ar/error.html | 20 ++++ 13 files changed, 1161 insertions(+) create mode 100644 resources/startupHints/locales/ar/1.html create mode 100644 resources/startupHints/locales/ar/10.html create mode 100644 resources/startupHints/locales/ar/11.html create mode 100644 resources/startupHints/locales/ar/12.html create mode 100644 resources/startupHints/locales/ar/2.html create mode 100644 resources/startupHints/locales/ar/3.html create mode 100644 resources/startupHints/locales/ar/4.html create mode 100644 resources/startupHints/locales/ar/5.html create mode 100644 resources/startupHints/locales/ar/6.html create mode 100644 resources/startupHints/locales/ar/7.html create mode 100644 resources/startupHints/locales/ar/8.html create mode 100644 resources/startupHints/locales/ar/9.html create mode 100644 resources/startupHints/locales/ar/error.html diff --git a/resources/startupHints/locales/ar/1.html b/resources/startupHints/locales/ar/1.html new file mode 100644 index 000000000..9b3e518c6 --- /dev/null +++ b/resources/startupHints/locales/ar/1.html @@ -0,0 +1,95 @@ + + + + + مرحباً بك في <bdi>OpenBoard</bdi> + + + + + +

    + +
    + + +

    + إليك بعض النصائح والإرشادات التي تساعدك على التعرّف إلى OpenBoard. +

    + +

    + OpenBoard هو سبورة تفاعلية صُممت من قبل المعلمين ولأجلهم. + ويوفر أربعة أوضاع متكاملة للاستخدام داخل الصف. +

    + +
    +

    أوضاع OpenBoard الأربعة

    +
    +
    + +
    +

    لنبدأ بأول الأوضاع وأهمها: وضع السبورة..

    +
    + + +
    + +
    + +
    + + + + diff --git a/resources/startupHints/locales/ar/10.html b/resources/startupHints/locales/ar/10.html new file mode 100644 index 000000000..6485a31ec --- /dev/null +++ b/resources/startupHints/locales/ar/10.html @@ -0,0 +1,94 @@ + + + + + التطبيقات + + + + + + + + + + +
    + +
    +

    الوصول إلى التطبيقات

    +

    + يوفر OpenBoard تطبيقات وأدوات مختلفة. + يمكنك العثور عليها في المكتبة بالنقر على + Applications icon. +

    +
    + + +
    +

    التطبيقات الافتراضية

    +

    + ستجد أدوات هندسية، وآلة حاسبة، وخرائط Google، ومولد رموز QR، وغيرها الكثير. + قم بدمجها لإنشاء تجارب تعليمية ممتعة! +

    + +
    + Example of using integrated applications +
    مثال على استخدام التطبيقات المدمجة في OpenBoard.
    +
    +
    + + +
    +

    إنشاء تطبيقاتك الخاصة

    +

    + كما هو موضح في قسم وضع الويب, يمكنك إنشاء تطبيق من موقع ويب باستخدام المتصفح المدمج أو من خلال نسخ رابط URL ولصقه على اللوحة. +

    +

    + يتيح لك ذلك تعزيز دروسك بأدوات قوية متاحة على الإنترنت ويمكن استخدامها مباشرةً داخل OpenBoard. + فيما يلي بعض الأمثلة المفيدة (اسحب الروابط وأفلتها على اللوحة لتجربتها): +

    + +
      +
    • Scratch — البرمجة المرئية
    • +
    • PhET simulations — تجارب علمية تفاعلية
    • +
    • Google Earth — استكشاف العالم في 3D
    • +
    • Flockmod — الرسم التعاوني عبر الإنترنت
    • +
    • Duolingo — تعلم اللغات
    • +
    + +

    ...وغير ذلك الكثير!

    + + +
    +
    + +
    + +
    + + + + + diff --git a/resources/startupHints/locales/ar/11.html b/resources/startupHints/locales/ar/11.html new file mode 100644 index 000000000..6ffd56704 --- /dev/null +++ b/resources/startupHints/locales/ar/11.html @@ -0,0 +1,89 @@ + + + + + تسجيل الفيديو + + + + + + + + + + +
    + +
    +

    تسجيل دراستك

    +

    + تيح لك OpenBoard حفظ الصوت و الفيديو الخاصين بدرسك. + وهو مثالي لمشاركة تمارين إضافية، أو نشر مقطع توضيحي قصير، أو إتاحة الدرس للطلاب الغائبين. +

    + + +
    + + +
    +

    الوصول إلى أداة التسجيل

    +

    افتح أداة التسجيل كما هو موضح أدناه:

    + +
    + Opening the Video Capture tool in OpenBoard +
    وصول سريع إلى أداة التسجيل من واجهة OpenBoard.
    +
    +
    + + +
    +

    واجهة التحكم

    +

    تظهر الواجهة في الزاوية السفلية اليمنى من اللوحة:

    + +
    + Recorder interface (bottom right controls) +
    + +

    انقر على الزر الأحمر لبدء التسجيل.

    + + +
    + + +
    +

    إنهاء التسجيل واسترجاع الفيديو

    +

    + بعد انتهاء التسجيل، يتم حفظ الفيديو تلقائياً على سطح المكتب في جهازك. +

    + +
    + End recording and save the video to the Desktop +
    إيقاف التسجيل وظهور ملف الفيديو على سطح المكتب.
    +
    +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/ar/12.html b/resources/startupHints/locales/ar/12.html new file mode 100644 index 000000000..588108d3a --- /dev/null +++ b/resources/startupHints/locales/ar/12.html @@ -0,0 +1,91 @@ + + + + + المستندات المفضلة + + + + + + + + + + +
    + +
    +

    إضافة مستندات OpenBoard إلى المفضلة

    +

    + أُضيفت هذه الميزة في الإصدار 1.7, وتتيح لك إضافة مستندات OpenBoard إلى المفضلة. +

    +

    + للقيام بذلك، انتقل إلى وضع المستندات, وحدد مستنداً ثم انقر على + Add to Favorites icon + في شريط الأدوات. +

    + +
    + Adding a OpenBoard document to favorites + +
    +
    + + +
    +

    التنقل بسرعة من مستند إلى آخر

    +

    + تظهر مستنداتك المفضلة في مكتبة OpenBoard, ضمن + Favorites Icon. +

    +

    + كل مستند مفضل + Document Icon OpenBoard + يمكن سحبه وإفلاته مباشرة على اللوحة. +

    + +
    + Viewing Favorites in Library OpenBoard +
    + + + +
    + + +
    +

    المستندات المفتوحة مؤخراً

    +

    + يُضاف كل مستند يتم فتحه مؤقتاً إلى المفضلة، مما يتيح لك التنقل بسرعة بين المستندات خلال الجلسة نفسها دون الحاجة إلى إضافتها يدوياً. +

    + +
    + Example of recently opened documents in OpenBoard + +
    + + +
    +
    + +
    +
    + + diff --git a/resources/startupHints/locales/ar/2.html b/resources/startupHints/locales/ar/2.html new file mode 100644 index 000000000..79237974f --- /dev/null +++ b/resources/startupHints/locales/ar/2.html @@ -0,0 +1,120 @@ + + + + + وضع السبورة + + + + + + + + +
    + +
    +

    لوحة الأدوات القلم

    +

    +تتيح لك لوحة أدوات القلم الوصول إلى الأدوات الأساسية عند العمل على السبورة البيضاء.

    + +
    + OpenBoard stylus palette +
    + +

    + ستجد هنا القلم + Pencil, + الممحاة + Eraser + وقلم التمييز. + Highlighter. + يوفر OpenBoard ميزات لا تتوفر في السبورة التقليدية: +

    + +
      +
    • + + المحدِّد : تحديد الكائنات والتفاعل معها. +
    • +
    • + + الإصبع السحري : التحريك أو التفاعل دون الحاجة إلى التحديد أولاً. +
    • +
    • + + اليد : تحريك الصفحة (مفيد جداً عند استخدام التكبير). +
    • +
    • + + + تكبير / تصغير : انقر على المكان الذي تريد تطبيق التأثير عليه بعد اختيار الأداة. +
    • + + مؤشر الليزر : الإشارة إلى العناصر دون التفاعل معها. +
    • +
    • + + الخط : رسم خطوط مستقيمة بسهولة. +
    • +
    • + + النص : إدراج مربع نص للكتابة على لوحة المفاتيح. +
    • +
    + + +
    + + +
    +

    شريط اللوحة

    +

    + يتيح لك شريط اللوحة تغيير لون و/أو حجم القلم وقلم التمييز، بالإضافة إلى وظائف أخرى. +

    + +
    + OpenBoard table bar +
    + +

    + يمكنك أيضاً تغيير خلفية اللوحة بالنقر على + Change the background. +

    + +
    + Example of changing table background +
    + +

    + تتوفر وظائف أخرى مثل: التراجع/الإعادة، إنشاء صفحات, التنقل بين الصفحات, مسح اللوحة وغيرها. +

    + + +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/ar/3.html b/resources/startupHints/locales/ar/3.html new file mode 100644 index 000000000..576f682d6 --- /dev/null +++ b/resources/startupHints/locales/ar/3.html @@ -0,0 +1,73 @@ + + + + + وضع سطح المكتب + + + + + + + + + +
    + +
    +

    التفاعل مع التطبيقات الأخرى

    +

    + يتيح لك وضع سطح المكتب التفاعل مع نظام التشغيل والتطبيقات المختلفة مع إبقاء أدوات OpenBoard متاحة فوقها. +

    +

    ببساطة ما عليك سوى النقر على الأيقونة التالية:

    + +
    + Icon to activate Desktop Mode +
    + +

    + استخدم أداة التحديد + Selector + للتفاعل مع سطح المكتب والتطبيقات الأخرى. +

    +
    + + +
    +

    إضافة ملاحظات على التطبيقات أو مواقع الويب

    +

    + يمكنك إضافة ملاحظات أو الكتابة فوق أي تطبيق باستخدام القلم + Pencil + أو قلم التمييز. + Marker. +

    + +
    + Annotating an application in Desktop Mode +
    مثال على إضافة ملاحظات على صفحة ويب.
    +
    + + +
    +
    + +
    + +
    + + diff --git a/resources/startupHints/locales/ar/4.html b/resources/startupHints/locales/ar/4.html new file mode 100644 index 000000000..f432e0db7 --- /dev/null +++ b/resources/startupHints/locales/ar/4.html @@ -0,0 +1,79 @@ + + + + + وضع المستندات + + + + + + + + + +
    + +
    +

    الوصول إلى مدير المستندات

    +

    + يوفر OpenBoard مديراً للمستندات. انقر على + Documents icon + لفتحه. +

    +
    + Document manager view +
    +
    + + +
    +

    إنشاء مجلدات وتنظيم عملك

    +

    + أنشئ مجلداً باستخدام + New folder, + ثم قم بتسميته واسحب مستنداتك وأفلتها داخله. + وبالمثل, يمكنك نقل مجلد كامل إلى آخر. +

    +
    + Creating and organizing files +
    مثال على إنشاء المجلدات وتنظيمها.
    +
    +
    + + +
    +

    إدارة الصفحات

    +

    + يمكن لمستند OpenBoard أن يحتوي على.عدة صفحات ومن وضع المستندات، يمكنك: +

    +
      +
    • تكرار الصفحات
    • +
    • إرسالها إلى سلة المهملات
    • +
    • نسخها إلى مستند آخر
    • +
    • إنشاء صفحات جديدة من مجلد الصور
    • +
    +
    + Examples of actions on pages +
    مثال على إدارة المستندات.
    +
    + + +
    +
    + +
    +
    + + diff --git a/resources/startupHints/locales/ar/5.html b/resources/startupHints/locales/ar/5.html new file mode 100644 index 000000000..cc1ab9b80 --- /dev/null +++ b/resources/startupHints/locales/ar/5.html @@ -0,0 +1,102 @@ + + + + + + الاستيراد والتصدير + + + + + + + + +
    + +
    +

    الاستيراد & التصدير

    +

    + في هذا الوضع، تتوفر ميزتان أساسيتان: الاستيراد وَ التصدير. +

    +
    + Import and export area in Documents Mode + +
    +
    + + +
    +

    استيراد المحتوى

    +

    + يمكنك استيراد ملفات PDF (.pdf), + وَ الصور (.png, .jpg), + وَ مستندات OpenBoard (ubz.) أو + OpenBoard مجلدات (.ubx) بالنقر على + Import icon. + +

    + +
    + Example of importing files into OpenBoard +
    مثال على استيراد الملفات إلى OpenBoard.
    +
    + +

    + يمكنك أيضاً استيراد مستند OpenBoard (ubz.) من خلال + النقر المزدوج على ملفه من نظام التشغيل. سيُشغَّل OpenBoard عند الحاجة وسيقترح استيراده (أو استبداله إذا كان موجوداً مسبقاً). +

    + + +
    + + +
    +

    تصدير مستنداتك

    +

    + كما يمكنك يمكنك تصدير مستند OpenBoard بصيغة PDF أو UBZ, + و مجلد OpenBoard بصيغة UBX. على سبيل المثال: +

    +
      +
    • حفظ العمل المنجز أثناء الدرس ومشاركته مع طالب غائب.
    • +
    • مشاركته مع معلمين آخرين أو حفظه على وحدة USB لاستيراده في مكان آخر.
    • +
    • استيراد عمل طالب بصيغة PDF، وإضافة الملاحظات عليه، ثم تصدير النسخة المشروحة وإرسالها مجدداً.
    • +
    + +
    + Examples of exporting documents and folders OpenBoard +
    مثال على تصدير الملفات من OpenBoard.
    +
    + + +
    +
    + +
    +
    + + + diff --git a/resources/startupHints/locales/ar/6.html b/resources/startupHints/locales/ar/6.html new file mode 100644 index 000000000..b0079fe84 --- /dev/null +++ b/resources/startupHints/locales/ar/6.html @@ -0,0 +1,89 @@ + + + + + وضع الويب + + + + + + + + + +
    + +
    +

    المتصفح المدمج

    +

    + وضع الويب هو متصفح مدمج داخل OpenBoard يضيف إلى المتصفح التقليدي ميزات عملية جداً للاستخدام داخل الصف الدراسي. +

    +

    + يتيح لك تصفح الإنترنت دون مغادرة OpenBoard، والتقاط المحتوى (جزء من الشاشة أو الشاشة كاملة)، وحتى إنشاء تطبيقات من مواقع الويب لإعادة استخدامها في مستنداتك. +

    + +
    + Example of using the built-in browser of OpenBoard +
    +
    + + +
    +

    إنشاء تطبيق من موقع ويب

    +

    + يمكنك إنشاء تطبيق من أي موقع ويب وإضافته إلى اللوحة والتفاعل معه كما تتفاعل مع التطبيقات المدمجة. +

    +

    + انتقل إلى الموقع المطلوب، ثم انقر على + Add to Library icon + ثم أكّد العملية باختيار "إنشاء تطبيق". +

    + +
    + Creating a web application from the built-in browser +
    إنشاء تطبيق من وضع الويب.
    +
    + +

    + بعد إنشائه، يُحفَظ التطبيق تلقائياً في + مكتبة OpenBoard. ستجده ضمن التطبيقات > الويب + ويمكنك إعادة استخدامه في أي مستند. +

    + +
    + Application saved in library, web folder +
    العثور على تطبيق تم إنشاؤه في المكتبة
    +
    +
    + + +
    + +

    + يمكنك اختيار فتح الروابط في متصفح خارجي عن طريق تحديد الخيار المناسب في الإعدادات. انقر على + Web Mode icon + سينطلق متصفحك المفضل كوضع سطح مكتب. +

    + + +
    + +
    + +
    + +
    + + + diff --git a/resources/startupHints/locales/ar/7.html b/resources/startupHints/locales/ar/7.html new file mode 100644 index 000000000..d7177b9a5 --- /dev/null +++ b/resources/startupHints/locales/ar/7.html @@ -0,0 +1,102 @@ + + + + + لقطة شاشة + + + + + + + + + +
    +
    +

    ميزة بسيطة ومفيدة جداً

    +

    + تتيح لك لقطة الشاشة إنشاء لقطة فورية لحالة اللوحة (أو شاشتك) + أثناء دورتك، لحفظها أو مشاركتها أو إعادة استخدامها. +

    +
    + + +
    +

    في وضع اللوحة

    +

    + في لوحة أدوات القلم، انقر على + Capture Area Icon (Board Mode), + ثم حدد المنطقة التي تريد التقاطها. بعد ذلك يمكنك اختيار: +

    +
      +
    • إضافة إلى الصفحة الحالية
    • +
    • إضافة إلى صفحة جديدة
    • +
    • + إضافة إلى المكتبة — يتم حفظ اللقطة في المجلد الصور + للاستخدام المستقبلي. +
    • +
    + +
    + Example of capturing an area in Board Mode +
    مثال على إدراج لقطة شاشة في OpenBoard.
    +
    + + +
    + + +
    +

    في وضع سطح المكتب

    +

    + انتقل إلى وضع سطح المكتب عبر + Desktop Mode icon + لالتقاط محتوى من تطبيقات أخرى. +

    +

    يتوفر خياران:

    +
      +
    • + Screen Capture icon + التقاط الشاشة كاملة +
    • +
    • + Capture area icon + التقاط منطقة محددة +
    • +
    +

    كما في وضع اللوحة، اختر المكان الذي تريد إضافة اللقطة إليه.

    + +
    + Example of capture in Desktop Mode +
    لقطة شاشة كاملة أو جزئية في وضع سطح المكتب.
    +
    +
    + + +
    +

    في وضع الويب

    +

    + في وضع الويب يمكنك التقاط جزء من الشاشة أو + التقاط علامة التبويب النشطة من المتصفح باستخدام + Capture tab icon. +

    +
    +
    + +
    +
    + + + diff --git a/resources/startupHints/locales/ar/8.html b/resources/startupHints/locales/ar/8.html new file mode 100644 index 000000000..a2ee6f67d --- /dev/null +++ b/resources/startupHints/locales/ar/8.html @@ -0,0 +1,101 @@ + + + + + الصور + + + + + + + + + +
    +
    +

    الوصول إلى الصور وتنظيمها

    +

    + في OpenBoard يمكنك الوصول إلى الصور وإضافتها بطرق مختلفة من خلال المكتبة. تقع المكتبة على الجانب الأيمن من الشاشة، كما يمكنك من خلالها تخزين الأصوات ومقاطع الفيديو والعثورعلى تطبيقات متنوعة. +

    +
    + Import and export area in Documents Mode +
    صورة للمكتبة الموجودة على الجانب الأيمن من البرنامج.
    +
    +
    + + +
    +

    تنظيم مجلد الصور

    +

    + تُجمع لقطات الشاشة المضافة إلى المكتبة داخل مجلد + Icon Images. + يمكنك إنشاء مجلدات فرعية باستخدام + New folder icon + (في أسفل المكتبة)، ثم سحب الصور وإفلاتها داخل المجلدات التي أنشأتها. +

    + +
    + Organizing the Pictures folder with subfolders +
    مثال على تنظيم وتصنيف الصور داخل المكتبة.
    +
    + + +
    + + +
    +

    إضافة صور من جهاز الكمبيوتر

    +

    + يمكنك استيراد ملفات الصور الخاصة بك مباشرة إلى OpenBoard, كما هو موضح أدناه: +

    + +
    + Adding images from the computer +
    استيراد صورة محلية إلى OpenBoard.
    +
    +
    + + +
    +

    إضافة صور من الويب

    +

    + يمكنك أيضاً البحث عن صور مجانية عبر محركات البحث المدمجة, + المواقع في المجلد البحث في الويب + Icon Images. +

    + +
    + Adding images from an integrated search engine +
    مثال على العثور على صور من الويب وإضافتها.
    +
    + + +
    +
    + +
    + +
    + + + diff --git a/resources/startupHints/locales/ar/9.html b/resources/startupHints/locales/ar/9.html new file mode 100644 index 000000000..b5130fab6 --- /dev/null +++ b/resources/startupHints/locales/ar/9.html @@ -0,0 +1,106 @@ + + + + + الأنشطة التفاعلية + + + + + + + + + + +
    + +
    +

    تمارين تفاعلية سهلة التخصيص

    +

    + يوفر OpenBoard مجموعة من الأنشطة التفاعلية القابلة للتخصيص، وهي مناسبة للتلاميذ الأصغر سناً وغيرهم، مثل: التصنيف، والحساب الذهني، والتذكر، وغيرها. +

    +

    + يمكن الوصول إليها في المكتبة: انقر على + Interactivities Icon. +

    +
    + + +
    +

    مثال: " تصنيف الصور"

    +

    + لننشئ تمريناً باستخدام النشاط التفاعلي + " تصنيف الصور ": + Thumbnail Categorize Pictures. +

    + + + +

    1) ضع النشاط التفاعلي وافتح المحرر

    +

    + اسحب النشاط التفاعلي وأفلته على اللوحة، ثم انقر على "تعديل ". +

    + +

    2) تسمية الفئات

    +

    + أعد تسمية الفئات حسب الحاجة. يمكنك أيضاً + إضافة فئات أو حذفها باستخدام أيقونتي “+” و “−”. +

    + +
    + Editing interactivity categories +
    تعديل الفئات: الإضافة، الحذف، وإعادة التسمية.
    +
    + +

    3) إضافة الصور

    +

    + أضف الصور المناسبة لكل فئة (بالسحب والإفلات، أو بالاختيار من المكتبة، وغير ذلك). +

    + +
    + Adding images to categories +
    ربط الصور بالفئات المحددة.
    +
    + +

    4) عرض التمرين وتنفيذه

    +

    + انقر على "عرض" لبدء النشاط في وضع الطالب. +

    + +
    + Performing the Categorize Pictures exercise +
    تنفيذ التمرين: انقل الصور إلى الفئة الصحيحة.
    +
    + +
    +
    + +
    +
    + + + + + diff --git a/resources/startupHints/locales/ar/error.html b/resources/startupHints/locales/ar/error.html new file mode 100644 index 000000000..fc9225577 --- /dev/null +++ b/resources/startupHints/locales/ar/error.html @@ -0,0 +1,20 @@ + + + + + خطأ + + + + + +
    +

    خطأ في التحميل

    +

    + حدث خطأ ما. + تحقق من وجود صفحات الإرشادات في المجلد + /Resources/startupHints/. +

    +
    + + From b6d016aef1908e0d60644af284f93db4f784bf83 Mon Sep 17 00:00:00 2001 From: Lamis Abla Date: Tue, 23 Jun 2026 01:13:03 +0200 Subject: [PATCH 133/133] Address review comments for Arabic StartupHints translation --- resources/startupHints/locales/ar/1.html | 14 +++++++------- resources/startupHints/locales/ar/6.html | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/resources/startupHints/locales/ar/1.html b/resources/startupHints/locales/ar/1.html index 9b3e518c6..d3c3e38b8 100644 --- a/resources/startupHints/locales/ar/1.html +++ b/resources/startupHints/locales/ar/1.html @@ -28,28 +28,28 @@

    مرحباً بك في OpenBoard

    -

    أوضاع OpenBoard الأربعة

    +

    أوضاع OpenBoard الأربعة

    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�-+KONK0g}hqqdtA*(7)f=|)}Lh(_WzXmim) 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 p=Onf{%Tf=@;S6W>U;&+Dr3VXW$fP|7j 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