15#include <QApplication>
18#include <QStandardPaths>
19#include <QDesktopServices>
24#include <QInputDialog>
27#include <QMdiSubWindow>
29#include <QMutexLocker>
37#include <QStyleFactory>
42#include <QStackedWidget>
47#include <QTemporaryDir>
49#include <QActionGroup>
52#include <kactionmenu.h>
56#include <klocalizedstring.h>
57#include <kaboutdata.h>
64#include <ktoggleaction.h>
71#include <kwindowconfig.h>
72#include <kacceleratormanager.h>
157#include <config-qmdiarea-always-show-subwindow-title.h>
166 QString
id()
const override {
167 return "sharedtooldocker";
186 , styleMenu(new KActionMenu(i18nc(
"@action:inmenu",
"Styles"), parent))
187 , dockWidgetMenu(new KActionMenu(i18nc(
"@action:inmenu",
"&Dockers"), parent))
188 , windowMenu(new KActionMenu(i18nc(
"@action:inmenu",
"&Window"), parent))
189 , documentMenu(new KActionMenu(i18nc(
"@action:inmenu",
"New &View"), parent))
190 , workspaceMenu(new KActionMenu(i18nc(
"@action:inmenu",
"Wor&kspace"), parent))
192 , widgetStack(new QStackedWidget(parent))
193 , mdiArea(new QMdiArea(parent))
197 if (
id.isNull()) this->
id = QUuid::createUuid();
199 welcomeScroller =
new QScrollArea();
200 welcomeScroller->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
201 welcomeScroller->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
202 welcomeScroller->setWidget(welcomePage);
203 welcomeScroller->setWidgetResizable(
true);
205 widgetStack->addWidget(welcomeScroller);
206 widgetStack->addWidget(mdiArea);
207 mdiArea->setTabsMovable(
true);
208 mdiArea->setActivationOrder(QMdiArea::ActivationHistoryOrder);
209 mdiArea->setDocumentMode(
true);
210 mdiArea->setOption(QMdiArea::DontMaximizeSubWindowOnActivation);
211#ifdef HAVE_QMDIAREA_ALWAYS_SHOW_SUBWINDOW_TITLE
212 mdiArea->setOption(QMdiArea::AlwaysShowSubwindowNameInTitleBar);
219 qDeleteAll(toolbarList);
232 bool firstTime {
true};
233 bool windowSizeDirty {
false};
265 KActionMenu *styleMenu {
nullptr};
266 QActionGroup* styleActions {
nullptr};
269 KActionMenu *dockWidgetMenu {
nullptr};
270 KActionMenu *windowMenu {
nullptr};
271 KActionMenu *documentMenu {
nullptr};
272 KActionMenu *workspaceMenu {
nullptr};
287 QCloseEvent *deferredClosingEvent {
nullptr};
291 QScrollArea *welcomeScroller {
nullptr};
295 QStackedWidget *widgetStack {
nullptr};
297 QMdiArea *mdiArea {
nullptr};
298 QMdiSubWindow *activeSubWindow {
nullptr};
314 return viewManager->actionManager();
318 QObjectList objects = mdiArea->children();
319 Q_FOREACH (QObject *
object, objects) {
320 QTabBar *bar = qobject_cast<QTabBar*>(
object);
336 widget->setEnabled(
false);
349 KAcceleratorManager::setNoAccel(
this);
352 connect(
d->workspacemodel, SIGNAL(modelReset()),
this, SLOT(
updateWindowMenu()));
353 connect(
d->workspacemodel, SIGNAL(rowsInserted(QModelIndex,
int,
int)),
this, SLOT(
updateWindowMenu()));
354 connect(
d->workspacemodel, SIGNAL(rowsRemoved(QModelIndex,
int,
int)),
this, SLOT(
updateWindowMenu()));
357 KConfigGroup group( KSharedConfig::openConfig(),
"theme");
361 d->windowStateConfig = KSharedConfig::openConfig()->group(
"MainWindow");
364 setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
365 setDockNestingEnabled(
true);
373 qApp->setStartDragDistance(25);
376 connect(
this, SIGNAL(
themeChanged()),
d->viewManager, SLOT(updateIcons()));
397 d->toolOptionsDocker = qobject_cast<KoToolDocker*>(
createDockWidget(&toolDockerFactory));
398 if (
d->toolOptionsDocker) {
399 d->toolOptionsDocker->toggleViewAction()->setEnabled(
true);
403 QMap<QString, QAction*> dockwidgetActions;
406 dockwidgetActions[toolbox->toggleViewAction()->text()] = toolbox->toggleViewAction();
412 dockwidgetActions[dw->toggleViewAction()->text()] = dw->toggleViewAction();
416 if (
d->toolOptionsDocker) {
417 dockwidgetActions[
d->toolOptionsDocker->toggleViewAction()->text()] =
d->toolOptionsDocker->toggleViewAction();
421 Q_FOREACH (QString title, dockwidgetActions.keys()) {
422 d->dockWidgetMenu->addAction(dockwidgetActions[title]);
427 d->styleActions =
new QActionGroup(
this);
430#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
436 Q_FOREACH (QString styleName, QStyleFactory::keys()) {
439 if (styleName.toLower().contains(
"android")) {
443 if (qgetenv(
"KRITA_NO_STYLE_OVERRIDE").isEmpty()) {
444 if (!allowableStyles.contains(styleName.toLower())) {
448 action =
new QAction(styleName,
d->styleActions);
449 action->setCheckable(
true);
450 d->actionMap.insert(styleName,
action);
451 d->styleMenu->addAction(
d->actionMap.value(styleName));
456 QString styleFromConfig = cfg.
widgetStyle().toLower();
457 QString styleToSelect = styleFromConfig ==
"" ? style()->objectName().toLower() : styleFromConfig;
459 Q_FOREACH (
auto key,
d->actionMap.keys()) {
460 if(key.toLower() == styleToSelect) {
461 d->actionMap.value(key)->setChecked(
true);
465 connect(
d->styleActions, SIGNAL(triggered(QAction*)),
477 if ((wdg->features() & QDockWidget::DockWidgetClosable) == 0) {
478 wdg->setVisible(
true);
485 if (mainwindowObserver) {
490 d->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
491 d->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
492 d->mdiArea->setTabPosition(QTabWidget::North);
493 d->mdiArea->setTabsClosable(
true);
494 d->mdiArea->setAcceptDrops(
true);
498 setCentralWidget(
d->widgetStack);
499 d->widgetStack->setCurrentIndex(0);
502 connect(
d->windowMapper, SIGNAL(mapped(QWidget*)),
this, SLOT(
setActiveSubWindow(QWidget*)));
503 connect(
d->documentMapper, SIGNAL(mapped(QObject*)),
this, SLOT(
newView(QObject*)));
511 d->welcomePage->setMainWindow(
this);
519 d->helpMenu =
new KisKHelpMenu(
this, KAboutData::applicationData(),
false);
534 if (helpContentsAction) {
535 actions->
addAction(helpContentsAction->objectName(), helpContentsAction);
537 if (whatsThisAction) {
538 actions->
addAction(whatsThisAction->objectName(), whatsThisAction);
540 if (reportBugAction) {
541 actions->
addAction(reportBugAction->objectName(), reportBugAction);
543 if (switchLanguageAction) {
544 actions->
addAction(switchLanguageAction->objectName(), switchLanguageAction);
546 if (aboutAppAction) {
547 actions->
addAction(aboutAppAction->objectName(), aboutAppAction);
549 if (aboutKdeAction) {
550 actions->
addAction(aboutKdeAction->objectName(), aboutKdeAction);
558 helpAction->disconnect();
559 connect(helpAction, SIGNAL(triggered()),
this, SLOT(
showManual()));
563 QSet<QKeySequence> existingShortcuts;
565 if(
action->shortcut() == QKeySequence(0)) {
569 Q_ASSERT(!existingShortcuts.contains(
action->shortcut()));
570 existingShortcuts.insert(
action->shortcut());
589 Q_FOREACH (QWidget* it,
guiFactory()->containers(
"ToolBar")) {
592 KToggleAction* act =
new KToggleAction(i18n(
"Show %1 Toolbar",
toolBar->windowTitle()),
this);
594 act->setCheckedState(KGuiItem(i18n(
"Hide %1 Toolbar",
toolBar->windowTitle())));
596 act->setChecked(!
toolBar->isHidden());
599 warnUI <<
"Toolbar list contains a " << it->metaObject()->className() <<
" which is not a toolbar!";
608 d->viewManager->updateGUI();
609 d->viewManager->updateIcons();
611 QTimer::singleShot(1000, Qt::CoarseTimer,
this, SLOT(
checkSanity()));
614 using namespace std::placeholders;
615 std::function<
void (
int)> callback(
618 d->tabSwitchCompressor.reset(
623 if (cfg.
readEntry(
"CanvasOnlyActive",
false)) {
624 QString currentWorkspace = cfg.
readEntry<QString>(
"CurrentWorkspace",
"Default");
631 menuBar()->setVisible(
true);
640 setFixedSize(KisApplication::primaryScreen()->availableGeometry().size());
642 QScreen *s = QGuiApplication::primaryScreen();
643 s->setOrientationUpdateMask(Qt::LandscapeOrientation|Qt::InvertedLandscapeOrientation|Qt::PortraitOrientation|Qt::InvertedPortraitOrientation);
649 QAndroidJniObject::callStaticMethod<void>(
"org/qtproject/qt5/android/QtNative",
"setApplicationState",
"(I)V", Qt::ApplicationActive);
652 setAcceptDrops(
true);
653 QTabBar *tabBar =
d->findTabBarHACK();
655 tabBar->setElideMode(Qt::ElideRight);
658 tabBar->setExpanding(
true);
659 tabBar->setAcceptDrops(
true);
660 tabBar->setChangeCurrentOnDrag(
true);
691 delete d->viewManager;
707 if (
d->activeView == view && !subWindow)
return;
710 d->activeView->disconnect(
this);
751 QMdiSubWindow *currentSubWin =
d->mdiArea->currentSubWindow();
752 bool shouldMaximize = currentSubWin ? currentSubWin->isMaximized() :
true;
753 subwin =
d->mdiArea->addSubWindow(imageView);
754 if (shouldMaximize) {
755 subwin->setWindowState(Qt::WindowMaximized);
758 subwin->setWidget(imageView);
761 subwin->setAttribute(Qt::WA_DeleteOnClose,
true);
765 subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.
readEntry<
int>(
"mdi_rubberband", cfg.
useOpenGL()));
766 subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.
readEntry<
int>(
"mdi_rubberband", cfg.
useOpenGL()));
767 subwin->setWindowIcon(qApp->windowIcon());
774 if (
d->mdiArea->subWindowList().size() == 1) {
775 imageView->showMaximized();
820 if (dlgPreferences->editPreferences()) {
843 d->viewManager->showHideScrollbars();
854 d->mdiArea->setPalette(qApp->palette());
855 for (
int i=0; i<
d->mdiArea->subWindowList().size(); i++) {
856 QMdiSubWindow *window =
d->mdiArea->subWindowList().at(i);
858 window->setPalette(qApp->palette());
859 KisView *view = qobject_cast<KisView*>(window->widget());
873 objects.append(aToolBar);
874 while (!objects.isEmpty()) {
875 QWidget*
widget = qobject_cast<QWidget*>(objects.takeFirst());
877 objects.append(
widget->children());
878 widget->setPalette(qApp->palette());
887 KConfigGroup group(KSharedConfig::openConfig(),
"theme");
889 if (group.readEntry(
"Theme",
"") ==
d->themeManager->currentThemeName())
return;
892 group.writeEntry(
"Theme",
d->themeManager->currentThemeName());
897 Q_FOREACH (QWidget* topLevelWidget, qApp->topLevelWidgets()) {
898 if (topLevelWidget ==
this) {
902 if (topLevelWidget->isHidden()) {
906 KisMainWindow *topLevelMainWindow = qobject_cast<KisMainWindow*>(topLevelWidget);
907 if (topLevelMainWindow) {
912 objects.append(topLevelWidget);
913 while (!objects.isEmpty()) {
914 QWidget*
widget = qobject_cast<QWidget*>(objects.takeFirst());
916 objects.append(
widget->children());
933 QString closeButtonImageUrl;
934 QString closeButtonHoverColor;
936 closeButtonImageUrl = QStringLiteral(
":/dark_close-tab.svg");
937 closeButtonHoverColor = QStringLiteral(
"lightcoral");
939 closeButtonImageUrl = QStringLiteral(
":/light_close-tab.svg");
940 closeButtonHoverColor = QStringLiteral(
"darkred");
942 QString tabStyleSheet = QStringLiteral(R
"(
943 QTabBar::close-button {
947 QTabBar::close-button:hover {
948 background-color: %2;
950 QTabBar::close-button:pressed {
951 background-color: red;
954 QHeaderView::section {
959 .arg(closeButtonImageUrl, closeButtonHoverColor);
962 QTabBar* tabBar = d->findTabBarHACK();
964 tabBar->setStyleSheet(tabStyleSheet);
971 return centralWidget() !=
d->widgetStack;
978 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"),
979 "Detach Canvas is unsupported on Android");
984 QWidget *outgoingWidget = centralWidget() ? takeCentralWidget() :
nullptr;
985 QWidget *incomingWidget =
d->canvasWindow->swapMainWidget(outgoingWidget);
987 if (incomingWidget) {
988 setCentralWidget(incomingWidget);
992 d->canvasWindow->show();
994 d->canvasWindow->hide();
996 d->toggleDetachCanvas->setChecked(detach);
1002 return d->canvasWindow;
1017 const QString fileName = QFileInfo(documentPath).fileName();
1019 if (!fileName.isEmpty()) {
1020 d->saveAction->setToolTip(i18n(
"Save as %1", fileName));
1023 d->saveAction->setToolTip(i18n(
"Save"));
1029 Q_UNUSED(readWrite);
1030 d->actionManager()->updateGUI();
1035 if (
d->activeView) {
1036 return d->activeView;
1044 QApplication::processEvents();
1046 if (!QFile(path).exists()) {
1048 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"The file %1 does not exist.", path));
1058 if (!QFile(path).exists()) {
1059 qWarning() <<
"KisMainWindow::openDocumentInternal. Could not open:" << path;
1069 d->firstTime =
true;
1071 connect(newdoc, SIGNAL(canceled(QString)),
this, SLOT(
slotLoadCanceled(QString)));
1090 ( path.startsWith(QDir::tempPath())
1091 || path.startsWith(QDir::homePath())
1093 ( QFileInfo(path).fileName().startsWith(
".krita")
1094 || QFileInfo(path).fileName().startsWith(
"krita")
1098 QString path = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
1099 if (!QFileInfo(path).exists()) {
1100 path = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
1102 newdoc->
setPath(path +
"/" + newdoc->objectName() +
".kra");
1109 Q_FOREACH(QMdiSubWindow *subwindow,
d->mdiArea->subWindowList()) {
1110 KisView *view = qobject_cast<KisView*>(subwindow->widget());
1114 if (view->
document() == document) {
1125 QMdiSubWindow *subWindow)
1145 QTimer::singleShot(0,
this, [
this] {
1147 QTimer::singleShot(0,
this, [
this] {
1160 dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
1162 dialog.setCaption(isImporting ? i18n(
"Import Images") : i18n(
"Open Images"));
1173 KisDocument *newdoc = qobject_cast<KisDocument*>(sender());
1174 if (newdoc && newdoc->
image()) {
1178 disconnect(newdoc, SIGNAL(canceled(QString)),
this, SLOT(
slotLoadCanceled(QString)));
1187 KisDocument* doc = qobject_cast<KisDocument*>(sender());
1190 disconnect(doc, SIGNAL(canceled(QString)),
this, SLOT(
slotLoadCanceled(QString)));
1195 if (!errMsg.isEmpty()) {
1197 QMessageBox::critical(
this, i18nc(
"@title:window",
"Krita"), errMsg);
1208 KisDocument* doc = qobject_cast<KisDocument*>(sender());
1211 disconnect(doc, SIGNAL(canceled(QString)),
this, SLOT(
slotSaveCanceled(QString)));
1214 if (
d->deferredClosingEvent) {
1221 std::unique_lock<QMutex> l(
d->savingEntryMutex, std::try_to_lock);
1222 return !l.owns_lock();
1227 QFileInfo from(fileName);
1230 QFile::remove(to.canonicalFilePath());
1232 return QFile::copy(fileName, to.absoluteFilePath());
1238 qreal scale = qreal(size)/qreal(qMax(geometry().width(), geometry().height()));
1239 QImage
layoutThumbnail = QImage(qRound(geometry().width()*scale), qRound(geometry().height()*scale), QImage::Format_ARGB32);
1243 Q_FOREACH(
const QObject *child, children()) {
1244 if (child->isWidgetType()) {
1245 const QWidget *w =
static_cast<const QWidget *
>(child);
1247 if (w->isVisible() && !w->property(
"_kis_excludeFromLayoutThumbnail").toBool()) {
1248 QRect wRect = QRectF(w->geometry().x()*scale
1249 , w->geometry().y()*scale
1250 , w->geometry().width()*scale
1251 , w->geometry().height()*scale
1254 wRect = wRect.intersected(
layoutThumbnail.rect().adjusted(-1, -1, -1, -1));
1256 gc.setBrush(this->
palette().window());
1257 if (w ==
d->widgetStack) {
1258 gc.setBrush(
d->mdiArea->background());
1260 gc.setPen(this->
palette().windowText().color());
1282 std::unique_lock<QMutex> l(
d->savingEntryMutex, std::try_to_lock);
1283 if (!l.owns_lock())
return false;
1293 QMessageBox::critical(qApp->activeWindow(),
1294 i18nc(
"@title:window",
"Krita"),
1295 i18n(
"You are saving a file while the image is "
1296 "still rendering. The saved file may be "
1297 "incomplete or corrupted.\n\n"
1298 "Please select a location where the original "
1299 "file will not be overridden!"));
1305 if (document->isRecovered()) {
1309 if (document->path().isEmpty()) {
1314 connect(document, SIGNAL(canceled(QString)),
this, SLOT(
slotSaveCanceled(QString)));
1316 QByteArray nativeFormat = document->nativeFormatMimeType();
1317 QByteArray oldMimeFormat = document->mimeType();
1319 QUrl suggestedURL = QUrl::fromLocalFile(document->path());
1324 if (!mimeFilter.contains(oldMimeFormat)) {
1325 dbgUI <<
"KisMainWindow::saveDocument no export filter for" << oldMimeFormat;
1331 QString suggestedFilename = QFileInfo(suggestedURL.toLocalFile()).completeBaseName();
1333 if (!suggestedFilename.isEmpty()) {
1335 suggestedURL = suggestedURL.adjusted(QUrl::RemoveFilename);
1336 suggestedURL.setPath(suggestedURL.path() + suggestedFilename);
1345 if (document->path().isEmpty() || isExporting || saveas) {
1348 bool justChangingFilterOptions =
false;
1351 dialog.setCaption(isExporting ? i18n(
"Exporting") : i18n(
"Saving As"));
1355 if (isExporting && !
d->lastExportLocation.isEmpty() && !
d->lastExportLocation.contains(QDir::tempPath())) {
1358 QString proposedPath = QFileInfo(
d->lastExportLocation).absolutePath();
1360 QString proposedFileName = suggestedURL.isEmpty() ? document->documentInfo()->aboutInfo(
"title") : QFileInfo(suggestedURL.toLocalFile()).completeBaseName();
1362 QString proposedMimeType =
d->lastExportedFormat.isEmpty() ?
"" :
d->lastExportedFormat;
1366 dialog.setDefaultDir(proposedPath +
"/" + proposedFileName +
"." + proposedExtension,
true);
1367 dialog.setMimeTypeFilters(mimeFilter, proposedMimeType);
1372 QByteArray default_mime_type = cfg.
exportMimeType(
false).toUtf8();
1373 QString proposedMimeType = QString::fromLatin1(default_mime_type);
1376 KConfigGroup group = KSharedConfig::openConfig()->group(
"File Dialogs");
1377 QString proposedPath = group.readEntry(
"SaveAs",
"");
1379 if (proposedPath.isEmpty()) {
1380 proposedPath = group.readEntry(
"OpenDocument",
"");
1383 if (proposedPath.isEmpty()) {
1384 proposedPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
1390 if(default_mime_type ==
"all/mime"){
1391 dialog.setDefaultDir(suggestedURL.isEmpty() ? proposedPath : proposedPath +
"/" + QFileInfo(suggestedURL.toLocalFile()).completeBaseName(),
true);
1394 if (default_mime_type !=
"all/mime" && !default_mime_type.isEmpty()) {
1397 dialog.setDefaultDir(suggestedURL.isEmpty() ? proposedPath : proposedPath +
"/" + QFileInfo(suggestedURL.toLocalFile()).completeBaseName() +
"." + proposedExtension,
true);
1402 dialog.setDefaultDir(suggestedURL.isEmpty() ? proposedPath : suggestedURL.toLocalFile(),
true);
1403 default_mime_type = document->mimeType().isEmpty() ? nativeFormat : document->mimeType();
1405 dialog.setMimeTypeFilters(mimeFilter, QString::fromLatin1(default_mime_type));
1408 QString newFilePath = dialog.filename();
1411 if (newFilePath.isEmpty()) {
1416 if (document->documentInfo()->aboutInfo(
"title") == i18n(
"Unnamed")) {
1417 QString fn = newFilePath;
1419 document->documentInfo()->setAboutInfo(
"title", info.completeBaseName());
1422 QByteArray outputFormat = nativeFormat;
1425 outputFormat = outputFormatString.toLatin1();
1429 justChangingFilterOptions = (newFilePath == document->path()) && (outputFormat == document->mimeType());
1432 QString path = QFileInfo(
d->lastExportLocation).absolutePath();
1433 QString filename = QFileInfo(document->path()).completeBaseName();
1434 justChangingFilterOptions = (QFileInfo(newFilePath).absolutePath() == path)
1435 && (QFileInfo(newFilePath).completeBaseName() == filename)
1436 && (outputFormat ==
d->lastExportedFormat);
1439 bool wantToSave =
true;
1442 if (!justChangingFilterOptions) {
1443 if (!document->isNativeFormat(outputFormat))
1449 ret = document->saveAs(newFilePath, outputFormat,
true);
1451 dbgUI <<
"Successful Save As!";
1454 dbgUI <<
"Failed Save As!";
1459 ret = document->exportDocument(newFilePath, outputFormat, isAdvancedExporting,
true);
1461 d->lastExportLocation = newFilePath;
1462 d->lastExportedFormat = outputFormat;
1478 if (document->isModified()) {
1479 ret = document->save(
true, 0);
1483 dbgUI <<
"Failed Save!";
1493 activeView()->document()->undoStack()->undo();
1500 activeView()->document()->undoStack()->redo();
1507 e->setAccepted(
false);
1512 QAction *
action=
d->viewManager->actionCollection()->action(
"view_show_canvas_only");
1514 action->setChecked(
false);
1521 if (!closeAllowed) {
1522 e->setAccepted(
false);
1528 d->mdiArea->closeAllSubWindows();
1532 if (childrenList.isEmpty()) {
1535 d->deferredClosingEvent = e;
1536 d->canvasWindow->close();
1538 e->setAccepted(
false);
1544 KSharedConfigPtr config = KSharedConfig::openConfig();
1546 if (
d->windowSizeDirty ) {
1547 dbgUI <<
"KisMainWindow::saveWindowSettings";
1548 KConfigGroup group =
d->windowStateConfig;
1549 KWindowConfig::saveWindowSize(windowHandle(), group);
1551 d->windowSizeDirty =
false;
1554 if (!
d->activeView ||
d->activeView->document()) {
1557 KConfigGroup group =
d->windowStateConfig;
1561 for (QMap<QString, QDockWidget*>::const_iterator i =
d->dockWidgetsMap.constBegin();
1562 i !=
d->dockWidgetsMap.constEnd(); ++i) {
1563 if (i.value()->widget()) {
1564 KConfigGroup dockGroup = group.group(QString(
"DockWidget ") + i.key());
1565 dockGroup.writeEntry(
"Locked", i.value()->property(
"Locked").toBool());
1566 dockGroup.writeEntry(
"DockArea", (
int) dockWidgetArea(i.value()));
1567 dockGroup.writeEntry(
"xPosition", (
int) i.value()->widget()->x());
1568 dockGroup.writeEntry(
"yPosition", (
int) i.value()->widget()->y());
1570 dockGroup.writeEntry(
"width", (
int) i.value()->widget()->width());
1571 dockGroup.writeEntry(
"height", (
int) i.value()->widget()->height());
1577 KSharedConfig::openConfig()->sync();
1584 d->windowSizeDirty =
true;
1585 KXmlGuiWindow::resizeEvent(e);
1603 QAction *
action=
d->viewManager->actionCollection()->action(
"view_show_canvas_only");
1611 if (!
event->spontaneous()) {
1615 Q_EMIT sigFullscreenOnShow(
true);
1617 return KXmlGuiWindow::showEvent(
event);
1623 if (widgetIndex == 0) {
1624 if (widgetIndexChanged) {
1630 if (
d->mdiArea->subWindowList().isEmpty()) {
1644 statusBar()->setVisible(
KisConfig(
true).showStatusBar());
1649 for (QAction *
action : actions) {
1651 action->setEnabled(widgetIndex);
1664 statusBar()->hide();
1667 for (QToolBar *toolbar : toolbars) {
1668 if (toolbar->objectName() !=
"mainToolBar") {
1676 d->activeView = view;
1678 if (
d->undoActionsUpdateManager) {
1679 d->undoActionsUpdateManager->setCurrentDocument(view ? view->
document() : 0);
1682 d->viewManager->setCurrentView(view);
1684 d->activeViewConnections.clear();
1685 d->activeViewConnections.addConnection(view->
document(),
1686 SIGNAL(sigPathChanged(QString)),
1689 d->activeViewConnections.addConnection(view->
document(),
1690 SIGNAL(sigReadWriteChanged(
bool)),
1701 d->activeViewConnections.clear();
1708 QTabBar *tabBar =
d->findTabBarHACK();
1710 if (!tabBar &&
d->mdiArea->viewMode() == QMdiArea::TabbedView) {
1711 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)!";
1714 if (tabBar && tabBar->isVisible()) {
1715 QPoint pos = tabBar->mapFromGlobal(mapToGlobal(
event->pos()));
1716 if (tabBar->rect().contains(pos)) {
1717 const int tabIndex = tabBar->tabAt(pos);
1719 if (tabIndex >= 0 && tabBar->currentIndex() != tabIndex) {
1720 d->tabSwitchCompressor->start(tabIndex);
1722 }
else if (
d->tabSwitchCompressor->isActive()) {
1723 d->tabSwitchCompressor->stop();
1730 if (
d->tabSwitchCompressor->isActive()) {
1731 d->tabSwitchCompressor->stop();
1738 QTabBar *tabBar =
d->findTabBarHACK();
1739 if (!tabBar)
return;
1741 tabBar->setCurrentIndex(index);
1746 const int currentIndex = show ? 0 : 1;
1747 if (
d->widgetStack->currentIndex() != currentIndex) {
1748 setUpdatesEnabled(
false);
1753 d->widgetStack->setCurrentIndex(currentIndex);
1755 d->widgetStack->setCurrentIndex(currentIndex);
1758 setUpdatesEnabled(
true);
1767 startupWidget->setWindowModality(Qt::WindowModal);
1768 startupWidget->setWindowTitle(i18n(
"Create new document"));
1791 item.
icon =
"document-new";
1792 item.
title = i18n(
"Custom Document");
1804 item.
title = i18n(
"Create from Clipboard");
1805 item.
icon =
"tab-new";
1810 connect(startupWidget, SIGNAL(openTemplate(QUrl)),
KisPart::instance(), SLOT(openTemplate(QUrl)));
1812 startupWidget->exec();
1813 startupWidget->deleteLater();
1818 dbgUI <<
"slotImportFile()";
1830 Q_FOREACH (
const QString& url, urls) {
1832 if (!url.isEmpty()) {
1833 OpenFlags flags = isImporting ?
Import :
None;
1836 warnKrita <<
"Loading" << url <<
"failed";
1849 if (
saveDocument(
d->activeView->document(),
false,
false,
false)) {
1856 if (
saveDocument(
d->activeView->document(),
true,
false,
false)) {
1863 if (
saveDocument(
d->activeView->document(),
true,
true,
false)) {
1869 if (
saveDocument(
d->activeView->document(),
true,
true,
true)) {
1880 return d->viewManager->canvasResourceProvider()->resourceManager();
1885 return d->mdiArea->subWindowList().size();
1890 return d->windowStateConfig;
1896 if (
d->widgetStack->currentIndex() == 0) {
1901 if (restoreNormalState) {
1902 QAction *showCanvasOnly =
d->viewManager->actionCollection()->action(
"view_show_canvas_only");
1904 if (showCanvasOnly && showCanvasOnly->isChecked()) {
1905 showCanvasOnly->setChecked(
false);
1908 d->windowStateConfig.writeEntry(
"ko_geometry", saveGeometry().toBase64());
1909 d->windowStateConfig.writeEntry(
"State", saveState().toBase64());
1912 if (!
d->toggleDockers->isChecked()) {
1913 restoreState(
d->dockerStateBeforeHiding);
1916 statusBar()->setVisible(
true);
1917 menuBar()->setVisible(
true);
1929 QByteArray oldState = saveState();
1935 dock->setProperty(
"Locked",
false);
1936 dock->toggleViewAction()->setEnabled(
true);
1938 if (dock->titleBarWidget() && !dock->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
1939 dock->titleBarWidget()->setVisible(showTitlebars);
1944 bool success = KXmlGuiWindow::restoreState(state);
1947 KXmlGuiWindow::restoreState(oldState);
1949 if (dock->titleBarWidget() && !dock->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
1950 dock->titleBarWidget()->setVisible(showTitlebars || dock->isFloating());
1960 QString md5 = sender()->property(
"md5").toString();
1967 qWarning() <<
"Could not retrieve resource for" << md5;
1976 int actionsCount = 0;
1981 if (
auto collection = c->actionCollection()) {
1982 actionCollections.append(collection);
1983 actionsCount += collection->count();
1992 actionCollections.append(layerActionCollection);
1993 actionsCount += layerActionCollection->
count();
1996 d->commandBar->updateBar(actionCollections, actionsCount);
2002 d->commandBar->activateWindow();
2015 warning = i18n(
"You don't have any resource bundles enabled.");
2019 warning += i18n(
"\nThere are no brush presets available. Please enable a bundle that has presets before continuing.\n");
2020 QMessageBox::critical(
this, i18nc(
"@title:window",
"Krita"), warning);
2029 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"), warning + i18n(
"\nOnly your local resources are available."));
2042 if (dock->titleBarWidget() && !dock->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
2043 dock->titleBarWidget()->setVisible(showTitlebars || dock->isFloating());
2048 activeKisView()->resourceProvider()->notifyLoadingWorkspace(workspace);
2051 d->viewManager->notifyWorkspaceLoaded();
2058 QByteArray currentWorkspace = saveState();
2060 if (!
d->workspaceBorrowedBy.isNull()) {
2061 if (other->
id() ==
d->workspaceBorrowedBy) {
2063 d->workspaceBorrowedBy = QUuid();
2064 return currentWorkspace;
2072 d->workspaceBorrowedBy = other->
id();
2073 return originalLayout;
2078 d->workspaceBorrowedBy = other->
id();
2079 return currentWorkspace;
2085 QByteArray workspaceB = b->borrowWorkspace(a);
2088 b->restoreWorkspaceState(workspaceA);
2093 return d->viewManager;
2098 if (!
d->activeView->document())
2106 KoDocumentInfoDlg *dlg =
d->activeView->document()->createDocumentInfoDialog(
this, docInfo);
2110 d->activeView->document()->setModified(
false);
2112 d->activeView->document()->setModified(
true);
2121 Q_FOREACH (QMdiSubWindow *subwin,
d->mdiArea->subWindowList()) {
2123 if(!subwin->close())
2147 if (!document)
return;
2151 if (dlg.exec() == QDialog::Accepted) {
2153 int firstFrame = dlg.firstFrame();
2154 int step = dlg.step();
2155 bool startFrom1 = dlg.startFrom1();
2156 bool autoAddHoldframes = dlg.autoAddHoldframes();
2162 int isAscending = dlg.isAscending();
2163 KisImportExportErrorCode status = importer.import(files, firstFrame, step, autoAddHoldframes, startFrom1, isAscending);
2168 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"Could not finish import animation:\n%1", msg));
2170 activeView()->canvasBase()->refetchDataFromImage();
2179 if (dlg.exec() == QDialog::Accepted) {
2180 const QTemporaryDir outputLocation(QDir::tempPath() + QDir::separator() +
"krita" + QDir::separator() +
"import_files");
2181 RenderedFrames renderedFrames = dlg.renderFrames(QDir(outputLocation.path()));
2182 dbgFile <<
"Frames rendered to directory: " << outputLocation.path();
2183 QStringList documentInfoList = dlg.documentInfo();
2185 if (renderedFrames.
isEmpty())
return;
2187 dbgFile <<
"Animation Import options: " << documentInfoList;
2190 const int step = documentInfoList[0].toInt();
2191 const int fps = documentInfoList[1].toInt();
2193 const QString
name = QFileInfo(documentInfoList[3]).fileName();
2194 const bool useCurrentDocument = documentInfoList[4].toInt();
2195 bool useDocumentColorSpace =
false;
2197 if ( useCurrentDocument ) {
2200 dbgFile <<
"Current frames:" << document->image()->animationInterface()->totalLength() <<
"total frames:" << totalFrames;
2201 if ( document->image()->animationInterface()->totalLength() < totalFrames ) {
2202 document->image()->animationInterface()->setDocumentRangeStartFrame(0);
2203 document->image()->animationInterface()->setDocumentRangeEndFrame(totalFrames);
2206 const int width = documentInfoList[5].toInt();
2207 const int height = documentInfoList[6].toInt();
2208 const double resolution = documentInfoList[7].toDouble();
2210 const QString colorModel = documentInfoList[8];
2211 const QString colorDepth = documentInfoList[9];
2212 const QString profile = documentInfoList[10];
2213 useDocumentColorSpace = profile !=
"Default";
2216 document->setObjectName(name);
2222 QColor qc(Qt::white);
2226 if (!document->newImage(name, width, height, cs, bgColor,
KisConfig::RASTER_LAYER, 1,
"",
double(resolution / 72) )) {
2227 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"Failed to create new document. Animation import aborted."));
2231 document->image()->animationInterface()->setFramerate(fps);
2232 document->image()->animationInterface()->setDocumentRangeStartFrame(0);
2233 document->image()->animationInterface()->setDocumentRangeEndFrame(totalFrames);
2246 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"Could not finish import animation:\n%1", msg));
2249 activeView()->canvasBase()->refetchDataFromImage();
2250 document->image()->refreshGraphAsync();
2251 document->image()->waitForDone();
2268 dlgAnimationRenderer.setCaption(i18n(
"Render Animation"));
2269 if (dlgAnimationRenderer.exec() == QDialog::Accepted) {
2346 if (
d->activeView &&
d->activeView->document()) {
2350 warnUI <<
"slotToolbarToggled : Toolbar " << sender()->objectName() <<
" not found!";
2359 setWindowState(windowState() | Qt::WindowFullScreen);
2361 setWindowState(windowState() & ~Qt::WindowFullScreen);
2363 d->fullScreenMode->setChecked(isFullScreen());
2371 if (!
d->dockWidgetsMap.contains(
factory->id())) {
2393 if (
dockWidget->titleBarWidget() && !
dockWidget->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
2399 if (!showTitlebars) {
2400 if (
dockWidget->titleBarWidget() && !
dockWidget->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
2401 dockWidget->titleBarWidget()->setVisible(
false);
2403 dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
2406 dockWidget->widget()->layout()->setContentsMargins(1, 1, 1, 1);
2408 Qt::DockWidgetArea side = Qt::RightDockWidgetArea;
2409 bool visible =
true;
2411 switch (
factory->defaultDockPosition()) {
2416 side = Qt::TopDockWidgetArea;
break;
2418 side = Qt::LeftDockWidgetArea;
break;
2420 side = Qt::BottomDockWidgetArea;
break;
2422 side = Qt::RightDockWidgetArea;
break;
2425 side = Qt::RightDockWidgetArea;
2429 KConfigGroup group =
d->windowStateConfig.group(
"DockWidget " +
factory->id());
2430 side =
static_cast<Qt::DockWidgetArea
>(group.readEntry(
"DockArea",
static_cast<int>(side)));
2431 if (side == Qt::NoDockWidgetArea) side = Qt::RightDockWidgetArea;
2438 bool locked = group.readEntry(
"Locked",
false);
2439 if (titleBar && locked) {
2442 else if (
dockWidget->titleBarWidget()->inherits(
"KisUtilityTitleBar") && locked){
2454 dockWidget->setAttribute(Qt::WA_MacSmallSize,
true);
2465 Q_FOREACH (QObject *child, children()) {
2466 if (child->inherits(
"QTabBar")) {
2477 Q_FOREACH (
auto key,
d->actionMap.keys()) {
2478 if(
d->actionMap.value(key)->isChecked()) {
2481 qApp->setStyle(key);
2485#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
2486 if (qApp->style()->objectName() ==
"macintosh") {
2487 d->themeManager->setCurrentTheme(
"System");
2490 if (qApp->style()->name() ==
"macos") {
2491 d->themeManager->setCurrentTheme(
"System");
2501 return d->dockWidgetsMap.values();
2506 if (!
d->dockWidgetsMap.contains(
id))
return 0;
2507 return d->dockWidgetsMap[
id];
2519 observers << observer;
2522 warnKrita << docker <<
"is not a canvas observer";
2533 d->dockerStateBeforeHiding = saveState();
2535 Q_FOREACH (QObject*
widget, children()) {
2536 if (
widget->inherits(
"QDockWidget")) {
2537 QDockWidget* dw =
static_cast<QDockWidget*
>(
widget);
2538 if (dw->isVisible() && !(onWelcomePage && dw->property(
"ShowOnWelcomePage").toBool())) {
2545 restoreState(
d->dockerStateBeforeHiding);
2553 d->mdiCascade->setEnabled(enabled);
2554 d->mdiNextWindow->setEnabled(enabled);
2555 d->mdiPreviousWindow->setEnabled(enabled);
2556 d->mdiTile->setEnabled(enabled);
2557 d->close->setEnabled(enabled);
2558 d->closeAll->setEnabled(enabled);
2571 QMdiSubWindow *subWindow =
d->mdiArea->currentSubWindow();
2573 QMenu *menu = subWindow->systemMenu();
2574 if (menu && menu->actions().size() == 8) {
2575 Q_FOREACH (QAction *
action, menu->actions()) {
2576 action->setShortcut(QKeySequence());
2579 menu->actions().last()->deleteLater();
2583 d->actionManager()->updateGUI();
2600 if (primary.isNull())
return;
2602 if (
d->id == primary) {
2603 if (!
d->workspaceBorrowedBy.isNull()) {
2605 if (!borrower)
return;
2609 if (
d->workspaceBorrowedBy == primary)
return;
2612 if (!primaryWindow)
return;
2620 QMenu *menu =
d->windowMenu->menu();
2624 menu->addAction(
d->newWindow);
2626 menu->addAction(
d->documentMenu);
2628 QMenu *docMenu =
d->documentMenu->menu();
2631 QFontMetrics fontMetrics = docMenu->fontMetrics();
2632 QRect geom = this->geometry();
2633 QPoint
p(geom.width() / 2 + geom.left(), geom.height() / 2 + geom.top());
2634 QScreen *screen = qApp->screenAt(
p);
2635 int fileStringWidth = 300;
2637 fileStringWidth = int(screen->availableGeometry().width() * .40f);
2641 QString title = fontMetrics.elidedText(doc->path(), Qt::ElideMiddle, fileStringWidth);
2642 if (title.isEmpty() && doc->image()) {
2643 title = doc->image()->objectName();
2645 QAction *
action = docMenu->addAction(title);
2646 action->setIcon(qApp->windowIcon());
2647 connect(
action, SIGNAL(triggered()),
d->documentMapper, SLOT(map()));
2648 d->documentMapper->setMapping(
action, doc);
2652 menu->addAction(
d->workspaceMenu);
2659 while (resourceIterator.
hasNext()) {
2662 action->setProperty(
"md5", QVariant::fromValue<QString>(resource->md5sum()));
2666 connect(
workspaceMenu->addAction(i18nc(
"@action:inmenu",
"&Import Workspace...")),
2667 &QAction::triggered,
2674 dialog.setMimeTypeFilters(mimeTypes);
2675 dialog.setCaption(i18nc(
"@title:window",
"Choose File to Add"));
2676 QString filename = dialog.filename();
2681 connect(
workspaceMenu->addAction(i18nc(
"@action:inmenu",
"&New Workspace...")),
2682 &QAction::triggered,
2685 name = QInputDialog::getText(
this, i18nc(
"@title:window",
"New Workspace..."),
2686 i18nc(
"@label:textbox",
"Name:"));
2687 if (name.isEmpty()) {
2692 workspace->setDockerState(m_this->saveState());
2694 workspace->setValid(
true);
2698 d->viewManager->canvasResourceProvider()->notifySavingWorkspace(workspace);
2699 workspace->setValid(
true);
2701 workspace->setFilename(name.replace(
" ",
"_") + workspace->defaultFileExtension());
2702 workspace->setName(name);
2710 menu->addSeparator();
2711 menu->addAction(
d->close);
2712 menu->addAction(
d->closeAll);
2713 if (
d->mdiArea->viewMode() == QMdiArea::SubWindowView) {
2714 menu->addSeparator();
2715 menu->addAction(
d->mdiTile);
2716 menu->addAction(
d->mdiCascade);
2718 menu->addSeparator();
2719 menu->addAction(
d->mdiNextWindow);
2720 menu->addAction(
d->mdiPreviousWindow);
2721 menu->addSeparator();
2724 for (
int i = 0; i < windows.size(); ++i) {
2726 if (child && child->document()) {
2729 text = i18n(
"&%1 %2", i + 1, fontMetrics.elidedText(child->document()->path(), Qt::ElideMiddle, fileStringWidth));
2732 text = i18n(
"%1 %2", i + 1, fontMetrics.elidedText(child->document()->path(), Qt::ElideMiddle, fileStringWidth));
2735 QAction *
action = menu->addAction(text);
2736 action->setIcon(qApp->windowIcon());
2737 action->setCheckable(
true);
2739 connect(
action, SIGNAL(triggered()),
d->windowMapper, SLOT(map()));
2740 d->windowMapper->setMapping(
action, windows.at(i));
2744 bool showMdiArea = windows.count( ) > 0;
2750 Q_FOREACH (QObject*
widget, children()) {
2751 if (
widget->inherits(
"QDockWidget")) {
2752 QDockWidget* dw =
static_cast<QDockWidget*
>(
widget);
2754 if ( dw->objectName() ==
"ToolBox") {
2755 dw->setEnabled(showMdiArea);
2763 bool onlyOne =
false;
2764 if (
d->mdiArea->subWindowList().size() == 1 &&
d->mdiArea->viewMode() == QMdiArea::SubWindowView) {
2767 Q_FOREACH (QMdiSubWindow *subwin,
d->mdiArea->subWindowList()) {
2769 subwin->setWindowFlags(subwin->windowFlags() | Qt::FramelessWindowHint);
2770 subwin->showMaximized();
2772 subwin->setWindowFlags((subwin->windowFlags() | Qt::FramelessWindowHint) ^ Qt::FramelessWindowHint);
2783 QMdiSubWindow *subwin = qobject_cast<QMdiSubWindow *>(window);
2786 if (subwin && subwin !=
d->activeSubWindow) {
2787 KisView *view = qobject_cast<KisView *>(subwin->widget());
2792 d->activeSubWindow = subwin;
2795 d->actionManager()->updateGUI();
2801 QMdiArea::ViewMode viewMode = (QMdiArea::ViewMode)cfg.
readEntry<
int>(
"mdi_viewmode", (
int)QMdiArea::TabbedView);
2802 d->mdiArea->setViewMode(viewMode);
2803 Q_FOREACH (QMdiSubWindow *subwin,
d->mdiArea->subWindowList()) {
2804 subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.
readEntry<
int>(
"mdi_rubberband", cfg.
useOpenGL()));
2805 subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.
readEntry<
int>(
"mdi_rubberband", cfg.
useOpenGL()));
2806 if (viewMode == QMdiArea::TabbedView) {
2807 subwin->setWindowState(Qt::WindowMaximized);
2817 if (viewMode == QMdiArea::TabbedView) {
2818 Qt::WindowFlags oldFlags = subwin->windowFlags();
2819 Qt::WindowFlags flags = oldFlags;
2821 flags &= ~Qt::WindowStaysOnTopHint;
2822 flags &= ~Qt::WindowStaysOnBottomHint;
2824 if (flags != oldFlags) {
2825 subwin->setWindowFlags(flags);
2826 subwin->showMaximized();
2834 KConfigGroup group( KSharedConfig::openConfig(),
"theme");
2836 d->themeManager->setCurrentTheme(group.readEntry(
"Theme",
"Krita dark"));
2838 d->actionManager()->updateGUI();
2843 d->mdiArea->setBackground(brush);
2846 if (backgroundImage !=
"") {
2847 QImage image(backgroundImage);
2848 QBrush brush(image);
2849 d->mdiArea->setBackground(brush);
2852 d->mdiArea->update();
2856 Q_FOREACH (QObject*
widget, children()) {
2857 if (
widget->inherits(
"QDockWidget")) {
2858 QDockWidget* dw =
static_cast<QDockWidget*
>(
widget);
2866 KisDocument *doc = qobject_cast<KisDocument*>(document);
2868 d->actionManager()->updateGUI();
2878 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"),
2879 "Creating a New Main Window is unsupported on Android");
2890 if (
d->mdiArea->currentSubWindow()) {
2891 d->mdiArea->currentSubWindow()->close();
2892 d->actionManager()->updateGUI();
2901 m_errorMessage = i18n(
"The Krita LittleCMS color management plugin is not installed. Krita will quit now.");
2917 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Installation error"),
m_errorMessage);
2931 if (!
d->mdiArea)
return 0;
2941 bool isOurOwnView =
false;
2944 if (view && view->canvasController() == controller) {
2945 isOurOwnView = view->mainWindow() ==
this;
2949 if (!isOurOwnView)
return;
2951 Q_FOREACH (QWidget *w, optionWidgetList) {
2953 w->setAttribute(Qt::WA_MacSmallSize,
true);
2958 if (
d->toolOptionsDocker) {
2959 d->toolOptionsDocker->setOptionWidgets(optionWidgetList);
2962 d->viewManager->paintOpBox()->newOptionWidgets(optionWidgetList);
2993 d->undoActionsUpdateManager->setCurrentDocument(
d->activeView ?
d->activeView->document() : 0);
2996 connect(
d->importAnimation, SIGNAL(triggered()),
this, SLOT(
importAnimation()));
3003 connect(
d->renderAnimation, SIGNAL(triggered()),
this, SLOT(
renderAnimation()));
3014 connect(
d->importFile, SIGNAL(triggered(
bool)),
this, SLOT(
slotImportFile()));
3017 connect(
d->exportFile, SIGNAL(triggered(
bool)),
this, SLOT(
slotExportFile()));
3020 connect(
d->exportFileAdvance, SIGNAL(triggered(
bool)),
this, SLOT(
slotExportAdvance()));
3025 connect(
d->showDocumentInfo, SIGNAL(triggered(
bool)),
this, SLOT(
slotDocumentInfo()));
3027 d->themeManager->setThemeMenuAction(
new KActionMenu(i18nc(
"@action:inmenu",
"&Themes"),
this));
3029 connect(
d->themeManager, SIGNAL(signalThemeChanged()),
this, SLOT(
slotThemeChanged()), Qt::QueuedConnection);
3030 connect(
this, SIGNAL(
themeChanged()),
d->welcomePage, SLOT(slotUpdateThemeColors()), Qt::UniqueConnection);
3036 d->toggleDockers->setChecked(
true);
3044 d->toggleDetachCanvas->setChecked(
false);
3045 connect(
d->toggleDetachCanvas, SIGNAL(toggled(
bool)), SLOT(
setCanvasDetached(
bool)));
3059 connect(
d->mdiCascade, SIGNAL(triggered()),
d->mdiArea, SLOT(cascadeSubWindows()));
3062 connect(
d->mdiTile, SIGNAL(triggered()),
d->mdiArea, SLOT(tileSubWindows()));
3065 connect(
d->mdiNextWindow, SIGNAL(triggered()),
d->mdiArea, SLOT(activateNextSubWindow()));
3068 connect(
d->mdiPreviousWindow, SIGNAL(triggered()),
d->mdiArea, SLOT(activatePreviousSubWindow()));
3072 connect(
d->newWindow, SIGNAL(triggered(
bool)),
this, SLOT(
newWindow()));
3081 connect(
d->commandBarAction, SIGNAL(triggered(
bool)),
this, SLOT(
openCommandBar()));
3085 for (
int i = 0; i < 2; i++) {
3086 d->expandingSpacers[i] =
new KisAction(i18n(
"Expanding Spacer"));
3087 d->expandingSpacers[i]->setDefaultWidget(
new QWidget(
this));
3088 d->expandingSpacers[i]->defaultWidget()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
3103 toolBar->layout()->setSpacing(4);
3104 toolBar->setStyleSheet(
"QToolBar { border: none }");
3107 Q_FOREACH (QAction *ac,
toolBar->actions()){
3108 if (ac->icon().pixmap(QSize(1,1)).isNull() ==
false){
3109 ac->setPriority(QAction::LowPriority);
3111 ac->setIcon(QIcon());
3121 KConfigGroup cfg =
d->windowStateConfig;
3122 QByteArray geom = QByteArray::fromBase64(cfg.readEntry(
"ko_geometry", QByteArray()));
3123 if (!restoreGeometry(geom)) {
3124 QRect desk = this->screen()->availableGeometry();
3126 quint32 x = desk.x();
3127 quint32 y = desk.y();
3132 const int deskWidth = desk.width();
3133 if (deskWidth > 1024) {
3136 w = (deskWidth / 3) * 2;
3137 h = (desk.height() / 3) * 2;
3144 x += (desk.width() - w) / 2;
3145 y += (desk.height() - h) / 2;
3148 setGeometry(geometry().x(), geometry().y(), w, h);
3150 d->fullScreenMode->setChecked(isFullScreen());
3155 QDesktopServices::openUrl(QUrl(
"https://docs.krita.org"));
3161 if (dock->titleBarWidget() && !dock->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
3162 dock->titleBarWidget()->setVisible(show || dock->isFloating());
3179 QScreen *screen = QGuiApplication::primaryScreen();
3181 for (QWindow* window: QGuiApplication::topLevelWindows()) {
3183 if ((window->type() == Qt::Popup)
3184 && (window->flags() & Qt::FramelessWindowHint) == 0
3185 && (window->geometry().topLeft() != QPoint(0, 0))) {
3188 int screenHeight = screen->geometry().width();
3189 int screenWidth = screen->geometry().height();
3192 int new_x = (window->position().x() * screenWidth) / screenHeight;
3193 int new_y = (window->position().y() * screenHeight) / screenWidth;
3196 int winWidth = window->geometry().width();
3197 int winHeight = window->geometry().height();
3200 if (new_x > screenWidth - winWidth) {
3201 new_x = screenWidth - winWidth;
3205 if (new_y > screenHeight - winHeight) {
3206 new_y = screenHeight - winHeight;
3211 window->setPosition(QPoint(new_x, new_y));
3224 return (proxy.rowCount() > 0);
3242 QFile file(xmlPath);
3243 if (!file.exists()) {
3248 if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file)) {
3252 QDomNodeList overridesList = doc.elementsByTagName(QStringLiteral(
"ActionIconOverrides"));
3253 if (!overridesList.isEmpty()) {
3254 QDomElement overridesElement = overridesList.at(0).toElement();
3255 QDomNodeList actions = overridesElement.elementsByTagName(QStringLiteral(
"Action"));
3256 for (
int i = 0; i < actions.count(); ++i) {
3257 QDomElement actionElement = actions.at(i).toElement();
3258 QString name = actionElement.attribute(QStringLiteral(
"name"));
3259 QString icon = actionElement.attribute(QStringLiteral(
"icon"));
3260 if (!name.isEmpty() && !icon.isEmpty()) {
3274 QString menuLocation =
action->property(
"menulocation").toString();
3275 if (!menuLocation.isEmpty()) {
3278 Q_FOREACH(
const QString &name, menuLocation.split(
"/")) {
3279 Q_FOREACH(QAction *candidate, candidates) {
3280 if (candidate->objectName().toLower() == name.toLower()) {
3282 candidates = candidate->menu()->actions();
3286 if (candidates.isEmpty()) {
3291 if (found && found->menu()) {
3294 if (std::find_if(existingActions.begin(),
3295 existingActions.end(),
3297 == existingActions.end()) {
3299 if (std::is_sorted(existingActions.begin(),
3300 existingActions.end(),
3303 auto it = std::upper_bound(existingActions.begin(),
3304 existingActions.end(),
3307 found->menu()->insertAction(it != existingActions.end() ? *it :
nullptr,
action);
3310 found->menu()->addAction(
action);
3318#include <moc_KisMainWindow.cpp>
QList< QString > QStringList
KDE top level main window with predefined action layout
QAction * toolBarMenuAction()
void setStandardToolBarMenuEnabled(bool enable)
void applyMainWindowSettings(const KConfigGroup &config) override
bool event(QEvent *event) override
virtual KisKXMLGUIFactory * guiFactory()
bool isHelpMenuEnabled() const
A KisActionManager class keeps track of KisActions. These actions are always associated with the GUI....
KisAction * createAction(const QString &name)
void addAction(const QString &name, KisAction *action)
KisAction * createStandardAction(KStandardAction::StandardAction, const QObject *receiver, const char *member)
@ ACTIVE_IMAGE
Activate if there is at least one image.
@ IMAGE_IS_WRITABLE
Activate KisDocument::isReadWrite() is active.
@ IMAGE_HAS_ANIMATION
Activate if the image has an animation.
void fromProperties(KisPropertiesConfigurationSP config)
Base class for the Krita app.
void setFavoriteResourceManager(KisFavoriteResourceManager *favoriteResourceManager)
static KisConfigNotifier * instance()
void notifyPixelGridModeChanged()
void notifyConfigChanged(void)
QString widgetStyle(bool defaultValue=false)
qint32 defImageHeight(bool defaultValue=false) const
void setFullscreenMode(const bool value) const
qint32 defImageWidth(bool defaultValue=false) const
void setWidgetStyle(QString name)
void writeEntry(const QString &name, const T &value)
QString getMDIBackgroundColor(bool defaultValue=false) const
QString getMDIBackgroundImage(bool defaultValue=false) const
bool showDockerTitleBars(bool defaultValue=false) const
qreal defImageResolution(bool defaultValue=false) const
QString exportMimeType(bool defaultValue) const
QString defColorProfile(bool defaultValue=false) const
void setShowDockerTitleBars(const bool value) const
bool toolOptionsInDocker(bool defaultValue=false) const
T readEntry(const QString &name, const T &defaultValue=T())
QString defColorModel(bool defaultValue=false) const
bool showDockers(bool defaultValue=false) const
bool useOpenGL(bool defaultValue=false) const
QString defaultColorDepth(bool defaultValue=false) const
void setFileBatchMode(const bool batchMode)
void setPath(const QString &path)
bool importDocument(const QString &path)
bool openPath(const QString &path, OpenFlags flags=None)
openPath Open a Path
bool hasAnimation() const
static KisImageConfigNotifier * instance()
void notifyConfigChanged(void)
KisGroupLayerSP rootLayer() const
KisImageAnimationInterface * animationInterface() const
QString errorMessage() const
bool isInternalError() const
static QStringList supportedMimeTypes(Direction direction)
A container for a set of QAction objects.
void setComponentDisplayName(const QString &displayName)
Q_INVOKABLE QAction * addAction(const QString &name, QAction *action)
QAction * action(int index) const
void addAssociatedWidget(QWidget *widget)
void setAutoSaveSettings(const QString &groupName=QLatin1String("MainWindow"), bool saveWindowSize=true)
void resetAutoSaveSettings()
void saveMainWindowSettings(KConfigGroup &config)
KisToolBar * toolBar(const QString &name=QString())
void closeEvent(QCloseEvent *) override
QList< KisToolBar * > toolBars() const
void setLocalXMLFile(const QString &file)
QAction * action(const char *name) const
KisKXMLGUIFactory * factory() const
void setXMLFile(const QString &file, bool merge=false, bool setXMLDoc=true)
void plugActionList(const QString &name, const QList< QAction * > &actionList)
virtual KisKActionCollection * actionCollection() const
void addClient(KisKXMLGUIClient *client)
QList< KisKXMLGUIClient * > clients() const
QMenu * createPopupMenu() override
KisActionManager * actionManager()
bool installBundle(const QString &fileName) const
Copy the given file into the bundle directory.
QPointer< KisView > activeKisView()
virtual void showAboutApplication()
showAboutApplication show the about box
QScopedPointer< KisUndoActionsUpdateManager > undoActionsUpdateManager
QDockWidget * dockWidget(const QString &id)
void applyActionIconOverridesFromLocalXML()
KisMainWindow(QUuid id=QUuid())
void closeCurrentWindow()
void setCanvasDetached(bool detached)
void guiLoadingFinished()
void dragLeaveEvent(QDragLeaveEvent *event) override
QImage layoutThumbnail()
layoutThumbnail
QTabBar * findTabBarHACK()
KisSignalAutoConnectionsStore activeViewConnections
QStringList showOpenFileDialog(bool isImporting)
void slotUpdateWidgetStyle()
bool checkPaintOpAvailable()
void dragMove(QDragMoveEvent *event)
void showWelcomeScreen(bool show)
void setActiveSubWindow(QWidget *window)
bool windowsLayoutSavingAllowed() const override
void slotLoadCanceled(const QString &)
void orientationChanged()
void slotConfigureToolbars()
QList< KoCanvasObserverBase * > canvasObservers() const override
void slotStoragesWarning(const QString &location=QString())
void slotNewToolbarConfig()
void themeChanged()
This signal is emitted when the color theme changes.
QMdiSubWindow * activeSubWindow
bool restoreWorkspaceState(const QByteArray &state)
KConfigGroup windowStateConfig
KisAction * renderAnimation
void updateSubwindowFlags()
void slotShowSessionManager()
QUuid workspaceBorrowedBy
void slotResetConfigurations()
void showErrorAndDie()
Quits Krita with error message from m_errorMessage.
QMap< QString, QAction * > actionMap
void slotUpdateReadWriteMode(bool readWrite)
bool checkActiveBundlesAvailable()
checkActiveStorages checks whether there is at least one bundle available and at least one paintop pr...
KisView * newView(QObject *document, QMdiSubWindow *subWindow=0)
bool openDocument(const QString &path, OpenFlags flags)
void toggleDockersVisibility(bool visible, bool onWelcomePage=false)
void showDocument(KisDocument *document)
void slotXmlGuiMakingChanges(bool finished)
void newOptionWidgets(KoCanvasController *controller, const QList< QPointer< QWidget > > &optionWidgetList)
KisView * addViewAndNotifyLoadingCompleted(KisDocument *document, QMdiSubWindow *subWindow=0)
QList< QDockWidget * > dockWidgets() const
Return the list of dock widgets belonging to this main window.
bool openDocumentInternal(const QString &path, KisMainWindow::OpenFlags f=KisMainWindow::OpenFlags())
QDockWidget * createDockWidget(KoDockFactoryBase *factory)
void resizeEvent(QResizeEvent *e) override
KisAction * renderAnimationAgain
virtual void showView(KisView *view, QMdiSubWindow *subWindow=0)
showView shows the given view, in subWindow if not null, in a new tab otherwise.
void addView(KisView *view, QMdiSubWindow *subWindow=0)
void setMainWindowLayoutForCurrentMainWidget(int widgetIndex, bool widgetIndexChanged)
QPointer< KisView > activeView
void slotUpdateSaveActionTitle(const QString &documentPath)
void slotPreferences()
slotPreferences open the preferences dialog
void slotFileOpenRecent(const QUrl &)
QString lastExportLocation
bool saveDocument(KisDocument *document, bool saveas, bool isExporting, bool isAdvancedExporting=false)
QByteArray lastExportedFormat
void showEvent(QShowEvent *event) override
KisViewManager * viewManager
bool hackIsSaving() const
void slotFileOpen(bool isImporting=false)
QMap< QString, QDockWidget * > dockWidgetsMap
void subWindowActivated()
void saveWindowState(bool restoreNormalState=false)
bool canvasDetached() const
KActionMenu * workspaceMenu
void viewFullscreen(bool fullScreen)
QList< QAction * > toolbarList
void restoringDone()
This signal is emitted right after the docker states have been successfully restored from config.
void activeViewChanged()
emitted when the current view has changed
KisCanvasWindow * canvasWindow
void initializeGeometry()
void notifyChildViewDestroyed(KisView *view)
void synchronizeDynamicActions()
void adjustLayoutForWelcomePage()
void setActiveView(KisView *view)
Set the active view, this will update the undo/redo actions.
void showDockerTitleBars(bool show)
static void swapWorkspaces(KisMainWindow *a, KisMainWindow *b)
KisAction * importAnimation
QByteArray dockerStateBeforeHiding
void removeRecentFile(QString url)
void slotSaveCanceled(const QString &)
KisAction * importVideoAnimation
Private(KisMainWindow *parent, QUuid id)
void switchTab(int index)
QByteArray borrowWorkspace(KisMainWindow *borrower)
void applyToolBarLayout()
void saveWindowSettings()
~KisMainWindow() override
QScopedPointer< KisSignalCompressorWithParam< int > > tabSwitchCompressor
void dragMoveEvent(QDragMoveEvent *event) override
void slotToolbarToggled(bool toggle)
void closeEvent(QCloseEvent *e) override
KoCanvasResourceProvider * resourceManager() const
The KisMainwindowObserver class is an interface for dock widgets that want to keep track of the main ...
virtual void setViewManager(KisViewManager *kisview)=0
static QStringList suffixesForMimeType(const QString &mimeType)
static QString mimeTypeForFile(const QString &file, bool checkExistingFiles=true)
Find the mimetype for the given filename. The filename must include a suffix.
void addCustomDocumentWidget(QWidget *widget, const QString &title, const QString &untranslatedName, const QString &icon=QString())
bool closeSession(bool keepWindows=false)
void removeMainWindow(KisMainWindow *mainWindow)
KisView * createView(KisDocument *document, KisViewManager *viewManager, QWidget *parent)
static KisPart * instance()
void addDocument(KisDocument *document, bool notify=true)
void queueAddRecentURLToAllMainWindowsOnFileSaved(QUrl url, QUrl oldUrl=QUrl())
void sigMainWindowCreated()
KisMainWindow * windowById(QUuid id) const
KisDocument * createDocument() const
void showSessionManager()
void notifyMainWindowIsBeingCreated(KisMainWindow *mainWindow)
notifyMainWindowIsBeingCreated emits the sigMainWindowCreated signal
KisMainWindow * createMainWindow(QUuid id=QUuid())
static KisRecentDocumentsModelWrapper * instance()
void remove(const QUrl &url)
static KisRecentFilesManager * instance()
The KisResourceIterator class provides an iterator for a KisResourceModel.
const KisResourceItemSP next()
static KisResourceLoaderRegistry * instance()
QStringList mimeTypes(const QString &resourceType) const
The KisResourceModel class provides the main access to resources. It is possible to filter the resour...
static KisResourceServerProvider * instance()
KoResourceServer< KisWorkspaceResource > * workspaceServer()
KisPaintOpPresetResourceServer * paintOpPresetServer()
static QString storageTypeToUntranslatedString(StorageType storageType)
static KoResourceSP importResourceFileWithUserInput(QWidget *widgetParent, QString storageLocation, QString resourceType, QString resourceFilepath)
static bool addResourceWithUserInput(QWidget *widgetParent, KoResourceSP resource, QString storageLocation="")
The KisSignalMapper class bundles signals from identifiable senders.
@ ByStorageType
Pass a string list of storage types.
void setFilter(FilterType filterType, QVariant filter)
static KisStorageModel * instance()
static void log(const QString &message)
Logs with date/time.
A special utility titlebar with a title and controls, as well as a central area for adding frequently...
void setLocked(bool locked)
KisDocument * document() const
void setCurrentView(KisView *view)
KisInputManager * inputManager() const
Filters events and sends them to canvas actions.
QPointer< KoUpdater > createUnthreadedUpdater(const QString &name)
create a new progress updater
KisSelectionManager * selectionManager()
KisImageWSP image() const
Return the image this view is displaying.
KisCanvas2 * canvasBase() const
void slotThemeChanged(QPalette pal)
void setSubWindow(QMdiSubWindow *subWindow)
QPointer< KisDocument > document
void slotLoadingFinished()
void setViewManager(KisViewManager *view)
A widget for displaying if no documents are open. This will display in the MDI area.
QUuid primaryWindowId() const
bool primaryWorkspaceFollowsFocus() const
static KisWindowLayoutManager * instance()
void activeDocumentChanged(KisDocument *document)
Resource for storing of workspaces.
void setObservedCanvas(KoCanvasBase *canvas)
static KoColorSpaceEngineRegistry * instance()
static KoColor fromXML(const QDomElement &elt, const QString &channelDepthId)
void toQColor(QColor *c) const
a convenience method for the above.
@ DockRight
Right of the centra widget.
@ DockTop
Above the central widget.
@ DockBottom
Below the central widget.
@ DockMinimized
Not docked, but reachable via the menu.
@ DockLeft
Left of the centra widget.
@ DockTornOff
Floating as its own top level window.
static KoDockRegistry * instance()
The dialog that shows information about the document.
The class containing all meta information about a document.
const T value(const QString &id) const
void load(const QString &serviceType, const PluginsConfig &config=PluginsConfig(), QObject *owner=0, bool cache=true)
static KoPluginLoader * instance()
static QString locateLocal(const QString &type, const QString &filename, bool createDir=false)
static QString getAppDataLocation()
int resourceCount() const
QSharedPointer< T > resource(const QString &md5, const QString &fileName, const QString &name)
resource retrieves a resource. If the md5sum is not empty, the resource will only be retrieved if a r...
#define KIS_ASSERT_RECOVER_NOOP(cond)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
constexpr const char * currentUnderlyingStyleNameProperty
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)
KRecentFilesAction * openRecent(const QObject *recvr, const char *slot, QObject *parent)
const char * name(StandardAction id)
bool looksLikeXiaomiDevice()
KRITAUI_EXPORT bool render(KisDocument *doc, KisViewManager *viewManager, KisAnimationRenderingOptions encoderOptions)
int size(const Forest< T > &forest)
QIcon loadIcon(const QString &name)
void updateIconCommon(QObject *object)
void updateIcon(QAbstractButton *button)
QFont normalFont()
Gets a font for normal UI widgets to use.
QFont dockFont()
Gets a font with a smallish font size for dock widgets to use.
auto mem_equal_to(MemTypeNoRef Class::*ptr, MemType &&value)
mem_equal_to is an unary functor that compares a member of the object to a given value
auto mem_less(MemTypeNoRef Class::*ptr, MemType &&value)
mem_less is an unary functor that compares a member of the object to a given value
rgba palette[MAX_PALETTE]
virtual void updateSettings()
void blockIfImageIsBusy()
QString icon
icon used in the sidebar. If left empty it will use the unknown icon
QString title
title used in the sidebar. If left empty it will be displayed as "Custom Document"
QWidget * widget
Pointer to the custom document widget.
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
bool framesNeedRelocation() const
QList< int > renderedFrameTargetTimes
QStringList renderedFrameFiles