diff --git a/libs/odf/CMakeLists.txt b/libs/odf/CMakeLists.txt index 6acbf4d1a5..3ac167df5d 100644 --- a/libs/odf/CMakeLists.txt +++ b/libs/odf/CMakeLists.txt @@ -1,45 +1,44 @@ add_subdirectory( tests ) set(kritaodf_LIB_SRCS KoOdf.cpp KoOdfManifestEntry.cpp KoDocumentInfo.cpp KoGenStyle.cpp KoGenStyles.cpp KoFontFace.cpp KoOdfLoadingContext.cpp KoOasisSettings.cpp KoOdfStylesReader.cpp KoOdfNumberStyles.cpp KoOdfReadStore.cpp KoOdfWriteStore.cpp KoStyleStack.cpp KoOdfGraphicStyles.cpp KoGenChange.cpp KoGenChanges.cpp KoDocumentBase.cpp KoEmbeddedDocumentSaver.cpp KoBorder.cpp KoShadowStyle.cpp KoPageLayout.cpp KoPageFormat.cpp - KoColumns.cpp KoUnit.cpp KoOdfNotesConfiguration.cpp KoOdfBibliographyConfiguration.cpp KoOdfNumberDefinition.cpp KoOdfLineNumberingConfiguration.cpp KoElementReference.cpp OdfDebug.cpp ) add_library(kritaodf SHARED ${kritaodf_LIB_SRCS}) generate_export_header(kritaodf BASE_NAME kritaodf) target_link_libraries(kritaodf kritaversion kritaplugin kritastore KF5::CoreAddons KF5::ConfigCore KF5::I18n Qt5::PrintSupport Qt5::Gui Qt5::Xml) set_target_properties(kritaodf PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritaodf ${INSTALL_TARGETS_DEFAULT_ARGS} ) diff --git a/libs/odf/KoColumns.cpp b/libs/odf/KoColumns.cpp deleted file mode 100644 index 6307056ca5..0000000000 --- a/libs/odf/KoColumns.cpp +++ /dev/null @@ -1,283 +0,0 @@ -/* This file is part of the KDE project - Copyright 2012 Friedrich W. H. Kossebau - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "KoColumns.h" - -#include - -#include "KoXmlWriter.h" -#include "KoGenStyle.h" -#include "KoXmlReader.h" -#include "KoXmlNS.h" -#include "KoUnit.h" -// KDE -#include - -static const int defaultColumnCount = 1; -static const KoColumns::SeparatorStyle defaultSeparatorStyle = KoColumns::None; -static const int defaultSeparatorHeight = 100; -static const Qt::GlobalColor defaultSeparatorColor = Qt::black; -static const KoColumns::SeparatorVerticalAlignment defaultSeparatorVerticalAlignment = KoColumns::AlignTop; -static const int defaultColumnGapWidth = 17; // in pt, ~ 6mm - - - -const char * KoColumns::separatorStyleString(KoColumns::SeparatorStyle separatorStyle) -{ - const char * result; - - // skip KoColumns::None, is default - if (separatorStyle == Solid) { - result = "solid"; - } else if (separatorStyle == Dotted) { - result = "dotted"; - } else if (separatorStyle == Dashed) { - result = "dashed"; - } else if (separatorStyle == DotDashed) { - result = "dot-dashed"; - } else { - result = "none"; - } - - return result; -} - -const char * KoColumns::separatorVerticalAlignmentString(KoColumns::SeparatorVerticalAlignment separatorVerticalAlignment) -{ - const char * result; - - // skip KoColumns::AlignTop, is default - if (separatorVerticalAlignment == AlignVCenter) { - result = "middle"; - } else if (separatorVerticalAlignment == AlignBottom) { - result = "bottom"; - } else { - result = "top"; - } - - return result; -} - -KoColumns::SeparatorVerticalAlignment KoColumns::parseSeparatorVerticalAlignment(const QString &value) -{ - // default to AlignTop - SeparatorVerticalAlignment result = defaultSeparatorVerticalAlignment; - - if (! value.isEmpty()) { - // skip "top", is default - if (value == QLatin1String("middle")) { - result = AlignVCenter; - } else if (value == QLatin1String("bottom")) { - result = AlignBottom; - } - } - - return result; -} - -QColor KoColumns::parseSeparatorColor(const QString &value) -{ - QColor result(value); - - if (! result.isValid()) - // default is black, cmp. ODF 1.2 ยง19.467 - result = QColor(defaultSeparatorColor); - - return result; -} - -// TODO: see if there is another parse method somewhere which can be used here -int KoColumns::parseSeparatorHeight(const QString &value) -{ - int result = defaultSeparatorHeight; - - // only try to convert if it ends with a %, so is also not empty - if (value.endsWith(QLatin1Char('%'))) { - bool ok = false; - // try to convert - result = value.left(value.length()-1).toInt(&ok); - // reset to 100% if conversion failed (which sets result to 0) - if (! ok) { - result = defaultSeparatorHeight; - } - } - - return result; -} - -KoColumns::SeparatorStyle KoColumns::parseSeparatorStyle(const QString &value) -{ - SeparatorStyle result = None; - if (! value.isEmpty()) { - // skip "none", is default - if (value == QLatin1String("solid")) { - result = Solid; - } else if (value == QLatin1String("dotted")) { - result = Dotted; - } else if (value == QLatin1String("dashed")) { - result = Dashed; - } else if (value == QLatin1String("dot-dashed")) { - result = DotDashed; - } - } - - return result; -} - -int KoColumns::parseRelativeWidth(const QString &value) -{ - int result = 0; - - // only try to convert if it ends with a *, so is also not empty - if (value.endsWith(QLatin1Char('*'))) { - bool ok = false; - // try to convert - result = value.left(value.length()-1).toInt(&ok); - if (! ok) { - result = 0; - } - } - - return result; -} - -KoColumns::KoColumns() - : count(defaultColumnCount) - , gapWidth(defaultColumnGapWidth) - , separatorStyle(defaultSeparatorStyle) - , separatorColor(defaultSeparatorColor) - , separatorVerticalAlignment(defaultSeparatorVerticalAlignment) - , separatorHeight(defaultSeparatorHeight) -{ -} - -void KoColumns::reset() -{ - count = defaultColumnCount; - gapWidth = defaultColumnGapWidth; - separatorStyle = defaultSeparatorStyle; - separatorColor = QColor(defaultSeparatorColor); - separatorVerticalAlignment = defaultSeparatorVerticalAlignment; - separatorHeight = defaultSeparatorHeight; -} - -bool KoColumns::operator==(const KoColumns& rhs) const { - return - count == rhs.count && - (columnData.isEmpty() && rhs.columnData.isEmpty() ? - (qAbs(gapWidth - rhs.gapWidth) <= 1E-10) : - (columnData == rhs.columnData)); -} - -bool KoColumns::operator!=(const KoColumns& rhs) const { - return - count != rhs.count || - (columnData.isEmpty() && rhs.columnData.isEmpty() ? - qAbs(gapWidth - rhs.gapWidth) > 1E-10 : - ! (columnData == rhs.columnData)); -} - -void KoColumns::loadOdf(const KoXmlElement &style) -{ - KoXmlElement columnsElement = KoXml::namedItemNS(style, KoXmlNS::style, "columns"); - if (!columnsElement.isNull()) { - count = columnsElement.attributeNS(KoXmlNS::fo, "column-count").toInt(); - if (count < 1) - count = 1; - gapWidth = KoUnit::parseValue(columnsElement.attributeNS(KoXmlNS::fo, "column-gap")); - - KoXmlElement columnSep = KoXml::namedItemNS(columnsElement, KoXmlNS::style, "column-sep"); - if (! columnSep.isNull()) { - separatorStyle = parseSeparatorStyle(columnSep.attributeNS(KoXmlNS::style, "style")); - separatorWidth = KoUnit::parseValue(columnSep.attributeNS(KoXmlNS::style, "width")); - separatorHeight = parseSeparatorHeight(columnSep.attributeNS(KoXmlNS::style, "height")); - separatorColor = parseSeparatorColor(columnSep.attributeNS(KoXmlNS::style, "color")); - separatorVerticalAlignment = - parseSeparatorVerticalAlignment(columnSep.attributeNS(KoXmlNS::style, "vertical-align")); - } - - KoXmlElement columnElement; - forEachElement(columnElement, columnsElement) { - if(columnElement.localName() != QLatin1String("column") || - columnElement.namespaceURI() != KoXmlNS::style) - continue; - - ColumnDatum datum; - datum.leftMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "start-indent"), 0.0); - datum.rightMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "end-indent"), 0.0); - datum.topMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "space-before"), 0.0); - datum.bottomMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "space-after"), 0.0); - datum.relativeWidth = parseRelativeWidth(columnElement.attributeNS(KoXmlNS::style, "rel-width")); - // on a bad relativeWidth just drop all data - if (datum.relativeWidth <= 0) { - columnData.clear(); - break; - } - - columnData.append(datum); - } - - if (! columnData.isEmpty() && count != columnData.count()) { - warnOdf << "Found not as many elements as attribute fo:column-count has set:"<< count; - columnData.clear(); - } - } else { - reset(); - } -} - -void KoColumns::saveOdf(KoGenStyle &style) const -{ - if (count > 1) { - QBuffer buffer; - buffer.open(QIODevice::WriteOnly); - KoXmlWriter writer(&buffer); - - writer.startElement("style:columns"); - writer.addAttribute("fo:column-count", count); - if (columnData.isEmpty()) { - writer.addAttribute("fo:column-gap", gapWidth); - } - - if (separatorStyle != KoColumns::None) { - writer.startElement("style:column-sep"); - writer.addAttribute("style:style", separatorStyleString(separatorStyle)); - writer.addAttribute("style:width", separatorWidth); - writer.addAttribute("style:height", QString::number(separatorHeight)+QLatin1Char('%')); - writer.addAttribute("style:color", separatorColor.name()); - writer.addAttribute("style:vertical-align", separatorVerticalAlignmentString(separatorVerticalAlignment)); - writer.endElement(); // style:column-sep - } - - Q_FOREACH (const ColumnDatum &cd, columnData) { - writer.startElement("style:column"); - writer.addAttribute("fo:start-indent", cd.leftMargin); - writer.addAttribute("fo:end-indent", cd.rightMargin); - writer.addAttribute("fo:space-before", cd.topMargin); - writer.addAttribute("fo:space-after", cd.bottomMargin); - writer.addAttribute("style:rel-width", QString::number(cd.relativeWidth)+QLatin1Char('*')); - writer.endElement(); // style:column - } - - writer.endElement(); // style:columns - - QString contentElement = QString::fromUtf8(buffer.buffer(), buffer.buffer().size()); - style.addChildElement("style:columns", contentElement); - } -} diff --git a/libs/odf/KoColumns.h b/libs/odf/KoColumns.h deleted file mode 100644 index cf068a0cf9..0000000000 --- a/libs/odf/KoColumns.h +++ /dev/null @@ -1,138 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 1998, 1999 Torben Weis - Copyright 2002, 2003 David Faure - Copyright 2003 Nicolas GOUTTE - Copyright 2007 Thomas Zander - Copyright 2012 Friedrich W. H. Kossebau - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. -*/ - -#ifndef KOCOLUMNS_H -#define KOCOLUMNS_H - -#include "kritaodf_export.h" - -#include -#include - -#include - -class KoGenStyle; - - -/** structure for columns */ -struct KoColumns { - enum SeparatorVerticalAlignment { - AlignTop = Qt::AlignTop, - AlignVCenter = Qt::AlignVCenter, - AlignBottom = Qt::AlignBottom - }; - - enum SeparatorStyle { - None = Qt::NoPen, - Solid = Qt::SolidLine, - Dashed = Qt::DashLine, - Dotted = Qt::DotLine, - DotDashed = Qt::DashDotLine - }; - - struct ColumnDatum - { - /** Left indent in points */ - qreal leftMargin; - /** Right indent in points */ - qreal rightMargin; - /** Top indent in points */ - qreal topMargin; - /** Bottom indent in points */ - qreal bottomMargin; - - /** The relative width */ - int relativeWidth; - - ColumnDatum() {} - ColumnDatum(qreal lm, qreal rm, qreal tm, qreal bm, int rw) - : leftMargin(lm), rightMargin(rm), topMargin(tm), bottomMargin(bm), relativeWidth(rw) {} - - bool operator==(const KoColumns::ColumnDatum &rhs) const - { - return - (leftMargin == rhs.leftMargin) && - (rightMargin == rhs.rightMargin) && - (topMargin == rhs.topMargin) && - (bottomMargin == rhs.bottomMargin) && - (relativeWidth == rhs.relativeWidth); - } - }; - - /** Number of columns */ - int count; - - /** Spacing between columns in points */ - qreal gapWidth; - - SeparatorStyle separatorStyle; - QColor separatorColor; - SeparatorVerticalAlignment separatorVerticalAlignment; - /** Width in pt */ - qreal separatorWidth; - /** Height in percent. Default is 100% */ - unsigned int separatorHeight; - - /** data about the individual columns if there */ - QList columnData; - - /** - * Construct a columns with the default column count 1, - * default margins (2 cm), and portrait orientation. - */ - KRITAODF_EXPORT KoColumns(); - - KRITAODF_EXPORT void reset(); - KRITAODF_EXPORT bool operator==(const KoColumns &l) const; - KRITAODF_EXPORT bool operator!=(const KoColumns &l) const; - - /** - * Save this columns to ODF. - */ - KRITAODF_EXPORT void saveOdf(KoGenStyle &style) const; - - /** - * Load this columns from ODF - */ - KRITAODF_EXPORT void loadOdf(const KoXmlElement &style); - - qreal totalRelativeWidth() const - { - qreal result = 0.0; - Q_FOREACH (const ColumnDatum &c, columnData) { - result += c.relativeWidth; - } - return result; - } - - KRITAODF_EXPORT static const char * separatorStyleString(KoColumns::SeparatorStyle separatorStyle); - KRITAODF_EXPORT static const char * separatorVerticalAlignmentString(KoColumns::SeparatorVerticalAlignment separatorVerticalAlignment); - KRITAODF_EXPORT static KoColumns::SeparatorVerticalAlignment parseSeparatorVerticalAlignment(const QString &value); - KRITAODF_EXPORT static QColor parseSeparatorColor(const QString &value); - KRITAODF_EXPORT static int parseSeparatorHeight(const QString &value); - KRITAODF_EXPORT static KoColumns::SeparatorStyle parseSeparatorStyle(const QString &value); - KRITAODF_EXPORT static int parseRelativeWidth(const QString &value); -}; - -#endif /* KOCOLUMNS_H */ - diff --git a/libs/ui/KisMainWindow.cpp b/libs/ui/KisMainWindow.cpp index d27ed267ef..754fba2a64 100644 --- a/libs/ui/KisMainWindow.cpp +++ b/libs/ui/KisMainWindow.cpp @@ -1,2675 +1,2673 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 2000-2006 David Faure Copyright (C) 2007, 2009 Thomas zander Copyright (C) 2010 Benjamin Port This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisMainWindow.h" #include // qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_selection_manager.h" #include "kis_icon_utils.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KoDockFactoryBase.h" #include "KoDocumentInfoDlg.h" #include "KoDocumentInfo.h" #include "KoFileDialog.h" #include -#include -#include #include #include #include "KoToolDocker.h" #include "KoToolBoxDocker_p.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_ANDROID #include #endif #include #include #include "dialogs/kis_about_application.h" #include "dialogs/kis_delayed_save_dialog.h" #include "dialogs/kis_dlg_preferences.h" #include "kis_action_manager.h" #include "KisApplication.h" #include "kis_canvas2.h" #include "kis_canvas_controller.h" #include "kis_canvas_resource_provider.h" #include "kis_clipboard.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_custom_image_widget.h" #include #include "kis_group_layer.h" #include "kis_image_from_clipboard_widget.h" #include "kis_image.h" #include #include "KisImportExportManager.h" #include "kis_mainwindow_observer.h" #include "kis_memory_statistics_server.h" #include "kis_node.h" #include "KisOpenPane.h" #include "kis_paintop_box.h" #include "KisPart.h" #include "KisResourceServerProvider.h" #include "kis_signal_compressor_with_param.h" #include "kis_statusbar.h" #include "KisView.h" #include "KisViewManager.h" #include "thememanager.h" #include "kis_animation_importer.h" #include "dialogs/kis_dlg_import_image_sequence.h" #include #include "KisWindowLayoutManager.h" #include #include "KisWelcomePageWidget.h" #include #include #include "KisCanvasWindow.h" #include "kis_action.h" #include class ToolDockerFactory : public KoDockFactoryBase { public: ToolDockerFactory() : KoDockFactoryBase() { } QString id() const override { return "sharedtooldocker"; } QDockWidget* createDockWidget() override { KoToolDocker* dockWidget = new KoToolDocker(); return dockWidget; } DockPosition defaultDockPosition() const override { return DockRight; } }; class Q_DECL_HIDDEN KisMainWindow::Private { public: Private(KisMainWindow *parent, QUuid id) : q(parent) , id(id) , dockWidgetMenu(new KActionMenu(i18nc("@action:inmenu", "&Dockers"), parent)) , windowMenu(new KActionMenu(i18nc("@action:inmenu", "&Window"), parent)) , documentMenu(new KActionMenu(i18nc("@action:inmenu", "New &View"), parent)) , workspaceMenu(new KActionMenu(i18nc("@action:inmenu", "Wor&kspace"), parent)) , welcomePage(new KisWelcomePageWidget(parent)) , widgetStack(new QStackedWidget(parent)) , mdiArea(new QMdiArea(parent)) , windowMapper(new KisSignalMapper(parent)) , documentMapper(new KisSignalMapper(parent)) #ifdef Q_OS_ANDROID , fileManager(new KisAndroidFileManager(parent)) #endif { if (id.isNull()) this->id = QUuid::createUuid(); welcomeScroller = new QScrollArea(); welcomeScroller->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); welcomeScroller->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); welcomeScroller->setWidget(welcomePage); welcomeScroller->setWidgetResizable(true); widgetStack->addWidget(welcomeScroller); widgetStack->addWidget(mdiArea); mdiArea->setTabsMovable(true); mdiArea->setActivationOrder(QMdiArea::ActivationHistoryOrder); } ~Private() { qDeleteAll(toolbarList); } KisMainWindow *q {0}; QUuid id; KisViewManager *viewManager {0}; QPointer activeView; QList toolbarList; bool firstTime {true}; bool windowSizeDirty {false}; bool readOnly {false}; KisAction *showDocumentInfo {0}; KisAction *saveAction {0}; KisAction *saveActionAs {0}; KisAction *importAnimation {0}; KisAction *closeAll {0}; KisAction *importFile {0}; KisAction *exportFile {0}; KisAction *undo {0}; KisAction *redo {0}; KisAction *newWindow {0}; KisAction *close {0}; KisAction *mdiCascade {0}; KisAction *mdiTile {0}; KisAction *mdiNextWindow {0}; KisAction *mdiPreviousWindow {0}; KisAction *toggleDockers {0}; KisAction *resetConfigurations {0}; KisAction *toggleDockerTitleBars {0}; KisAction *toggleDetachCanvas {0}; KisAction *fullScreenMode {0}; KisAction *showSessionManager {0}; KisAction *expandingSpacers[2]; KActionMenu *dockWidgetMenu; KActionMenu *windowMenu; KActionMenu *documentMenu; KActionMenu *workspaceMenu; KHelpMenu *helpMenu {0}; KRecentFilesAction *recentFiles {0}; KisResourceModel *workspacemodel {0}; QScopedPointer undoActionsUpdateManager; QString lastExportLocation; QMap dockWidgetsMap; QByteArray dockerStateBeforeHiding; KoToolDocker *toolOptionsDocker {0}; QCloseEvent *deferredClosingEvent {0}; Digikam::ThemeManager *themeManager {0}; QScrollArea *welcomeScroller {0}; KisWelcomePageWidget *welcomePage {0}; QStackedWidget *widgetStack {0}; QMdiArea *mdiArea; QMdiSubWindow *activeSubWindow {0}; KisSignalMapper *windowMapper; KisSignalMapper *documentMapper; KisCanvasWindow *canvasWindow {0}; QByteArray lastExportedFormat; QScopedPointer > tabSwitchCompressor; QMutex savingEntryMutex; KConfigGroup windowStateConfig; QUuid workspaceBorrowedBy; KisSignalAutoConnectionsStore screenConnectionsStore; #ifdef Q_OS_ANDROID KisAndroidFileManager *fileManager; #endif KisActionManager * actionManager() { return viewManager->actionManager(); } QTabBar* findTabBarHACK() { QObjectList objects = mdiArea->children(); Q_FOREACH (QObject *object, objects) { QTabBar *bar = qobject_cast(object); if (bar) { return bar; } } return 0; } }; KisMainWindow::KisMainWindow(QUuid uuid) : KXmlGuiWindow() , d(new Private(this, uuid)) { d->workspacemodel = KisResourceModelProvider::resourceModel(ResourceType::Workspaces); connect(d->workspacemodel, SIGNAL(afterResourcesLayoutReset()), this, SLOT(updateWindowMenu())); d->viewManager = new KisViewManager(this, actionCollection()); KConfigGroup group( KSharedConfig::openConfig(), "theme"); d->themeManager = new Digikam::ThemeManager(group.readEntry("Theme", "Krita dark"), this); d->windowStateConfig = KSharedConfig::openConfig()->group("MainWindow"); setStandardToolBarMenuEnabled(true); setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North); setDockNestingEnabled(true); qApp->setStartDragDistance(25); // 25 px is a distance that works well for Tablet and Mouse events #ifdef Q_OS_MACOS setUnifiedTitleAndToolBarOnMac(true); #endif connect(this, SIGNAL(restoringDone()), this, SLOT(forceDockTabFonts())); connect(this, SIGNAL(themeChanged()), d->viewManager, SLOT(updateIcons())); connect(KisPart::instance(), SIGNAL(documentClosed(QString)), SLOT(updateWindowMenu())); connect(KisPart::instance(), SIGNAL(documentOpened(QString)), SLOT(updateWindowMenu())); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), this, SLOT(configChanged())); actionCollection()->addAssociatedWidget(this); KoPluginLoader::instance()->load("Krita/ViewPlugin", "Type == 'Service' and ([X-Krita-Version] == 28)", KoPluginLoader::PluginsConfig(), d->viewManager, false); // Load the per-application plugins (Right now, only Python) We do this only once, when the first mainwindow is being created. KoPluginLoader::instance()->load("Krita/ApplicationPlugin", "Type == 'Service' and ([X-Krita-Version] == 28)", KoPluginLoader::PluginsConfig(), qApp, true); KoToolBoxFactory toolBoxFactory; QDockWidget *toolbox = createDockWidget(&toolBoxFactory); toolbox->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable); KisConfig cfg(true); if (cfg.toolOptionsInDocker()) { ToolDockerFactory toolDockerFactory; d->toolOptionsDocker = qobject_cast(createDockWidget(&toolDockerFactory)); d->toolOptionsDocker->toggleViewAction()->setEnabled(true); } QMap dockwidgetActions; dockwidgetActions[toolbox->toggleViewAction()->text()] = toolbox->toggleViewAction(); Q_FOREACH (const QString & docker, KoDockRegistry::instance()->keys()) { KoDockFactoryBase *factory = KoDockRegistry::instance()->value(docker); QDockWidget *dw = createDockWidget(factory); dockwidgetActions[dw->toggleViewAction()->text()] = dw->toggleViewAction(); } if (d->toolOptionsDocker) { dockwidgetActions[d->toolOptionsDocker->toggleViewAction()->text()] = d->toolOptionsDocker->toggleViewAction(); } connect(KoToolManager::instance(), SIGNAL(toolOptionWidgetsChanged(KoCanvasController*,QList >)), this, SLOT(newOptionWidgets(KoCanvasController*,QList >))); Q_FOREACH (QString title, dockwidgetActions.keys()) { d->dockWidgetMenu->addAction(dockwidgetActions[title]); } Q_FOREACH (QDockWidget *wdg, dockWidgets()) { if ((wdg->features() & QDockWidget::DockWidgetClosable) == 0) { wdg->setVisible(true); } } Q_FOREACH (KoCanvasObserverBase* observer, canvasObservers()) { observer->setObservedCanvas(0); KisMainwindowObserver* mainwindowObserver = dynamic_cast(observer); if (mainwindowObserver) { mainwindowObserver->setViewManager(d->viewManager); } } // Load all the actions from the tool plugins Q_FOREACH(KoToolFactoryBase *toolFactory, KoToolRegistry::instance()->values()) { toolFactory->createActions(actionCollection()); } d->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); d->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); d->mdiArea->setTabPosition(QTabWidget::North); d->mdiArea->setTabsClosable(true); // Tab close button override // Windows just has a black X, and Ubuntu has a dark x that is hard to read // just switch this icon out for all OSs so it is easier to see d->mdiArea->setStyleSheet("QTabBar::close-button { image: url(:/pics/broken-preset.png) }"); setCentralWidget(d->widgetStack); d->widgetStack->setCurrentIndex(0); connect(d->mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(subWindowActivated())); connect(d->windowMapper, SIGNAL(mapped(QWidget*)), this, SLOT(setActiveSubWindow(QWidget*))); connect(d->documentMapper, SIGNAL(mapped(QObject*)), this, SLOT(newView(QObject*))); d->canvasWindow = new KisCanvasWindow(this); actionCollection()->addAssociatedWidget(d->canvasWindow); createActions(); // the welcome screen needs to grab actions...so make sure this line goes after the createAction() so they exist d->welcomePage->setMainWindow(this); setAutoSaveSettings(d->windowStateConfig, false); subWindowActivated(); updateWindowMenu(); if (isHelpMenuEnabled() && !d->helpMenu) { // workaround for KHelpMenu (or rather KAboutData::applicationData()) internally // not using the Q*Application metadata ATM, which results e.g. in the bugreport wizard // not having the app version preset // fixed hopefully in KF5 5.22.0, patch pending QGuiApplication *app = qApp; KAboutData aboutData(app->applicationName(), app->applicationDisplayName(), app->applicationVersion()); aboutData.setOrganizationDomain(app->organizationDomain().toUtf8()); d->helpMenu = new KHelpMenu(this, aboutData, false); // workaround-less version: // d->helpMenu = new KHelpMenu(this, QString()/*unused*/, false); // The difference between using KActionCollection->addAction() is that // these actions do not get tied to the MainWindow. What does this all do? KActionCollection *actions = d->viewManager->actionCollection(); QAction *helpContentsAction = d->helpMenu->action(KHelpMenu::menuHelpContents); QAction *whatsThisAction = d->helpMenu->action(KHelpMenu::menuWhatsThis); QAction *reportBugAction = d->helpMenu->action(KHelpMenu::menuReportBug); QAction *switchLanguageAction = d->helpMenu->action(KHelpMenu::menuSwitchLanguage); QAction *aboutAppAction = d->helpMenu->action(KHelpMenu::menuAboutApp); QAction *aboutKdeAction = d->helpMenu->action(KHelpMenu::menuAboutKDE); if (helpContentsAction) { actions->addAction(helpContentsAction->objectName(), helpContentsAction); } if (whatsThisAction) { actions->addAction(whatsThisAction->objectName(), whatsThisAction); } if (reportBugAction) { actions->addAction(reportBugAction->objectName(), reportBugAction); } if (switchLanguageAction) { actions->addAction(switchLanguageAction->objectName(), switchLanguageAction); } if (aboutAppAction) { actions->addAction(aboutAppAction->objectName(), aboutAppAction); } if (aboutKdeAction) { actions->addAction(aboutKdeAction->objectName(), aboutKdeAction); } connect(d->helpMenu, SIGNAL(showAboutApplication()), SLOT(showAboutApplication())); } // KDE' libs 4''s help contents action is broken outside kde, for some reason... We can handle it just as easily ourselves QAction *helpAction = actionCollection()->action("help_contents"); helpAction->disconnect(); connect(helpAction, SIGNAL(triggered()), this, SLOT(showManual())); #if 0 //check for colliding shortcuts QSet existingShortcuts; Q_FOREACH (QAction* action, actionCollection()->actions()) { if(action->shortcut() == QKeySequence(0)) { continue; } dbgKrita << "shortcut " << action->text() << " " << action->shortcut(); Q_ASSERT(!existingShortcuts.contains(action->shortcut())); existingShortcuts.insert(action->shortcut()); } #endif configChanged(); // Make sure the python plugins create their actions in time KisPart::instance()->notifyMainWindowIsBeingCreated(this); // If we have customized the toolbars, load that first setLocalXMLFile(KoResourcePaths::locateLocal("data", "krita4.xmlgui")); setXMLFile(":/kxmlgui5/krita4.xmlgui"); guiFactory()->addClient(this); connect(guiFactory(), SIGNAL(makingChanges(bool)), SLOT(slotXmlGuiMakingChanges(bool))); // Create and plug toolbar list for Settings menu QList toolbarList; Q_FOREACH (QWidget* it, guiFactory()->containers("ToolBar")) { KToolBar * toolBar = ::qobject_cast(it); if (toolBar) { toolBar->setMovable(KisConfig(true).readEntry("LockAllDockerPanels", false)); if (toolBar->objectName() == "BrushesAndStuff") { toolBar->setEnabled(false); } KToggleAction* act = new KToggleAction(i18n("Show %1 Toolbar", toolBar->windowTitle()), this); actionCollection()->addAction(toolBar->objectName().toUtf8(), act); act->setCheckedState(KGuiItem(i18n("Hide %1 Toolbar", toolBar->windowTitle()))); connect(act, SIGNAL(toggled(bool)), this, SLOT(slotToolbarToggled(bool))); act->setChecked(!toolBar->isHidden()); toolbarList.append(act); } else { warnUI << "Toolbar list contains a " << it->metaObject()->className() << " which is not a toolbar!"; } } KToolBar::setToolBarsLocked(KisConfig(true).readEntry("LockAllDockerPanels", false)); plugActionList("toolbarlist", toolbarList); d->toolbarList = toolbarList; applyToolBarLayout(); d->viewManager->updateGUI(); d->viewManager->updateIcons(); QTimer::singleShot(1000, this, SLOT(checkSanity())); { using namespace std::placeholders; // For _1 placeholder std::function callback( std::bind(&KisMainWindow::switchTab, this, _1)); d->tabSwitchCompressor.reset( new KisSignalCompressorWithParam(500, callback, KisSignalCompressor::FIRST_INACTIVE)); } if (cfg.readEntry("CanvasOnlyActive", false)) { QString currentWorkspace = cfg.readEntry("CurrentWorkspace", "Default"); KoResourceServer * rserver = KisResourceServerProvider::instance()->workspaceServer(); KisWorkspaceResourceSP workspace = rserver->resourceByName(currentWorkspace); if (workspace) { restoreWorkspace(workspace->resourceId()); } cfg.writeEntry("CanvasOnlyActive", false); menuBar()->setVisible(true); } this->winId(); // Ensures the native window has been created. QWindow *window = this->windowHandle(); connect(window, SIGNAL(screenChanged(QScreen *)), this, SLOT(windowScreenChanged(QScreen *))); } KisMainWindow::~KisMainWindow() { // Q_FOREACH (QAction *ac, actionCollection()->actions()) { // QAction *action = qobject_cast(ac); // if (action) { // qDebug() << "", "").replace("", "") // << "\n\ticonText=" << action->iconText().replace("&", "&") // << "\n\tshortcut=" << action->shortcut().toString() // << "\n\tisCheckable=" << QString((action->isChecked() ? "true" : "false")) // << "\n\tstatusTip=" << action->statusTip() // << "\n/>\n" ; // } // else { // dbgKrita << "Got a non-qaction:" << ac->objectName(); // } // } // The doc and view might still exist (this is the case when closing the window) KisPart::instance()->removeMainWindow(this); delete d->viewManager; delete d; } QUuid KisMainWindow::id() const { return d->id; } void KisMainWindow::addView(KisView *view, QMdiSubWindow *subWindow) { if (d->activeView == view && !subWindow) return; if (d->activeView) { d->activeView->disconnect(this); } // register the newly created view in the input manager viewManager()->inputManager()->addTrackedCanvas(view->canvasBase()); showView(view, subWindow); updateCaption(); emit restoringDone(); if (d->activeView) { connect(d->activeView, SIGNAL(titleModified(QString,bool)), SLOT(slotDocumentTitleModified())); connect(d->viewManager->statusBar(), SIGNAL(memoryStatusUpdated()), this, SLOT(updateCaption())); } } void KisMainWindow::notifyChildViewDestroyed(KisView *view) { /** * If we are the last view of the window, Qt will not activate another tab * before destroying tab/window. In this case we should clear all the dangling * pointers manually by setting the current view to null */ viewManager()->inputManager()->removeTrackedCanvas(view->canvasBase()); if (view->canvasBase() == viewManager()->canvasBase()) { viewManager()->setCurrentView(0); } } void KisMainWindow::showView(KisView *imageView, QMdiSubWindow *subwin) { if (imageView && activeView() != imageView) { // XXX: find a better way to initialize this! imageView->setViewManager(d->viewManager); imageView->canvasBase()->setFavoriteResourceManager(d->viewManager->paintOpBox()->favoriteResourcesManager()); imageView->slotLoadingFinished(); if (!subwin) { subwin = d->mdiArea->addSubWindow(imageView); } else { subwin->setWidget(imageView); } imageView->setSubWindow(subwin); subwin->setAttribute(Qt::WA_DeleteOnClose, true); connect(subwin, SIGNAL(destroyed()), SLOT(updateWindowMenu())); KisConfig cfg(true); subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setWindowIcon(qApp->windowIcon()); #ifdef Q_OS_MACOS connect(subwin, SIGNAL(destroyed()), SLOT(updateSubwindowFlags())); updateSubwindowFlags(); #endif if (d->mdiArea->subWindowList().size() == 1) { imageView->showMaximized(); } else { imageView->show(); } /** * Hack alert! * * Here we explicitly request KoToolManager to emit all the tool * activation signals, to reinitialize the tool options docker. * * That is needed due to a design flaw we have in the * initialization procedure. The tool in the KoToolManager is * initialized in KisView::setViewManager() calls, which * happens early enough. During this call the tool manager * requests KoCanvasControllerWidget to emit the signal to * update the widgets in the tool docker. *But* at that moment * of time the view is not yet connected to the main window, * because it happens in KisViewManager::setCurrentView a bit * later. This fact makes the widgets updating signals be lost * and never reach the tool docker. * * So here we just explicitly call the tool activation stub. */ KoToolManager::instance()->initializeCurrentToolForCanvas(); // No, no, no: do not try to call this _before_ the show() has // been called on the view; only when that has happened is the // opengl context active, and very bad things happen if we tell // the dockers to update themselves with a view if the opengl // context is not active. setActiveView(imageView); updateWindowMenu(); updateCaption(); } } void KisMainWindow::slotPreferences() { QScopedPointer dlgPreferences(new KisDlgPreferences(this)); if (dlgPreferences->editPreferences()) { KisConfigNotifier::instance()->notifyConfigChanged(); KisConfigNotifier::instance()->notifyPixelGridModeChanged(); KisImageConfigNotifier::instance()->notifyConfigChanged(); // XXX: should this be changed for the views in other windows as well? Q_FOREACH (QPointer koview, KisPart::instance()->views()) { KisViewManager *view = qobject_cast(koview); if (view) { // Update the settings for all nodes -- they don't query // KisConfig directly because they need the settings during // compositing, and they don't connect to the config notifier // because nodes are not QObjects (because only one base class // can be a QObject). KisNode* node = dynamic_cast(view->image()->rootLayer().data()); node->updateSettings(); } } updateWindowMenu(); d->viewManager->showHideScrollbars(); } } void KisMainWindow::slotThemeChanged() { // save theme changes instantly KConfigGroup group( KSharedConfig::openConfig(), "theme"); group.writeEntry("Theme", d->themeManager->currentThemeName()); // reload action icons! Q_FOREACH (QAction *action, actionCollection()->actions()) { KisIconUtils::updateIcon(action); } if (d->mdiArea) { d->mdiArea->setPalette(qApp->palette()); for (int i=0; imdiArea->subWindowList().size(); i++) { QMdiSubWindow *window = d->mdiArea->subWindowList().at(i); if (window) { window->setPalette(qApp->palette()); KisView *view = qobject_cast(window->widget()); if (view) { view->slotThemeChanged(qApp->palette()); } } } } emit themeChanged(); } bool KisMainWindow::canvasDetached() const { return centralWidget() != d->widgetStack; } void KisMainWindow::setCanvasDetached(bool detach) { if (detach == canvasDetached()) return; QWidget *outgoingWidget = centralWidget() ? takeCentralWidget() : nullptr; QWidget *incomingWidget = d->canvasWindow->swapMainWidget(outgoingWidget); if (incomingWidget) { setCentralWidget(incomingWidget); } if (detach) { d->canvasWindow->show(); } else { d->canvasWindow->hide(); } } void KisMainWindow::slotFileSelected(QString path) { QString url = path; if (!url.isEmpty()) { bool res = openDocument(QUrl::fromLocalFile(url), Import); if (!res) { warnKrita << "Loading" << url << "failed"; } } } void KisMainWindow::slotEmptyFilePath() { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("The chosen file's location could not be found. Does it exist?")); } QWidget * KisMainWindow::canvasWindow() const { return d->canvasWindow; } void KisMainWindow::setReadWrite(bool readwrite) { d->saveAction->setEnabled(readwrite); d->importFile->setEnabled(readwrite); d->readOnly = !readwrite; updateCaption(); } void KisMainWindow::addRecentURL(const QUrl &url, const QUrl &oldUrl) { // Add entry to recent documents list // (call coming from KisDocument because it must work with cmd line, template dlg, file/open, etc.) if (!url.isEmpty()) { bool ok = true; if (url.isLocalFile()) { QString path = url.adjusted(QUrl::StripTrailingSlash).toLocalFile(); const QStringList tmpDirs = KoResourcePaths::resourceDirs("tmp"); for (QStringList::ConstIterator it = tmpDirs.begin() ; ok && it != tmpDirs.end() ; ++it) { if (path.contains(*it)) { ok = false; // it's in the tmp resource } } const QStringList templateDirs = KoResourcePaths::findDirs("templates"); for (QStringList::ConstIterator it = templateDirs.begin() ; ok && it != templateDirs.end() ; ++it) { if (path.contains(*it)) { ok = false; // it's in the templates directory. break; } } } if (ok) { if (!oldUrl.isEmpty()) { d->recentFiles->removeUrl(oldUrl); } d->recentFiles->addUrl(url); } saveRecentFiles(); } } void KisMainWindow::saveRecentFiles() { // Save list of recent files KSharedConfigPtr config = KSharedConfig::openConfig(); d->recentFiles->saveEntries(config->group("RecentFiles")); config->sync(); // Tell all windows to reload their list, after saving // Doesn't work multi-process, but it's a start Q_FOREACH (KisMainWindow *mw, KisPart::instance()->mainWindows()) { if (mw != this) { mw->reloadRecentFileList(); } } } QList KisMainWindow::recentFilesUrls() { return d->recentFiles->urls(); } void KisMainWindow::clearRecentFiles() { d->recentFiles->clear(); d->welcomePage->populateRecentDocuments(); } void KisMainWindow::removeRecentUrl(const QUrl &url) { d->recentFiles->removeUrl(url); KSharedConfigPtr config = KSharedConfig::openConfig(); d->recentFiles->saveEntries(config->group("RecentFiles")); config->sync(); } void KisMainWindow::reloadRecentFileList() { d->recentFiles->loadEntries(KSharedConfig::openConfig()->group("RecentFiles")); } void KisMainWindow::updateCaption() { if (!d->mdiArea->activeSubWindow()) { updateCaption(QString(), false); } else if (d->activeView && d->activeView->document() && d->activeView->image()){ KisDocument *doc = d->activeView->document(); QString caption(doc->caption()); caption = "RESOURCES REWRITE GOING ON " + caption; if (d->readOnly) { caption += " [" + i18n("Write Protected") + "] "; } if (doc->isRecovered()) { caption += " [" + i18n("Recovered") + "] "; } // show the file size for the document KisMemoryStatisticsServer::Statistics m_fileSizeStats = KisMemoryStatisticsServer::instance()->fetchMemoryStatistics(d->activeView ? d->activeView->image() : 0); if (m_fileSizeStats.imageSize) { caption += QString(" (").append( KFormat().formatByteSize(m_fileSizeStats.imageSize)).append( ")"); } updateCaption(caption, doc->isModified()); if (!doc->url().fileName().isEmpty()) { d->saveAction->setToolTip(i18n("Save as %1", doc->url().fileName())); } else { d->saveAction->setToolTip(i18n("Save")); } } } void KisMainWindow::updateCaption(const QString &caption, bool modified) { QString versionString = KritaVersionWrapper::versionString(true); QString title = caption; if (!title.contains(QStringLiteral("[*]"))) { // append the placeholder so that the modified mechanism works title.append(QStringLiteral(" [*]")); } if (d->mdiArea->activeSubWindow()) { #if defined(KRITA_ALPHA) || defined (KRITA_BETA) || defined (KRITA_RC) d->mdiArea->activeSubWindow()->setWindowTitle(QString("%1: %2").arg(versionString).arg(title)); #else d->mdiArea->activeSubWindow()->setWindowTitle(title); #endif d->mdiArea->activeSubWindow()->setWindowModified(modified); } else { #if defined(KRITA_ALPHA) || defined (KRITA_BETA) || defined (KRITA_RC) setWindowTitle(QString("%1: %2").arg(versionString).arg(title)); #else setWindowTitle(title); #endif } setWindowModified(modified); } KisView *KisMainWindow::activeView() const { if (d->activeView) { return d->activeView; } return 0; } bool KisMainWindow::openDocument(const QUrl &url, OpenFlags flags) { if (!QFile(url.toLocalFile()).exists()) { if (!(flags & BatchMode)) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("The file %1 does not exist.", url.url())); } d->recentFiles->removeUrl(url); //remove the file from the recent-opened-file-list saveRecentFiles(); return false; } return openDocumentInternal(url, flags); } bool KisMainWindow::openDocumentInternal(const QUrl &url, OpenFlags flags) { if (!url.isLocalFile()) { qWarning() << "KisMainWindow::openDocumentInternal. Not a local file:" << url; return false; } KisDocument *newdoc = KisPart::instance()->createDocument(); if (flags & BatchMode) { newdoc->setFileBatchMode(true); } d->firstTime = true; connect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); connect(newdoc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString))); KisDocument::OpenFlags openFlags = KisDocument::None; // XXX: Why this duplication of of OpenFlags... if (flags & RecoveryFile) { openFlags |= KisDocument::RecoveryFile; } bool openRet = !(flags & Import) ? newdoc->openUrl(url, openFlags) : newdoc->importDocument(url); if (!openRet) { delete newdoc; return false; } KisPart::instance()->addDocument(newdoc); if (!QFileInfo(url.toLocalFile()).isWritable()) { setReadWrite(false); } // Try to determine whether this was an unnamed autosave if (flags & RecoveryFile && ( url.toLocalFile().startsWith(QDir::tempPath()) || url.toLocalFile().startsWith(QDir::homePath()) ) && ( QFileInfo(url.toLocalFile()).fileName().startsWith(".krita") || QFileInfo(url.toLocalFile()).fileName().startsWith("krita") ) ) { QString path = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); if (!QFileInfo(path).exists()) { path = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); } newdoc->setUrl(QUrl::fromLocalFile( path + "/" + newdoc->objectName() + ".kra")); } return true; } void KisMainWindow::showDocument(KisDocument *document) { Q_FOREACH(QMdiSubWindow *subwindow, d->mdiArea->subWindowList()) { KisView *view = qobject_cast(subwindow->widget()); KIS_SAFE_ASSERT_RECOVER_NOOP(view); if (view) { if (view->document() == document) { setActiveSubWindow(subwindow); return; } } } addViewAndNotifyLoadingCompleted(document); } KisView* KisMainWindow::addViewAndNotifyLoadingCompleted(KisDocument *document, QMdiSubWindow *subWindow) { showWelcomeScreen(false); // see workaround in function header KisView *view = KisPart::instance()->createView(document, d->viewManager, this); addView(view, subWindow); emit guiLoadingFinished(); return view; } QStringList KisMainWindow::showOpenFileDialog(bool isImporting) { KoFileDialog dialog(this, KoFileDialog::ImportFiles, "OpenDocument"); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setMimeTypeFilters(KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import)); dialog.setCaption(isImporting ? i18n("Import Images") : i18n("Open Images")); return dialog.filenames(); } // Separate from openDocument to handle async loading (remote URLs) void KisMainWindow::slotLoadCompleted() { KisDocument *newdoc = qobject_cast(sender()); if (newdoc && newdoc->image()) { addViewAndNotifyLoadingCompleted(newdoc); disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); disconnect(newdoc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString))); emit loadCompleted(); } } void KisMainWindow::slotLoadCanceled(const QString & errMsg) { KisUsageLogger::log(QString("Loading canceled. Error:").arg(errMsg)); if (!errMsg.isEmpty()) // empty when canceled by user QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg); // ... can't delete the document, it's the one who emitted the signal... KisDocument* doc = qobject_cast(sender()); Q_ASSERT(doc); disconnect(doc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); disconnect(doc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString))); } void KisMainWindow::slotSaveCanceled(const QString &errMsg) { KisUsageLogger::log(QString("Saving canceled. Error:").arg(errMsg)); if (!errMsg.isEmpty()) { // empty when canceled by user QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg); } slotSaveCompleted(); } void KisMainWindow::slotSaveCompleted() { KisUsageLogger::log(QString("Saving Completed")); KisDocument* doc = qobject_cast(sender()); Q_ASSERT(doc); disconnect(doc, SIGNAL(completed()), this, SLOT(slotSaveCompleted())); disconnect(doc, SIGNAL(canceled(QString)), this, SLOT(slotSaveCanceled(QString))); if (d->deferredClosingEvent) { KXmlGuiWindow::closeEvent(d->deferredClosingEvent); } } bool KisMainWindow::hackIsSaving() const { StdLockableWrapper wrapper(&d->savingEntryMutex); std::unique_lock> l(wrapper, std::try_to_lock); return !l.owns_lock(); } bool KisMainWindow::installBundle(const QString &fileName) const { QFileInfo from(fileName); QFileInfo to(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/bundles/" + from.fileName()); if (to.exists()) { QFile::remove(to.canonicalFilePath()); } return QFile::copy(fileName, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/bundles/" + from.fileName()); } QImage KisMainWindow::layoutThumbnail() { int size = 256; qreal scale = qreal(size)/qreal(qMax(geometry().width(), geometry().height())); QImage layoutThumbnail = QImage(qRound(geometry().width()*scale), qRound(geometry().height()*scale), QImage::Format_ARGB32); QPainter gc(&layoutThumbnail); gc.fillRect(0, 0, layoutThumbnail.width(), layoutThumbnail.height(), this->palette().dark()); for (int childW = 0; childW< children().size(); childW++) { if (children().at(childW)->isWidgetType()) { QWidget *w = dynamic_cast(children().at(childW)); if (w->isVisible()) { QRect wRect = QRectF(w->geometry().x()*scale , w->geometry().y()*scale , w->geometry().width()*scale , w->geometry().height()*scale ).toRect(); wRect = wRect.intersected(layoutThumbnail.rect().adjusted(-1, -1, -1, -1)); gc.setBrush(this->palette().window()); if (w == d->widgetStack) { gc.setBrush(d->mdiArea->background()); } gc.setPen(this->palette().windowText().color()); gc.drawRect(wRect); } } } gc.end(); return layoutThumbnail; } bool KisMainWindow::saveDocument(KisDocument *document, bool saveas, bool isExporting) { if (!document) { return true; } /** * Make sure that we cannot enter this method twice! * * The lower level functions may call processEvents() so * double-entry is quite possible to achieve. Here we try to lock * the mutex, and if it is failed, just cancel saving. */ StdLockableWrapper wrapper(&d->savingEntryMutex); std::unique_lock> l(wrapper, std::try_to_lock); if (!l.owns_lock()) return false; // no busy wait for saving because it is dangerous! KisDelayedSaveDialog dlg(document->image(), KisDelayedSaveDialog::SaveDialog, 0, this); dlg.blockIfImageIsBusy(); if (dlg.result() == KisDelayedSaveDialog::Rejected) { return false; } else if (dlg.result() == KisDelayedSaveDialog::Ignored) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("You are saving a file while the image is " "still rendering. The saved file may be " "incomplete or corrupted.\n\n" "Please select a location where the original " "file will not be overridden!")); saveas = true; } if (document->isRecovered()) { saveas = true; } if (document->url().isEmpty()) { saveas = true; } connect(document, SIGNAL(completed()), this, SLOT(slotSaveCompleted())); connect(document, SIGNAL(canceled(QString)), this, SLOT(slotSaveCanceled(QString))); QByteArray nativeFormat = document->nativeFormatMimeType(); QByteArray oldMimeFormat = document->mimeType(); QUrl suggestedURL = document->url(); QStringList mimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export); mimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export); if (!mimeFilter.contains(oldMimeFormat)) { dbgUI << "KisMainWindow::saveDocument no export filter for" << oldMimeFormat; // --- don't setOutputMimeType in case the user cancels the Save As // dialog and then tries to just plain Save --- // suggest a different filename extension (yes, we fortunately don't all live in a world of magic :)) QString suggestedFilename = QFileInfo(suggestedURL.toLocalFile()).completeBaseName(); if (!suggestedFilename.isEmpty()) { // ".kra" looks strange for a name suggestedFilename = suggestedFilename + "." + KisMimeDatabase::suffixesForMimeType(KIS_MIME_TYPE).first(); suggestedURL = suggestedURL.adjusted(QUrl::RemoveFilename); suggestedURL.setPath(suggestedURL.path() + suggestedFilename); } // force the user to choose outputMimeType saveas = true; } bool ret = false; if (document->url().isEmpty() || isExporting || saveas) { // if you're just File/Save As'ing to change filter options you // don't want to be reminded about overwriting files etc. bool justChangingFilterOptions = false; KoFileDialog dialog(this, KoFileDialog::SaveFile, "SaveAs"); dialog.setCaption(isExporting ? i18n("Exporting") : i18n("Saving As")); //qDebug() << ">>>>>" << isExporting << d->lastExportLocation << d->lastExportedFormat << QString::fromLatin1(document->mimeType()); if (isExporting && !d->lastExportLocation.isEmpty() && !d->lastExportLocation.contains(QDir::tempPath())) { // Use the location where we last exported to, if it's set, as the opening location for the file dialog QString proposedPath = QFileInfo(d->lastExportLocation).absolutePath(); // If the document doesn't have a filename yet, use the title QString proposedFileName = suggestedURL.isEmpty() ? document->documentInfo()->aboutInfo("title") : QFileInfo(suggestedURL.toLocalFile()).completeBaseName(); // Use the last mimetype we exported to by default QString proposedMimeType = d->lastExportedFormat.isEmpty() ? "" : d->lastExportedFormat; QString proposedExtension = KisMimeDatabase::suffixesForMimeType(proposedMimeType).first().remove("*,"); // Set the default dir: this overrides the one loaded from the config file, since we're exporting and the lastExportLocation is not empty dialog.setDefaultDir(proposedPath + "/" + proposedFileName + "." + proposedExtension, true); dialog.setMimeTypeFilters(mimeFilter, proposedMimeType); } else { // Get the last used location for saving KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); QString proposedPath = group.readEntry("SaveAs", ""); // if that is empty, get the last used location for loading if (proposedPath.isEmpty()) { proposedPath = group.readEntry("OpenDocument", ""); } // If that is empty, too, use the Pictures location. if (proposedPath.isEmpty()) { proposedPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); } // But only use that if the suggestedUrl, that is, the document's own url is empty, otherwise // open the location where the document currently is. dialog.setDefaultDir(suggestedURL.isEmpty() ? proposedPath : suggestedURL.toLocalFile(), true); // If exporting, default to all supported file types if user is exporting QByteArray default_mime_type = ""; if (!isExporting) { // otherwise use the document's mimetype, or if that is empty, kra, which is the savest. default_mime_type = document->mimeType().isEmpty() ? nativeFormat : document->mimeType(); } dialog.setMimeTypeFilters(mimeFilter, QString::fromLatin1(default_mime_type)); } QUrl newURL = QUrl::fromUserInput(dialog.filename()); if (newURL.isLocalFile()) { QString fn = newURL.toLocalFile(); if (QFileInfo(fn).completeSuffix().isEmpty()) { fn.append(KisMimeDatabase::suffixesForMimeType(nativeFormat).first()); newURL = QUrl::fromLocalFile(fn); } } if (document->documentInfo()->aboutInfo("title") == i18n("Unnamed")) { QString fn = newURL.toLocalFile(); QFileInfo info(fn); document->documentInfo()->setAboutInfo("title", info.completeBaseName()); } QByteArray outputFormat = nativeFormat; QString outputFormatString = KisMimeDatabase::mimeTypeForFile(newURL.toLocalFile(), false); outputFormat = outputFormatString.toLatin1(); if (!isExporting) { justChangingFilterOptions = (newURL == document->url()) && (outputFormat == document->mimeType()); } else { QString path = QFileInfo(d->lastExportLocation).absolutePath(); QString filename = QFileInfo(document->url().toLocalFile()).completeBaseName(); justChangingFilterOptions = (QFileInfo(newURL.toLocalFile()).absolutePath() == path) && (QFileInfo(newURL.toLocalFile()).completeBaseName() == filename) && (outputFormat == d->lastExportedFormat); } bool bOk = true; if (newURL.isEmpty()) { bOk = false; } if (bOk) { bool wantToSave = true; // don't change this line unless you know what you're doing :) if (!justChangingFilterOptions) { if (!document->isNativeFormat(outputFormat)) wantToSave = true; } if (wantToSave) { if (!isExporting) { // Save As ret = document->saveAs(newURL, outputFormat, true); if (ret) { dbgUI << "Successful Save As!"; KisPart::instance()->addRecentURLToAllMainWindows(newURL); setReadWrite(true); } else { dbgUI << "Failed Save As!"; } } else { // Export ret = document->exportDocument(newURL, outputFormat); if (ret) { d->lastExportLocation = newURL.toLocalFile(); d->lastExportedFormat = outputFormat; } } } // if (wantToSave) { else ret = false; } // if (bOk) { else ret = false; } else { // saving // We cannot "export" into the currently // opened document. We are not Gimp. KIS_ASSERT_RECOVER_NOOP(!isExporting); // be sure document has the correct outputMimeType! if (document->isModified()) { ret = document->save(true, 0); } if (!ret) { dbgUI << "Failed Save!"; } } updateCaption(); return ret; } void KisMainWindow::undo() { if (activeView()) { activeView()->document()->undoStack()->undo(); } } void KisMainWindow::redo() { if (activeView()) { activeView()->document()->undoStack()->redo(); } } void KisMainWindow::closeEvent(QCloseEvent *e) { if (hackIsSaving()) { e->setAccepted(false); return; } if (!KisPart::instance()->closingSession()) { QAction *action= d->viewManager->actionCollection()->action("view_show_canvas_only"); if ((action) && (action->isChecked())) { action->setChecked(false); } // Save session when last window is closed if (KisPart::instance()->mainwindowCount() == 1) { bool closeAllowed = KisPart::instance()->closeSession(); if (!closeAllowed) { e->setAccepted(false); return; } } } d->mdiArea->closeAllSubWindows(); QList childrenList = d->mdiArea->subWindowList(); if (childrenList.isEmpty()) { d->deferredClosingEvent = e; saveWindowState(true); d->canvasWindow->close(); } else { e->setAccepted(false); } } void KisMainWindow::saveWindowSettings() { KSharedConfigPtr config = KSharedConfig::openConfig(); if (d->windowSizeDirty ) { dbgUI << "KisMainWindow::saveWindowSettings"; KConfigGroup group = d->windowStateConfig; KWindowConfig::saveWindowSize(windowHandle(), group); config->sync(); d->windowSizeDirty = false; } if (!d->activeView || d->activeView->document()) { // Save toolbar position into the config file of the app, under the doc's component name KConfigGroup group = d->windowStateConfig; saveMainWindowSettings(group); // Save collapsible state of dock widgets for (QMap::const_iterator i = d->dockWidgetsMap.constBegin(); i != d->dockWidgetsMap.constEnd(); ++i) { if (i.value()->widget()) { KConfigGroup dockGroup = group.group(QString("DockWidget ") + i.key()); dockGroup.writeEntry("Collapsed", i.value()->widget()->isHidden()); dockGroup.writeEntry("Locked", i.value()->property("Locked").toBool()); dockGroup.writeEntry("DockArea", (int) dockWidgetArea(i.value())); dockGroup.writeEntry("xPosition", (int) i.value()->widget()->x()); dockGroup.writeEntry("yPosition", (int) i.value()->widget()->y()); dockGroup.writeEntry("width", (int) i.value()->widget()->width()); dockGroup.writeEntry("height", (int) i.value()->widget()->height()); } } } KSharedConfig::openConfig()->sync(); resetAutoSaveSettings(); // Don't let KMainWindow override the good stuff we wrote down } void KisMainWindow::resizeEvent(QResizeEvent * e) { d->windowSizeDirty = true; KXmlGuiWindow::resizeEvent(e); } void KisMainWindow::setActiveView(KisView* view) { d->activeView = view; updateCaption(); if (d->undoActionsUpdateManager) { d->undoActionsUpdateManager->setCurrentDocument(view ? view->document() : 0); } d->viewManager->setCurrentView(view); KisWindowLayoutManager::instance()->activeDocumentChanged(view->document()); } void KisMainWindow::dragMove(QDragMoveEvent * event) { QTabBar *tabBar = d->findTabBarHACK(); if (!tabBar && d->mdiArea->viewMode() == QMdiArea::TabbedView) { qWarning() << "WARNING!!! Cannot find QTabBar in the main window! Looks like Qt has changed behavior. Drag & Drop between multiple tabs might not work properly (tabs will not switch automatically)!"; } if (tabBar && tabBar->isVisible()) { QPoint pos = tabBar->mapFromGlobal(mapToGlobal(event->pos())); if (tabBar->rect().contains(pos)) { const int tabIndex = tabBar->tabAt(pos); if (tabIndex >= 0 && tabBar->currentIndex() != tabIndex) { d->tabSwitchCompressor->start(tabIndex); } } else if (d->tabSwitchCompressor->isActive()) { d->tabSwitchCompressor->stop(); } } } void KisMainWindow::dragLeave() { if (d->tabSwitchCompressor->isActive()) { d->tabSwitchCompressor->stop(); } } void KisMainWindow::switchTab(int index) { QTabBar *tabBar = d->findTabBarHACK(); if (!tabBar) return; tabBar->setCurrentIndex(index); } void KisMainWindow::showWelcomeScreen(bool show) { d->widgetStack->setCurrentIndex(!show); } void KisMainWindow::slotFileNew() { const QStringList mimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import); KisOpenPane *startupWidget = new KisOpenPane(this, mimeFilter, QStringLiteral("templates/")); startupWidget->setWindowModality(Qt::WindowModal); startupWidget->setWindowTitle(i18n("Create new document")); KisConfig cfg(true); int w = cfg.defImageWidth(); int h = cfg.defImageHeight(); const double resolution = cfg.defImageResolution(); const QString colorModel = cfg.defColorModel(); const QString colorDepth = cfg.defaultColorDepth(); const QString colorProfile = cfg.defColorProfile(); CustomDocumentWidgetItem item; item.widget = new KisCustomImageWidget(startupWidget, w, h, resolution, colorModel, colorDepth, colorProfile, i18n("Unnamed")); item.icon = "document-new"; item.title = i18n("Custom Document"); startupWidget->addCustomDocumentWidget(item.widget, item.title, "Custom Document", item.icon); QSize sz = KisClipboard::instance()->clipSize(); if (sz.isValid() && sz.width() != 0 && sz.height() != 0) { w = sz.width(); h = sz.height(); } item.widget = new KisImageFromClipboard(startupWidget, w, h, resolution, colorModel, colorDepth, colorProfile, i18n("Unnamed")); item.title = i18n("Create from Clipboard"); item.icon = "tab-new"; startupWidget->addCustomDocumentWidget(item.widget, item.title, "Create from ClipBoard", item.icon); // calls deleteLater connect(startupWidget, SIGNAL(documentSelected(KisDocument*)), KisPart::instance(), SLOT(startCustomDocument(KisDocument*))); // calls deleteLater connect(startupWidget, SIGNAL(openTemplate(QUrl)), KisPart::instance(), SLOT(openTemplate(QUrl))); startupWidget->exec(); // Cancel calls deleteLater... } void KisMainWindow::slotImportFile() { dbgUI << "slotImportFile()"; slotFileOpen(true); } void KisMainWindow::slotFileOpen(bool isImporting) { #ifndef Q_OS_ANDROID QStringList urls = showOpenFileDialog(isImporting); if (urls.isEmpty()) return; Q_FOREACH (const QString& url, urls) { if (!url.isEmpty()) { OpenFlags flags = isImporting ? Import : None; bool res = openDocument(QUrl::fromLocalFile(url), flags); if (!res) { warnKrita << "Loading" << url << "failed"; } } } #else Q_UNUSED(isImporting) d->fileManager->openImportFile(); connect(d->fileManager, SIGNAL(sigFileSelected(QString)), this, SLOT(slotFileSelected(QString))); connect(d->fileManager, SIGNAL(sigEmptyFilePath()), this, SLOT(slotEmptyFilePath())); #endif } void KisMainWindow::slotFileOpenRecent(const QUrl &url) { (void) openDocument(QUrl::fromLocalFile(url.toLocalFile()), None); } void KisMainWindow::slotFileSave() { if (saveDocument(d->activeView->document(), false, false)) { emit documentSaved(); } } void KisMainWindow::slotFileSaveAs() { if (saveDocument(d->activeView->document(), true, false)) { emit documentSaved(); } } void KisMainWindow::slotExportFile() { if (saveDocument(d->activeView->document(), true, true)) { emit documentSaved(); } } void KisMainWindow::slotShowSessionManager() { KisPart::instance()->showSessionManager(); } KoCanvasResourceProvider *KisMainWindow::resourceManager() const { return d->viewManager->canvasResourceProvider()->resourceManager(); } int KisMainWindow::viewCount() const { return d->mdiArea->subWindowList().size(); } const KConfigGroup &KisMainWindow::windowStateConfig() const { return d->windowStateConfig; } void KisMainWindow::saveWindowState(bool restoreNormalState) { if (restoreNormalState) { QAction *showCanvasOnly = d->viewManager->actionCollection()->action("view_show_canvas_only"); if (showCanvasOnly && showCanvasOnly->isChecked()) { showCanvasOnly->setChecked(false); } d->windowStateConfig.writeEntry("ko_geometry", saveGeometry().toBase64()); d->windowStateConfig.writeEntry("State", saveState().toBase64()); if (!d->dockerStateBeforeHiding.isEmpty()) { restoreState(d->dockerStateBeforeHiding); } statusBar()->setVisible(true); menuBar()->setVisible(true); saveWindowSettings(); } else { saveMainWindowSettings(d->windowStateConfig); } } bool KisMainWindow::restoreWorkspaceState(const QByteArray &state) { QByteArray oldState = saveState(); // needed because otherwise the layout isn't correctly restored in some situations Q_FOREACH (QDockWidget *dock, dockWidgets()) { dock->toggleViewAction()->setEnabled(true); dock->hide(); } bool success = KXmlGuiWindow::restoreState(state); if (!success) { KXmlGuiWindow::restoreState(oldState); return false; } return success; } bool KisMainWindow::restoreWorkspace(int workspaceId) { KisWorkspaceResourceSP workspace = KisResourceModelProvider::resourceModel(ResourceType::Workspaces) ->resourceForId(workspaceId).dynamicCast(); bool success = restoreWorkspaceState(workspace->dockerState()); if (activeKisView()) { activeKisView()->resourceProvider()->notifyLoadingWorkspace(workspace); } return success; } QByteArray KisMainWindow::borrowWorkspace(KisMainWindow *other) { QByteArray currentWorkspace = saveState(); if (!d->workspaceBorrowedBy.isNull()) { if (other->id() == d->workspaceBorrowedBy) { // We're swapping our original workspace back d->workspaceBorrowedBy = QUuid(); return currentWorkspace; } else { // Get our original workspace back before swapping with a third window KisMainWindow *borrower = KisPart::instance()->windowById(d->workspaceBorrowedBy); if (borrower) { QByteArray originalLayout = borrower->borrowWorkspace(this); borrower->restoreWorkspaceState(currentWorkspace); d->workspaceBorrowedBy = other->id(); return originalLayout; } } } d->workspaceBorrowedBy = other->id(); return currentWorkspace; } void KisMainWindow::swapWorkspaces(KisMainWindow *a, KisMainWindow *b) { QByteArray workspaceA = a->borrowWorkspace(b); QByteArray workspaceB = b->borrowWorkspace(a); a->restoreWorkspaceState(workspaceB); b->restoreWorkspaceState(workspaceA); } KisViewManager *KisMainWindow::viewManager() const { return d->viewManager; } void KisMainWindow::slotDocumentInfo() { if (!d->activeView->document()) return; KoDocumentInfo *docInfo = d->activeView->document()->documentInfo(); if (!docInfo) return; KoDocumentInfoDlg *dlg = d->activeView->document()->createDocumentInfoDialog(this, docInfo); if (dlg->exec()) { if (dlg->isDocumentSaved()) { d->activeView->document()->setModified(false); } else { d->activeView->document()->setModified(true); } d->activeView->document()->setTitleModified(); } delete dlg; } bool KisMainWindow::slotFileCloseAll() { Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { if (subwin) { if(!subwin->close()) return false; } } updateCaption(); return true; } void KisMainWindow::slotFileQuit() { // Do not close while KisMainWindow has the savingEntryMutex locked, bug409395. // After the background saving job is initiated, KisDocument blocks closing // while it saves itself. if (hackIsSaving()) { return; } KisPart::instance()->closeSession(); } void KisMainWindow::importAnimation() { if (!activeView()) return; KisDocument *document = activeView()->document(); if (!document) return; KisDlgImportImageSequence dlg(this, document); if (dlg.exec() == QDialog::Accepted) { QStringList files = dlg.files(); int firstFrame = dlg.firstFrame(); int step = dlg.step(); KoUpdaterPtr updater = !document->fileBatchMode() ? viewManager()->createUnthreadedUpdater(i18n("Import frames")) : 0; KisAnimationImporter importer(document->image(), updater); KisImportExportErrorCode status = importer.import(files, firstFrame, step); if (!status.isOk() && !status.isInternalError()) { QString msg = status.errorMessage(); if (!msg.isEmpty()) QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not finish import animation:\n%1", msg)); } activeView()->canvasBase()->refetchDataFromImage(); } } void KisMainWindow::slotConfigureToolbars() { saveWindowState(); KEditToolBar edit(factory(), this); connect(&edit, SIGNAL(newToolBarConfig()), this, SLOT(slotNewToolbarConfig())); (void) edit.exec(); applyToolBarLayout(); } void KisMainWindow::slotResetConfigurations() { KisApplication *kisApp = static_cast(qApp); kisApp->askresetConfig(); } void KisMainWindow::slotNewToolbarConfig() { applyMainWindowSettings(d->windowStateConfig); KXMLGUIFactory *factory = guiFactory(); Q_UNUSED(factory); // Check if there's an active view if (!d->activeView) return; plugActionList("toolbarlist", d->toolbarList); applyToolBarLayout(); } void KisMainWindow::slotToolbarToggled(bool toggle) { //dbgUI <<"KisMainWindow::slotToolbarToggled" << sender()->name() <<" toggle=" << true; // The action (sender) and the toolbar have the same name KToolBar * bar = toolBar(sender()->objectName()); if (bar) { if (toggle) { bar->show(); } else { bar->hide(); } if (d->activeView && d->activeView->document()) { saveWindowState(); } } else warnUI << "slotToolbarToggled : Toolbar " << sender()->objectName() << " not found!"; } void KisMainWindow::viewFullscreen(bool fullScreen) { KisConfig cfg(false); cfg.setFullscreenMode(fullScreen); if (fullScreen) { setWindowState(windowState() | Qt::WindowFullScreen); // set } else { setWindowState(windowState() & ~Qt::WindowFullScreen); // reset } d->fullScreenMode->setChecked(isFullScreen()); } void KisMainWindow::setMaxRecentItems(uint _number) { d->recentFiles->setMaxItems(_number); } QDockWidget* KisMainWindow::createDockWidget(KoDockFactoryBase* factory) { QDockWidget* dockWidget = 0; bool lockAllDockers = KisConfig(true).readEntry("LockAllDockerPanels", false); if (!d->dockWidgetsMap.contains(factory->id())) { dockWidget = factory->createDockWidget(); // It is quite possible that a dock factory cannot create the dock; don't // do anything in that case. if (!dockWidget) { warnKrita << "Could not create docker for" << factory->id(); return 0; } dockWidget->setFont(KoDockRegistry::dockFont()); dockWidget->setObjectName(factory->id()); dockWidget->setParent(this); if (lockAllDockers) { if (dockWidget->titleBarWidget()) { dockWidget->titleBarWidget()->setVisible(false); } dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures); } if (dockWidget->widget() && dockWidget->widget()->layout()) dockWidget->widget()->layout()->setContentsMargins(1, 1, 1, 1); Qt::DockWidgetArea side = Qt::RightDockWidgetArea; bool visible = true; switch (factory->defaultDockPosition()) { case KoDockFactoryBase::DockTornOff: dockWidget->setFloating(true); // position nicely? break; case KoDockFactoryBase::DockTop: side = Qt::TopDockWidgetArea; break; case KoDockFactoryBase::DockLeft: side = Qt::LeftDockWidgetArea; break; case KoDockFactoryBase::DockBottom: side = Qt::BottomDockWidgetArea; break; case KoDockFactoryBase::DockRight: side = Qt::RightDockWidgetArea; break; case KoDockFactoryBase::DockMinimized: default: side = Qt::RightDockWidgetArea; visible = false; } KConfigGroup group = d->windowStateConfig.group("DockWidget " + factory->id()); side = static_cast(group.readEntry("DockArea", static_cast(side))); if (side == Qt::NoDockWidgetArea) side = Qt::RightDockWidgetArea; addDockWidget(side, dockWidget); if (!visible) { dockWidget->hide(); } d->dockWidgetsMap.insert(factory->id(), dockWidget); } else { dockWidget = d->dockWidgetsMap[factory->id()]; } #ifdef Q_OS_MACOS dockWidget->setAttribute(Qt::WA_MacSmallSize, true); #endif dockWidget->setFont(KoDockRegistry::dockFont()); connect(dockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(forceDockTabFonts())); return dockWidget; } void KisMainWindow::forceDockTabFonts() { Q_FOREACH (QObject *child, children()) { if (child->inherits("QTabBar")) { ((QTabBar *)child)->setFont(KoDockRegistry::dockFont()); } } } QList KisMainWindow::dockWidgets() const { return d->dockWidgetsMap.values(); } QDockWidget* KisMainWindow::dockWidget(const QString &id) { if (!d->dockWidgetsMap.contains(id)) return 0; return d->dockWidgetsMap[id]; } QList KisMainWindow::canvasObservers() const { QList observers; Q_FOREACH (QDockWidget *docker, dockWidgets()) { KoCanvasObserverBase *observer = dynamic_cast(docker); if (observer) { observers << observer; } else { warnKrita << docker << "is not a canvas observer"; } } return observers; } void KisMainWindow::toggleDockersVisibility(bool visible) { if (!visible) { d->dockerStateBeforeHiding = saveState(); Q_FOREACH (QObject* widget, children()) { if (widget->inherits("QDockWidget")) { QDockWidget* dw = static_cast(widget); if (dw->isVisible()) { dw->hide(); } } } } else { restoreState(d->dockerStateBeforeHiding); } } void KisMainWindow::slotDocumentTitleModified() { updateCaption(); } void KisMainWindow::subWindowActivated() { bool enabled = (activeKisView() != 0); d->mdiCascade->setEnabled(enabled); d->mdiNextWindow->setEnabled(enabled); d->mdiPreviousWindow->setEnabled(enabled); d->mdiTile->setEnabled(enabled); d->close->setEnabled(enabled); d->closeAll->setEnabled(enabled); setActiveSubWindow(d->mdiArea->activeSubWindow()); Q_FOREACH (QToolBar *tb, toolBars()) { if (tb->objectName() == "BrushesAndStuff") { tb->setEnabled(enabled); } } /** * Qt has a weirdness, it has hardcoded shortcuts added to an action * in the window menu. We need to reset the shortcuts for that menu * to nothing, otherwise the shortcuts cannot be made configurable. * * See: https://bugs.kde.org/show_bug.cgi?id=352205 * https://bugs.kde.org/show_bug.cgi?id=375524 * https://bugs.kde.org/show_bug.cgi?id=398729 */ QMdiSubWindow *subWindow = d->mdiArea->currentSubWindow(); if (subWindow) { QMenu *menu = subWindow->systemMenu(); if (menu && menu->actions().size() == 8) { Q_FOREACH (QAction *action, menu->actions()) { action->setShortcut(QKeySequence()); } menu->actions().last()->deleteLater(); } } updateCaption(); d->actionManager()->updateGUI(); } void KisMainWindow::windowFocused() { /** * Notify selection manager so that it could update selection mask overlay */ if (viewManager() && viewManager()->selectionManager()) { viewManager()->selectionManager()->selectionChanged(); } KisPart *kisPart = KisPart::instance(); KisWindowLayoutManager *layoutManager = KisWindowLayoutManager::instance(); if (!layoutManager->primaryWorkspaceFollowsFocus()) return; QUuid primary = layoutManager->primaryWindowId(); if (primary.isNull()) return; if (d->id == primary) { if (!d->workspaceBorrowedBy.isNull()) { KisMainWindow *borrower = kisPart->windowById(d->workspaceBorrowedBy); if (!borrower) return; swapWorkspaces(this, borrower); } } else { if (d->workspaceBorrowedBy == primary) return; KisMainWindow *primaryWindow = kisPart->windowById(primary); if (!primaryWindow) return; swapWorkspaces(this, primaryWindow); } } void KisMainWindow::updateWindowMenu() { QMenu *menu = d->windowMenu->menu(); menu->clear(); menu->addAction(d->newWindow); menu->addAction(d->documentMenu); QMenu *docMenu = d->documentMenu->menu(); docMenu->clear(); QFontMetrics fontMetrics = docMenu->fontMetrics(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) QRect geom = this->geometry(); QPoint p(geom.width() / 2 + geom.left(), geom.height() / 2 + geom.top()); QScreen *screen = qApp->screenAt(p); int fileStringWidth = 300; if (screen) { fileStringWidth = int(screen->availableGeometry().width() * .40f); } #else int fileStringWidth = int(QApplication::desktop()->screenGeometry(this).width() * .40f); #endif Q_FOREACH (QPointer doc, KisPart::instance()->documents()) { if (doc) { QString title = fontMetrics.elidedText(doc->url().toDisplayString(QUrl::PreferLocalFile), Qt::ElideMiddle, fileStringWidth); if (title.isEmpty() && doc->image()) { title = doc->image()->objectName(); } QAction *action = docMenu->addAction(title); action->setIcon(qApp->windowIcon()); connect(action, SIGNAL(triggered()), d->documentMapper, SLOT(map())); d->documentMapper->setMapping(action, doc); } } menu->addAction(d->workspaceMenu); QMenu *workspaceMenu = d->workspaceMenu->menu(); workspaceMenu->clear(); KisResourceIterator resourceIterator(KisResourceModelProvider::resourceModel(ResourceType::Workspaces)); KisMainWindow *m_this = this; while (resourceIterator.hasNext()) { KisResourceItemSP resource = resourceIterator.next(); QAction *action = workspaceMenu->addAction(resource->name()); connect(action, &QAction::triggered, this, [=]() { m_this->restoreWorkspace(resource->id()); }); } workspaceMenu->addSeparator(); connect(workspaceMenu->addAction(i18nc("@action:inmenu", "&Import Workspace...")), &QAction::triggered, this, [&]() { QStringList mimeTypes = KisResourceLoaderRegistry::instance()->mimeTypes(ResourceType::Workspaces); KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument"); dialog.setMimeTypeFilters(mimeTypes); dialog.setCaption(i18nc("@title:window", "Choose File to Add")); QString filename = dialog.filename(); d->workspacemodel->importResourceFile(filename); }); connect(workspaceMenu->addAction(i18nc("@action:inmenu", "&New Workspace...")), &QAction::triggered, [=]() { QString name; auto rserver = KisResourceServerProvider::instance()->workspaceServer(); KisWorkspaceResourceSP workspace(new KisWorkspaceResource("")); workspace->setDockerState(m_this->saveState()); d->viewManager->canvasResourceProvider()->notifySavingWorkspace(workspace); workspace->setValid(true); QString saveLocation = rserver->saveLocation(); QFileInfo fileInfo(saveLocation + name + workspace->defaultFileExtension()); bool fileOverWriteAccepted = false; while(!fileOverWriteAccepted) { name = QInputDialog::getText(this, i18nc("@title:window", "New Workspace..."), i18nc("@label:textbox", "Name:")); if (name.isNull() || name.isEmpty()) { return; } else { fileInfo = QFileInfo(saveLocation + name.split(" ").join("_") + workspace->defaultFileExtension()); if (fileInfo.exists()) { int res = QMessageBox::warning(this, i18nc("@title:window", "Name Already Exists") , i18n("The name '%1' already exists, do you wish to overwrite it?", name) , QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if (res == QMessageBox::Yes) fileOverWriteAccepted = true; } else { fileOverWriteAccepted = true; } } } workspace->setFilename(fileInfo.fileName()); workspace->setName(name); rserver->addResource(workspace); }); // TODO: What to do about delete? // workspaceMenu->addAction(i18nc("@action:inmenu", "&Delete Workspace...")); menu->addSeparator(); menu->addAction(d->close); menu->addAction(d->closeAll); if (d->mdiArea->viewMode() == QMdiArea::SubWindowView) { menu->addSeparator(); menu->addAction(d->mdiTile); menu->addAction(d->mdiCascade); } menu->addSeparator(); menu->addAction(d->mdiNextWindow); menu->addAction(d->mdiPreviousWindow); menu->addSeparator(); QList windows = d->mdiArea->subWindowList(); for (int i = 0; i < windows.size(); ++i) { QPointerchild = qobject_cast(windows.at(i)->widget()); if (child && child->document()) { QString text; if (i < 9) { text = i18n("&%1 %2", i + 1, fontMetrics.elidedText(child->document()->url().toDisplayString(QUrl::PreferLocalFile), Qt::ElideMiddle, fileStringWidth)); } else { text = i18n("%1 %2", i + 1, fontMetrics.elidedText(child->document()->url().toDisplayString(QUrl::PreferLocalFile), Qt::ElideMiddle, fileStringWidth)); } QAction *action = menu->addAction(text); action->setIcon(qApp->windowIcon()); action->setCheckable(true); action->setChecked(child == activeKisView()); connect(action, SIGNAL(triggered()), d->windowMapper, SLOT(map())); d->windowMapper->setMapping(action, windows.at(i)); } } bool showMdiArea = windows.count( ) > 0; if (!showMdiArea) { showWelcomeScreen(true); // see workaround in function in header // keep the recent file list updated when going back to welcome screen reloadRecentFileList(); d->welcomePage->populateRecentDocuments(); } // enable/disable the toolbox docker if there are no documents open Q_FOREACH (QObject* widget, children()) { if (widget->inherits("QDockWidget")) { QDockWidget* dw = static_cast(widget); if ( dw->objectName() == "ToolBox") { dw->setEnabled(showMdiArea); } } } updateCaption(); } void KisMainWindow::updateSubwindowFlags() { bool onlyOne = false; if (d->mdiArea->subWindowList().size() == 1 && d->mdiArea->viewMode() == QMdiArea::SubWindowView) { onlyOne = true; } Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { if (onlyOne) { subwin->setWindowFlags(subwin->windowFlags() | Qt::FramelessWindowHint); subwin->showMaximized(); } else { subwin->setWindowFlags((subwin->windowFlags() | Qt::FramelessWindowHint) ^ Qt::FramelessWindowHint); } } } void KisMainWindow::setActiveSubWindow(QWidget *window) { if (!window) return; QMdiSubWindow *subwin = qobject_cast(window); //dbgKrita << "setActiveSubWindow();" << subwin << d->activeSubWindow; if (subwin && subwin != d->activeSubWindow) { KisView *view = qobject_cast(subwin->widget()); //dbgKrita << "\t" << view << activeView(); if (view && view != activeView()) { d->mdiArea->setActiveSubWindow(subwin); setActiveView(view); } d->activeSubWindow = subwin; } updateWindowMenu(); d->actionManager()->updateGUI(); } void KisMainWindow::configChanged() { KisConfig cfg(true); QMdiArea::ViewMode viewMode = (QMdiArea::ViewMode)cfg.readEntry("mdi_viewmode", (int)QMdiArea::TabbedView); d->mdiArea->setViewMode(viewMode); Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); /** * Dirty workaround for a bug in Qt (checked on Qt 5.6.1): * * If you make a window "Show on top" and then switch to the tabbed mode * the window will continue to be painted in its initial "mid-screen" * position. It will persist here until you explicitly switch to its tab. */ if (viewMode == QMdiArea::TabbedView) { Qt::WindowFlags oldFlags = subwin->windowFlags(); Qt::WindowFlags flags = oldFlags; flags &= ~Qt::WindowStaysOnTopHint; flags &= ~Qt::WindowStaysOnBottomHint; if (flags != oldFlags) { subwin->setWindowFlags(flags); subwin->showMaximized(); } } } #ifdef Q_OS_MACOS updateSubwindowFlags(); #endif KConfigGroup group( KSharedConfig::openConfig(), "theme"); d->themeManager->setCurrentTheme(group.readEntry("Theme", "Krita dark")); d->actionManager()->updateGUI(); QString s = cfg.getMDIBackgroundColor(); KoColor c = KoColor::fromXML(s); QBrush brush(c.toQColor()); d->mdiArea->setBackground(brush); QString backgroundImage = cfg.getMDIBackgroundImage(); if (backgroundImage != "") { QImage image(backgroundImage); QBrush brush(image); d->mdiArea->setBackground(brush); } d->mdiArea->update(); } KisView* KisMainWindow::newView(QObject *document, QMdiSubWindow *subWindow) { KisDocument *doc = qobject_cast(document); KisView *view = addViewAndNotifyLoadingCompleted(doc, subWindow); d->actionManager()->updateGUI(); return view; } void KisMainWindow::newWindow() { KisMainWindow *mainWindow = KisPart::instance()->createMainWindow(); mainWindow->initializeGeometry(); mainWindow->show(); } void KisMainWindow::closeCurrentWindow() { if (d->mdiArea->currentSubWindow()) { d->mdiArea->currentSubWindow()->close(); d->actionManager()->updateGUI(); } } void KisMainWindow::checkSanity() { // print error if the lcms engine is not available if (!KoColorSpaceEngineRegistry::instance()->contains("icc")) { // need to wait 1 event since exiting here would not work. m_errorMessage = i18n("The Krita LittleCMS color management plugin is not installed. Krita will quit now."); m_dieOnError = true; QTimer::singleShot(0, this, SLOT(showErrorAndDie())); return; } KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); if (rserver->resourceCount() == 0) { m_errorMessage = i18n("Krita cannot find any brush presets! Krita will quit now."); m_dieOnError = true; QTimer::singleShot(0, this, SLOT(showErrorAndDie())); return; } } void KisMainWindow::showErrorAndDie() { QMessageBox::critical(0, i18nc("@title:window", "Installation error"), m_errorMessage); if (m_dieOnError) { exit(10); } } void KisMainWindow::showAboutApplication() { KisAboutApplication dlg(this); dlg.exec(); } QPointer KisMainWindow::activeKisView() { if (!d->mdiArea) return 0; QMdiSubWindow *activeSubWindow = d->mdiArea->activeSubWindow(); //dbgKrita << "activeKisView" << activeSubWindow; if (!activeSubWindow) return 0; return qobject_cast(activeSubWindow->widget()); } void KisMainWindow::newOptionWidgets(KoCanvasController *controller, const QList > &optionWidgetList) { KIS_ASSERT_RECOVER_NOOP(controller == KoToolManager::instance()->activeCanvasController()); bool isOurOwnView = false; Q_FOREACH (QPointer view, KisPart::instance()->views()) { if (view && view->canvasController() == controller) { isOurOwnView = view->mainWindow() == this; } } if (!isOurOwnView) return; Q_FOREACH (QWidget *w, optionWidgetList) { #ifdef Q_OS_MACOS w->setAttribute(Qt::WA_MacSmallSize, true); #endif w->setFont(KoDockRegistry::dockFont()); } if (d->toolOptionsDocker) { d->toolOptionsDocker->setOptionWidgets(optionWidgetList); } else { d->viewManager->paintOpBox()->newOptionWidgets(optionWidgetList); } } void KisMainWindow::createActions() { KisActionManager *actionManager = d->actionManager(); actionManager->createStandardAction(KStandardAction::New, this, SLOT(slotFileNew())); actionManager->createStandardAction(KStandardAction::Open, this, SLOT(slotFileOpen())); actionManager->createStandardAction(KStandardAction::Quit, this, SLOT(slotFileQuit())); actionManager->createStandardAction(KStandardAction::ConfigureToolbars, this, SLOT(slotConfigureToolbars())); d->fullScreenMode = actionManager->createStandardAction(KStandardAction::FullScreen, this, SLOT(viewFullscreen(bool))); d->recentFiles = KStandardAction::openRecent(this, SLOT(slotFileOpenRecent(QUrl)), actionCollection()); connect(d->recentFiles, SIGNAL(recentListCleared()), this, SLOT(saveRecentFiles())); KSharedConfigPtr configPtr = KSharedConfig::openConfig(); d->recentFiles->loadEntries(configPtr->group("RecentFiles")); d->saveAction = actionManager->createStandardAction(KStandardAction::Save, this, SLOT(slotFileSave())); d->saveAction->setActivationFlags(KisAction::ACTIVE_IMAGE); d->saveActionAs = actionManager->createStandardAction(KStandardAction::SaveAs, this, SLOT(slotFileSaveAs())); d->saveActionAs->setActivationFlags(KisAction::ACTIVE_IMAGE); d->undo = actionManager->createStandardAction(KStandardAction::Undo, this, SLOT(undo())); d->undo->setActivationFlags(KisAction::ACTIVE_IMAGE); d->redo = actionManager->createStandardAction(KStandardAction::Redo, this, SLOT(redo())); d->redo->setActivationFlags(KisAction::ACTIVE_IMAGE); d->undoActionsUpdateManager.reset(new KisUndoActionsUpdateManager(d->undo, d->redo)); d->undoActionsUpdateManager->setCurrentDocument(d->activeView ? d->activeView->document() : 0); d->importAnimation = actionManager->createAction("file_import_animation"); connect(d->importAnimation, SIGNAL(triggered()), this, SLOT(importAnimation())); d->closeAll = actionManager->createAction("file_close_all"); connect(d->closeAll, SIGNAL(triggered()), this, SLOT(slotFileCloseAll())); d->importFile = actionManager->createAction("file_import_file"); connect(d->importFile, SIGNAL(triggered(bool)), this, SLOT(slotImportFile())); d->exportFile = actionManager->createAction("file_export_file"); connect(d->exportFile, SIGNAL(triggered(bool)), this, SLOT(slotExportFile())); /* The following entry opens the document information dialog. Since the action is named so it intends to show data this entry should not have a trailing ellipses (...). */ d->showDocumentInfo = actionManager->createAction("file_documentinfo"); connect(d->showDocumentInfo, SIGNAL(triggered(bool)), this, SLOT(slotDocumentInfo())); d->themeManager->setThemeMenuAction(new KActionMenu(i18nc("@action:inmenu", "&Themes"), this)); d->themeManager->registerThemeActions(actionCollection()); connect(d->themeManager, SIGNAL(signalThemeChanged()), this, SLOT(slotThemeChanged())); connect(d->themeManager, SIGNAL(signalThemeChanged()), d->welcomePage, SLOT(slotUpdateThemeColors())); d->toggleDockers = actionManager->createAction("view_toggledockers"); KisConfig(true).showDockers(true); d->toggleDockers->setChecked(true); connect(d->toggleDockers, SIGNAL(toggled(bool)), SLOT(toggleDockersVisibility(bool))); d->resetConfigurations = actionManager->createAction("reset_configurations"); connect(d->resetConfigurations, SIGNAL(triggered()), this, SLOT(slotResetConfigurations())); d->toggleDetachCanvas = actionManager->createAction("view_detached_canvas"); d->toggleDetachCanvas->setChecked(false); connect(d->toggleDetachCanvas, SIGNAL(toggled(bool)), SLOT(setCanvasDetached(bool))); setCanvasDetached(false); actionCollection()->addAction("settings_dockers_menu", d->dockWidgetMenu); actionCollection()->addAction("window", d->windowMenu); d->mdiCascade = actionManager->createAction("windows_cascade"); connect(d->mdiCascade, SIGNAL(triggered()), d->mdiArea, SLOT(cascadeSubWindows())); d->mdiTile = actionManager->createAction("windows_tile"); connect(d->mdiTile, SIGNAL(triggered()), d->mdiArea, SLOT(tileSubWindows())); d->mdiNextWindow = actionManager->createAction("windows_next"); connect(d->mdiNextWindow, SIGNAL(triggered()), d->mdiArea, SLOT(activateNextSubWindow())); d->mdiPreviousWindow = actionManager->createAction("windows_previous"); connect(d->mdiPreviousWindow, SIGNAL(triggered()), d->mdiArea, SLOT(activatePreviousSubWindow())); d->newWindow = actionManager->createAction("view_newwindow"); connect(d->newWindow, SIGNAL(triggered(bool)), this, SLOT(newWindow())); d->close = actionManager->createStandardAction(KStandardAction::Close, this, SLOT(closeCurrentWindow())); d->showSessionManager = actionManager->createAction("file_sessions"); connect(d->showSessionManager, SIGNAL(triggered(bool)), this, SLOT(slotShowSessionManager())); actionManager->createStandardAction(KStandardAction::Preferences, this, SLOT(slotPreferences())); for (int i = 0; i < 2; i++) { d->expandingSpacers[i] = new KisAction(i18n("Expanding Spacer")); d->expandingSpacers[i]->setDefaultWidget(new QWidget(this)); d->expandingSpacers[i]->defaultWidget()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); actionManager->addAction(QString("expanding_spacer_%1").arg(i), d->expandingSpacers[i]); } } void KisMainWindow::applyToolBarLayout() { const bool isPlastiqueStyle = style()->objectName() == "plastique"; Q_FOREACH (KToolBar *toolBar, toolBars()) { toolBar->layout()->setSpacing(4); if (isPlastiqueStyle) { toolBar->setContentsMargins(0, 0, 0, 2); } //Hide text for buttons with an icon in the toolbar Q_FOREACH (QAction *ac, toolBar->actions()){ if (ac->icon().pixmap(QSize(1,1)).isNull() == false){ ac->setPriority(QAction::LowPriority); }else { ac->setIcon(QIcon()); } } } } void KisMainWindow::initializeGeometry() { // if the user didn's specify the geometry on the command line (does anyone do that still?), // we first figure out some good default size and restore the x,y position. See bug 285804Z. KConfigGroup cfg = d->windowStateConfig; QByteArray geom = QByteArray::fromBase64(cfg.readEntry("ko_geometry", QByteArray())); if (!restoreGeometry(geom)) { const int scnum = QApplication::desktop()->screenNumber(parentWidget()); QRect desk = QGuiApplication::screens().at(scnum)->availableVirtualGeometry(); quint32 x = desk.x(); quint32 y = desk.y(); quint32 w = 0; quint32 h = 0; // Default size -- maximize on small screens, something useful on big screens const int deskWidth = desk.width(); if (deskWidth > 1024) { // a nice width, and slightly less than total available // height to compensate for the window decs w = (deskWidth / 3) * 2; h = (desk.height() / 3) * 2; } else { w = desk.width(); h = desk.height(); } x += (desk.width() - w) / 2; y += (desk.height() - h) / 2; move(x,y); setGeometry(geometry().x(), geometry().y(), w, h); } d->fullScreenMode->setChecked(isFullScreen()); } void KisMainWindow::showManual() { QDesktopServices::openUrl(QUrl("https://docs.krita.org")); } void KisMainWindow::windowScreenChanged(QScreen *screen) { emit screenChanged(); d->screenConnectionsStore.clear(); d->screenConnectionsStore.addConnection(screen, SIGNAL(physicalDotsPerInchChanged(qreal)), this, SIGNAL(screenChanged())); } void KisMainWindow::slotXmlGuiMakingChanges(bool finished) { if (finished) { subWindowActivated(); } } #include diff --git a/libs/widgets/CMakeLists.txt b/libs/widgets/CMakeLists.txt index 0f02994eeb..9244804bb7 100644 --- a/libs/widgets/CMakeLists.txt +++ b/libs/widgets/CMakeLists.txt @@ -1,119 +1,115 @@ add_subdirectory( tests ) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(kritawidgets_LIB_SRCS KoVBox.cpp KoDialog.cpp KoZoomWidget.cpp KoAspectButton.cpp - KoPagePreviewWidget.cpp KoSliderCombo.cpp KoColorPopupButton.cpp KoConfigAuthorPage.cpp KoUnitDoubleSpinBox.cpp KoZoomAction.cpp KoZoomController.cpp KoZoomInput.cpp KoZoomHandler.cpp KoZoomMode.cpp KoDpi.cpp KoColorPatch.cpp KoColorPopupAction.cpp KoColorSetWidget.cpp KoColorSlider.cpp KoTriangleColorSelector.cpp KoResourcePopupAction.cpp KoRuler.cpp KoResourceServerProvider.cpp KoLineStyleSelector.cpp KoLineStyleItemDelegate.cpp KoLineStyleModel.cpp KoTitledTabWidget.cpp KoToolBoxButton.cpp KoToolBox.cpp KoToolBoxDocker.cpp KoToolBoxFactory.cpp KoToolDocker.cpp - KoPageLayoutWidget.cpp - KoPageLayoutDialog.cpp KoShadowConfigWidget.cpp KoMarkerSelector.cpp KoMarkerModel.cpp KoMarkerItemDelegate.cpp KoDocumentInfoDlg.cpp WidgetsDebug.cpp kis_file_name_requester.cpp KisColorSelectorInterface.cpp KoAnchorSelectionWidget.cpp KisGradientSlider.cpp KisGradientSliderWidget.cpp kis_color_input.cpp # classes used by internal color selector kis_spinbox_color_selector.cpp KisSpinboxHSXSelector.cpp KisVisualColorSelector.cpp KisVisualColorSelectorShape.cpp KisVisualEllipticalSelectorShape.cpp KisVisualRectangleSelectorShape.cpp KisVisualTriangleSelectorShape.cpp KisScreenColorPickerBase.cpp KisDlgInternalColorSelector.cpp KisPaletteModel.cpp KisPaletteDelegate.cpp kis_palette_view.cpp KisPaletteChooser.cpp KisPaletteComboBox.cpp kis_color_button.cpp ) ki18n_wrap_ui( kritawidgets_LIB_SRCS KoConfigAuthorPage.ui koDocumentInfoAboutWidget.ui koDocumentInfoAuthorWidget.ui wdg_file_name_requester.ui - KoPageLayoutWidget.ui KoShadowConfigWidget.ui WdgDlgInternalColorSelector.ui WdgPaletteListWidget.ui ) add_library(kritawidgets SHARED ${kritawidgets_LIB_SRCS}) generate_export_header(kritawidgets BASE_NAME kritawidgets) target_link_libraries(kritawidgets kritaodf kritaglobal kritaflake kritapigment kritawidgetutils kritaresources kritaresourcewidgets Qt5::PrintSupport KF5::CoreAddons KF5::ConfigGui KF5::GuiAddons KF5::WidgetsAddons KF5::ConfigCore KF5::Completion ) if(X11_FOUND) target_link_libraries(kritawidgets Qt5::X11Extras ${X11_LIBRARIES}) endif() set_target_properties(kritawidgets PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritawidgets ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/libs/widgets/KoPageLayoutDialog.cpp b/libs/widgets/KoPageLayoutDialog.cpp deleted file mode 100644 index 26f2c8b625..0000000000 --- a/libs/widgets/KoPageLayoutDialog.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* This file is part of the KDE project - * Copyright (C) 2007,2010 Thomas Zander - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "KoPageLayoutDialog.h" - -#include "KoPageLayoutWidget.h" -#include "KoPagePreviewWidget.h" - -#include -#include - -#include -#include -#include -#include - -class Q_DECL_HIDDEN KoPageLayoutDialog::Private -{ -public: - Private() : pageLayoutWidget(0), documentCheckBox(0) {} - KoPageLayoutWidget *pageLayoutWidget; - QCheckBox *documentCheckBox; -}; - - -KoPageLayoutDialog::KoPageLayoutDialog(QWidget *parent, const KoPageLayout &layout) - : KPageDialog(parent) - , d(new Private) -{ - setWindowTitle(i18n("Page Layout")); - setFaceType(KPageDialog::Tabbed); - - QWidget *widget = new QWidget(this); - addPage(widget, i18n("Page")); - - QHBoxLayout *lay = new QHBoxLayout(widget); - - d->pageLayoutWidget = new KoPageLayoutWidget(widget, layout); - d->pageLayoutWidget->showUnitchooser(false); - lay->addWidget(d->pageLayoutWidget,1); - - KoPagePreviewWidget *prev = new KoPagePreviewWidget(widget); - // use not original layout, but "fixed" one (e.g. with 0 values) as now hold by pageLayoutWidget - prev->setPageLayout(d->pageLayoutWidget->pageLayout()); - lay->addWidget(prev, 1); - - connect (d->pageLayoutWidget, SIGNAL(layoutChanged(KoPageLayout)), - prev, SLOT(setPageLayout(KoPageLayout))); - connect (d->pageLayoutWidget, SIGNAL(layoutChanged(KoPageLayout)), - this, SLOT(setPageLayout(KoPageLayout))); - connect (d->pageLayoutWidget, SIGNAL(unitChanged(KoUnit)), - this, SIGNAL(unitChanged(KoUnit))); -} - -KoPageLayoutDialog::~KoPageLayoutDialog() -{ - delete d; -} - -KoPageLayout KoPageLayoutDialog::pageLayout() const -{ - return d->pageLayoutWidget->pageLayout(); -} - -void KoPageLayoutDialog::setPageLayout(const KoPageLayout &layout) -{ - d->pageLayoutWidget->setPageLayout(layout); -} - -void KoPageLayoutDialog::accept() -{ - KPageDialog::accept(); - deleteLater(); -} - -void KoPageLayoutDialog::reject() -{ - KPageDialog::reject(); - deleteLater(); -} - -bool KoPageLayoutDialog::applyToDocument() const -{ - return d->documentCheckBox && d->documentCheckBox->isChecked(); -} - -void KoPageLayoutDialog::showApplyToDocument(bool on) -{ - if (on && d->documentCheckBox == 0) { - for (int i = 0; i < children().count(); ++i) { - if (QDialogButtonBox *buttonBox = qobject_cast(children()[i])) { - d->documentCheckBox = new QCheckBox(i18n("Apply to document"), buttonBox); - d->documentCheckBox->setChecked(true); - buttonBox->addButton(d->documentCheckBox, QDialogButtonBox::ResetRole); - break; - } - } - - Q_ASSERT(d->pageLayoutWidget); - connect (d->documentCheckBox, SIGNAL(toggled(bool)), - d->pageLayoutWidget, SLOT(setApplyToDocument(bool))); - } else if (d->documentCheckBox) { - d->documentCheckBox->setVisible(on); - } -} - -void KoPageLayoutDialog::showTextDirection(bool on) -{ - d->pageLayoutWidget->showTextDirection(on); -} - -void KoPageLayoutDialog::showPageSpread(bool on) -{ - d->pageLayoutWidget->showPageSpread(on); -} - -void KoPageLayoutDialog::setPageSpread(bool pageSpread) -{ - d->pageLayoutWidget->setPageSpread(pageSpread); -} - -void KoPageLayoutDialog::showUnitchooser(bool on) -{ - d->pageLayoutWidget->showUnitchooser(on); -} - -void KoPageLayoutDialog::setUnit(const KoUnit &unit) -{ - d->pageLayoutWidget->setUnit(unit); -} - diff --git a/libs/widgets/KoPageLayoutWidget.cpp b/libs/widgets/KoPageLayoutWidget.cpp deleted file mode 100644 index 7fb2d7261f..0000000000 --- a/libs/widgets/KoPageLayoutWidget.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/* This file is part of the KDE project - * Copyright (C) 2007, 2010 Thomas Zander - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "KoPageLayoutWidget.h" - -#include - -#include - -#include - -class Q_DECL_HIDDEN KoPageLayoutWidget::Private -{ -public: - Ui::KoPageLayoutWidget widget; - KoPageLayout pageLayout; - KoUnit unit; - - QButtonGroup *orientationGroup; - bool marginsEnabled; - bool allowSignals; -}; - - -KoPageLayoutWidget::KoPageLayoutWidget(QWidget *parent, const KoPageLayout &layout) - : QWidget(parent) - , d(new Private) -{ - d->widget.setupUi(this); - - d->pageLayout = layout; - d->marginsEnabled = true; - d->allowSignals = true; - d->orientationGroup = new QButtonGroup(this); - d->orientationGroup->addButton(d->widget.portrait, KoPageFormat::Portrait); - d->orientationGroup->addButton(d->widget.landscape, KoPageFormat::Landscape); - - QButtonGroup *group2 = new QButtonGroup(this); - group2->addButton(d->widget.singleSided); - group2->addButton(d->widget.facingPages); - // the two sets of labels we use might have different lengths; make sure this does not create a 'jumping' ui - d->widget.facingPages->setChecked(true); - facingPagesChanged(); - int width = qMax(d->widget.leftLabel->width(), d->widget.rightLabel->width()); - d->widget.singleSided->setChecked(true); - facingPagesChanged(); - width = qMax(width, qMax(d->widget.leftLabel->width(), d->widget.rightLabel->width())); - d->widget.leftLabel->setMinimumSize(QSize(width, 5)); - - d->widget.units->addItems(KoUnit::listOfUnitNameForUi(KoUnit::HidePixel)); - d->widget.sizes->addItems(KoPageFormat::localizedPageFormatNames()); - setPageSpread(false); - - connect(d->widget.sizes, SIGNAL(currentIndexChanged(int)), this, SLOT(sizeChanged(int))); - connect(d->widget.units, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int))); - connect(group2, SIGNAL(buttonClicked(int)), this, SLOT(facingPagesChanged())); - connect(d->orientationGroup, SIGNAL(buttonClicked(int)), this, SLOT(orientationChanged())); - connect(d->widget.width, SIGNAL(valueChangedPt(qreal)), this, SLOT(optionsChanged())); - connect(d->widget.height, SIGNAL(valueChangedPt(qreal)), this, SLOT(optionsChanged())); - connect(d->widget.topMargin, SIGNAL(valueChangedPt(qreal)), this, SLOT(marginsChanged())); - connect(d->widget.bottomMargin, SIGNAL(valueChangedPt(qreal)), this, SLOT(marginsChanged())); - connect(d->widget.bindingEdgeMargin, SIGNAL(valueChangedPt(qreal)), this, SLOT(marginsChanged())); - connect(d->widget.pageEdgeMargin, SIGNAL(valueChangedPt(qreal)), this, SLOT(marginsChanged())); - connect(d->widget.width, SIGNAL(valueChangedPt(qreal)), this, SLOT(optionsChanged())); - connect(d->widget.height, SIGNAL(valueChangedPt(qreal)), this, SLOT(optionsChanged())); - - setUnit(KoUnit(KoUnit::Millimeter)); - setPageLayout(layout); - if (layout.format == 0) // make sure we always call this during startup, even if the A3 (index=0) was chosen - sizeChanged(layout.format); - - showTextDirection(false); - /* disable advanced page layout features by default */ - d->widget.facingPageLabel->setVisible(false); - d->widget.facingPages->setVisible(false); - d->widget.singleSided->setVisible(false); - d->widget.stylesLabel->setVisible(false); - d->widget.pageStyle->setVisible(false); -} - -KoPageLayoutWidget::~KoPageLayoutWidget() -{ - delete d; -} - -KoPageLayout KoPageLayoutWidget::pageLayout() const -{ - return d->pageLayout; -} - -void KoPageLayoutWidget::sizeChanged(int row) -{ - if (row < 0) return; - if (! d->allowSignals) return; - d->allowSignals = false; - d->pageLayout.format = static_cast (row); - bool custom = d->pageLayout.format == KoPageFormat::CustomSize; - d->widget.width->setEnabled( custom ); - d->widget.height->setEnabled( custom ); - - if ( !custom ) { - d->pageLayout.width = MM_TO_POINT( KoPageFormat::width( d->pageLayout.format, d->pageLayout.orientation ) ); - d->pageLayout.height = MM_TO_POINT( KoPageFormat::height( d->pageLayout.format, d->pageLayout.orientation ) ); - if (d->widget.facingPages->isChecked()) // is pagespread - d->pageLayout.width *= 2; - } - - d->widget.width->changeValue( d->pageLayout.width ); - d->widget.height->changeValue( d->pageLayout.height ); - - emit layoutChanged(d->pageLayout); - d->allowSignals = true; -} - -void KoPageLayoutWidget::unitChanged(int row) -{ - setUnit(KoUnit::fromListForUi(row, KoUnit::HidePixel)); -} - -void KoPageLayoutWidget::setUnit(const KoUnit &unit) -{ - if (d->unit == unit) - return; - d->unit = unit; - - d->widget.width->setUnit(unit); - d->widget.height->setUnit(unit); - d->widget.topMargin->setUnit(unit); - d->widget.bottomMargin->setUnit(unit); - d->widget.bindingEdgeMargin->setUnit(unit); - d->widget.pageEdgeMargin->setUnit(unit); - d->widget.units->setCurrentIndex(unit.indexInListForUi(KoUnit::HidePixel)); - - emit unitChanged(d->unit); -} - -void KoPageLayoutWidget::setPageLayout(const KoPageLayout &layout) -{ - if (! d->allowSignals) return; - d->allowSignals = false; - d->pageLayout = layout; - - Q_ASSERT(d->orientationGroup->button( layout.orientation )); - d->orientationGroup->button( layout.orientation )->setChecked( true ); - if (layout.bindingSide >= 0 && layout.pageEdge >= 0) { - d->widget.facingPages->setChecked(true); - d->widget.bindingEdgeMargin->changeValue(layout.bindingSide); - d->widget.pageEdgeMargin->changeValue(layout.pageEdge); - d->pageLayout.leftMargin = -1; - d->pageLayout.rightMargin = -1; - } - else { - d->widget.singleSided->setChecked(true); - d->widget.bindingEdgeMargin->changeValue(layout.leftMargin); - d->widget.pageEdgeMargin->changeValue(layout.rightMargin); - d->pageLayout.pageEdge = -1; - d->pageLayout.bindingSide = -1; - } - facingPagesChanged(); - - d->widget.topMargin->changeValue(layout.topMargin); - d->widget.bottomMargin->changeValue(layout.bottomMargin); - d->allowSignals = true; - d->widget.sizes->setCurrentIndex(layout.format); // calls sizeChanged() -} - -void KoPageLayoutWidget::facingPagesChanged() -{ - if (! d->allowSignals) return; - d->allowSignals = false; - if (d->widget.singleSided->isChecked()) { - d->widget.leftLabel->setText(i18n("Left Edge:")); - d->widget.rightLabel->setText(i18n("Right Edge:")); - } - else { - d->widget.leftLabel->setText(i18n("Binding Edge:")); - d->widget.rightLabel->setText(i18n("Page Edge:")); - } - d->allowSignals = true; - marginsChanged(); - sizeChanged(d->widget.sizes->currentIndex()); -} - -void KoPageLayoutWidget::marginsChanged() -{ - if (! d->allowSignals) return; - d->allowSignals = false; - d->pageLayout.leftMargin = -1; - d->pageLayout.rightMargin = -1; - d->pageLayout.bindingSide = -1; - d->pageLayout.pageEdge = -1; - d->pageLayout.topMargin = d->marginsEnabled?d->widget.topMargin->value():0; - d->pageLayout.bottomMargin = d->marginsEnabled?d->widget.bottomMargin->value():0; - qreal left = d->marginsEnabled?d->widget.bindingEdgeMargin->value():0; - qreal right = d->marginsEnabled?d->widget.pageEdgeMargin->value():0; - if (left + right > d->pageLayout.width - 10) { - // make sure the actual text area is never smaller than 10 points. - qreal diff = d->pageLayout.width - 10 - left - right; - left = qMin(d->pageLayout.width - 10, qMax(qreal(0.0), left - diff / qreal(2.0))); - right = qMax(qreal(0.0), right - d->pageLayout.width - 10 - left); - } - - if (d->widget.singleSided->isChecked()) { - d->pageLayout.leftMargin = left; - d->pageLayout.rightMargin = right; - } - else { - d->pageLayout.bindingSide = left; - d->pageLayout.pageEdge = right; - } - // debugWidgets << " " << d->pageLayout.left <<"|"<< d->pageLayout.bindingSide << "," << - // d->pageLayout.right << "|"<< d->pageLayout.pageEdge; - emit layoutChanged(d->pageLayout); - d->allowSignals = true; -} - -void KoPageLayoutWidget::setTextAreaAvailable(bool available) -{ - d->marginsEnabled = available; - d->widget.margins->setEnabled(available); - marginsChanged(); -} - -void KoPageLayoutWidget::optionsChanged() -{ - if (! d->allowSignals) return; - if (d->widget.sizes->currentIndex() == KoPageFormat::CustomSize) { - d->pageLayout.width = d->widget.width->value(); - d->pageLayout.height = d->widget.height->value(); - } else - sizeChanged(d->widget.sizes->currentIndex()); - - marginsChanged(); -} - -void KoPageLayoutWidget::orientationChanged() -{ - if (! d->allowSignals) return; - d->allowSignals = false; - d->pageLayout.orientation = d->widget.landscape->isChecked() ? KoPageFormat::Landscape : KoPageFormat::Portrait; - - qreal x = d->widget.height->value(); - d->widget.height->changeValue( d->widget.width->value() ); - d->widget.width->changeValue( x ); - - d->allowSignals = true; - optionsChanged(); -} - -void KoPageLayoutWidget::showUnitchooser(bool on) { - d->widget.units->setVisible(on); - d->widget.unitsLabel->setVisible(on); -} - -void KoPageLayoutWidget::showPageSpread(bool on) -{ - d->widget.facingPageLabel->setVisible(on); - d->widget.singleSided->setVisible(on); - d->widget.facingPages->setVisible(on); -} - -void KoPageLayoutWidget::setPageSpread(bool pageSpread) -{ - if (pageSpread) - d->widget.facingPages->setChecked(true); - else - d->widget.singleSided->setChecked(true); -} - -void KoPageLayoutWidget::setApplyToDocument(bool apply) -{ - if (apply) { - d->widget.facingPageLabel->setText(i18n("Facing Pages:")); - d->widget.facingPages->setText(i18n("Facing pages")); - } - else { - d->widget.facingPageLabel->setText(i18n("Page Layout:")); - d->widget.facingPages->setText(i18n("Page spread")); - } -} - -void KoPageLayoutWidget::showTextDirection(bool on) -{ - d->widget.directionLabel->setVisible(on); - d->widget.textDirection->setVisible(on); -} - - -void KoPageLayoutWidget::showPageStyles(bool on) -{ - d->widget.stylesLabel->setVisible(on); - d->widget.pageStyle->setVisible(on); -} - -void KoPageLayoutWidget::setPageStyles(const QStringList &styles) -{ - d->widget.pageStyle->clear(); - d->widget.pageStyle->addItems(styles); -} - -QString KoPageLayoutWidget::currentPageStyle() const -{ - return d->widget.pageStyle->currentText(); -} diff --git a/libs/widgets/KoPageLayoutWidget.h b/libs/widgets/KoPageLayoutWidget.h deleted file mode 100644 index 5362fa9dd7..0000000000 --- a/libs/widgets/KoPageLayoutWidget.h +++ /dev/null @@ -1,72 +0,0 @@ -/* This file is part of the KDE project - * Copyright (C) 2007, 2010 Thomas Zander - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef KO_PAGE_LAYOUT_WIDGET -#define KO_PAGE_LAYOUT_WIDGET - -#include "kritawidgets_export.h" - -#include -#include - -class KoUnit; - -/// the widget that shows the size/margins and other page settings. -class KRITAWIDGETS_EXPORT KoPageLayoutWidget : public QWidget -{ - Q_OBJECT - -public: - KoPageLayoutWidget(QWidget *parent, const KoPageLayout &layout); - ~KoPageLayoutWidget() override; - - KoPageLayout pageLayout() const; - - void setUnit(const KoUnit &unit); - void showUnitchooser(bool on); - void showPageSpread(bool on); - void showPageStyles(bool on); - void setPageStyles(const QStringList &styles); - QString currentPageStyle() const; - void setPageSpread(bool pageSpread); - void showTextDirection(bool on); - -Q_SIGNALS: - void layoutChanged(const KoPageLayout &layout); - void unitChanged(const KoUnit &unit); - -public Q_SLOTS: - void setPageLayout(const KoPageLayout &layout); - void setTextAreaAvailable(bool available); - -private Q_SLOTS: - void sizeChanged(int row); - void unitChanged(int row); - void facingPagesChanged(); - void optionsChanged(); - void marginsChanged(); - void orientationChanged(); - void setApplyToDocument(bool apply); - -private: - class Private; - Private * const d; -}; - -#endif diff --git a/libs/widgets/KoPageLayoutWidget.ui b/libs/widgets/KoPageLayoutWidget.ui deleted file mode 100644 index ec0f1229bb..0000000000 --- a/libs/widgets/KoPageLayoutWidget.ui +++ /dev/null @@ -1,365 +0,0 @@ - - - KoPageLayoutWidget - - - - 0 - 0 - 341 - 417 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - &Unit: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - units - - - - - - - - 0 - 0 - - - - - - - - &Follow style: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - pageStyle - - - - - - - - - - S&ize: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - sizes - - - - - - - - - - Width: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - width - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - 0 - 0 - - - - &Height: - - - height - - - - - - - - - - - - Orientation: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Po&rtrait - - - - - - - Landscape - - - - - - - Facing pages: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Single sided - - - - - - - Facing pages - - - - - - - &Text direction: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - textDirection - - - - - - - - 0 - 0 - - - - - Automatic - - - - - Left to right - - - - - Right to left - - - - - - - - - - Margins - - - - - - Top: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - topMargin - - - - - - - 999.990000000000009 - - - - - - - &Binding edge: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - bindingEdgeMargin - - - - - - - 999.990000000000009 - - - - - - - Pa&ge edge: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - pageEdgeMargin - - - - - - - 999.990000000000009 - - - - - - - Botto&m: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - bottomMargin - - - - - - - 999.990000000000009 - - - - - - - - - - Qt::Vertical - - - QSizePolicy::MinimumExpanding - - - - 0 - 0 - - - - - - - - - KisDoubleParseUnitSpinBox - QDoubleSpinBox -
kis_double_parse_unit_spin_box.h
-
-
- - units - sizes - width - height - portrait - landscape - singleSided - facingPages - textDirection - topMargin - bindingEdgeMargin - pageEdgeMargin - bottomMargin - - - -
diff --git a/libs/widgets/KoPagePreviewWidget.cpp b/libs/widgets/KoPagePreviewWidget.cpp deleted file mode 100644 index 5d9d73b3f3..0000000000 --- a/libs/widgets/KoPagePreviewWidget.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* This file is part of the KDE project - * Copyright (C) 2007 Thomas Zander - * Copyright (C) 2006 Gary Cramblitt - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "KoPagePreviewWidget.h" - -#include -#include -#include -#include - -#include -#include - -class Q_DECL_HIDDEN KoPagePreviewWidget::Private -{ -public: - KoPageLayout pageLayout; - KoColumns columns; -}; - - -KoPagePreviewWidget::KoPagePreviewWidget(QWidget *parent) - : QWidget(parent) - , d(new Private) -{ - setMinimumSize( 100, 100 ); -} - -KoPagePreviewWidget::~KoPagePreviewWidget() -{ - delete d; -} - -void KoPagePreviewWidget::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event); - // resolution[XY] is in pixel per pt - qreal resolutionX = POINT_TO_INCH( static_cast(KoDpi::dpiX()) ); - qreal resolutionY = POINT_TO_INCH( static_cast(KoDpi::dpiY()) ); - - qreal pageWidth = d->pageLayout.width * resolutionX; - qreal pageHeight = d->pageLayout.height * resolutionY; - - const bool pageSpread = (d->pageLayout.bindingSide >= 0 && d->pageLayout.pageEdge >= 0); - qreal sheetWidth = pageWidth / (pageSpread?2:1); - - qreal zoomH = (height() * 90.0 / 100.0) / pageHeight; - qreal zoomW = (width() * 90.0 / 100.0) / pageWidth; - qreal zoom = qMin( zoomW, zoomH ); - - pageWidth *= zoom; - sheetWidth *= zoom; - pageHeight *= zoom; - QPainter painter( this ); - - QRect page = QRectF((width() - pageWidth) / 2.0, - (height() - pageHeight) / 2.0, sheetWidth, pageHeight).toRect(); - - painter.save(); - drawPage(painter, zoom, page, true); - painter.restore(); - if(pageSpread) { - page.moveLeft(page.left() + (int) (sheetWidth)); - painter.save(); - drawPage(painter, zoom, page, false); - painter.restore(); - } - - painter.end(); - - // paint scale -} - -void KoPagePreviewWidget::drawPage(QPainter &painter, qreal zoom, const QRect &dimensions, bool left) -{ - painter.fillRect(dimensions, QBrush(palette().base())); - painter.setPen(QPen(palette().color(QPalette::Dark), 0)); - painter.drawRect(dimensions); - - // draw text areas - QRect textArea = dimensions; - if ((d->pageLayout.topMargin == 0 && d->pageLayout.bottomMargin == 0 && - d->pageLayout.leftMargin == 0 && d->pageLayout.rightMargin == 0) || - ( d->pageLayout.pageEdge == 0 && d->pageLayout.bindingSide == 0)) { - // no margin - return; - } - else { - textArea.setTop(textArea.top() + qRound(zoom * d->pageLayout.topMargin)); - textArea.setBottom(textArea.bottom() - qRound(zoom * d->pageLayout.bottomMargin)); - - qreal leftMargin, rightMargin; - if(d->pageLayout.bindingSide < 0) { // normal margins. - leftMargin = d->pageLayout.leftMargin; - rightMargin = d->pageLayout.rightMargin; - } - else { // margins mirrored for left/right pages - leftMargin = d->pageLayout.bindingSide; - rightMargin = d->pageLayout.pageEdge; - if(left) - std::swap(leftMargin, rightMargin); - } - textArea.setLeft(textArea.left() + qRound(zoom * leftMargin)); - textArea.setRight(textArea.right() - qRound(zoom * rightMargin)); - } - painter.setBrush( QBrush( palette().color(QPalette::ButtonText), Qt::HorPattern ) ); - painter.setPen(QPen(palette().color(QPalette::Dark), 0)); - - // uniform columns? - if (d->columns.columnData.isEmpty()) { - qreal columnWidth = (textArea.width() + (d->columns.gapWidth * zoom)) / d->columns.count; - int width = qRound(columnWidth - d->columns.gapWidth * zoom); - for ( int i = 0; i < d->columns.count; ++i ) - painter.drawRect( qRound(textArea.x() + i * columnWidth), textArea.y(), width, textArea.height()); - } else { - qreal totalRelativeWidth = 0.0; - Q_FOREACH (const KoColumns::ColumnDatum &cd, d->columns.columnData) { - totalRelativeWidth += cd.relativeWidth; - } - int relativeColumnXOffset = 0; - for (int i = 0; i < d->columns.count; i++) { - const KoColumns::ColumnDatum &columnDatum = d->columns.columnData.at(i); - const qreal columnWidth = textArea.width() * columnDatum.relativeWidth / totalRelativeWidth; - const qreal columnXOffset = textArea.width() * relativeColumnXOffset / totalRelativeWidth; - - painter.drawRect( qRound(textArea.x() + columnXOffset + columnDatum.leftMargin * zoom), - qRound(textArea.y() + columnDatum.topMargin * zoom), - qRound(columnWidth - (columnDatum.leftMargin + columnDatum.rightMargin) * zoom), - qRound(textArea.height() - (columnDatum.topMargin + columnDatum.bottomMargin) * zoom)); - - relativeColumnXOffset += columnDatum.relativeWidth; - } - } -} - -void KoPagePreviewWidget::setPageLayout(const KoPageLayout &layout) -{ - d->pageLayout = layout; - update(); -} - -void KoPagePreviewWidget::setColumns(const KoColumns &columns) -{ - d->columns = columns; - update(); -} - diff --git a/libs/widgets/KoPagePreviewWidget.h b/libs/widgets/KoPagePreviewWidget.h deleted file mode 100644 index 91cc3380ec..0000000000 --- a/libs/widgets/KoPagePreviewWidget.h +++ /dev/null @@ -1,54 +0,0 @@ -/* This file is part of the KDE project - * Copyright (C) 2007 Thomas Zander - * Copyright (C) 2006 Gary Cramblitt - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef KO_PAGE_PREVIEW_WIDGET -#define KO_PAGE_PREVIEW_WIDGET - -#include "kritawidgets_export.h" - -#include - -// Needed for building on Windows (cannot use forward declarations) -#include -#include - -/// A widget to preview the KoPageLayout and KoColumns data structures. -class KRITAWIDGETS_EXPORT KoPagePreviewWidget : public QWidget { - Q_OBJECT -public: - explicit KoPagePreviewWidget(QWidget *parent = 0); - ~KoPagePreviewWidget() override; - -protected: - void paintEvent(QPaintEvent *event) override; - -public Q_SLOTS: - void setPageLayout(const KoPageLayout &layout); - void setColumns(const KoColumns &columns); - -private: - void drawPage(QPainter &painter, qreal zoom, const QRect &dimensions, bool left); - -private: - class Private; - Private * const d; -}; - -#endif