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>
65#include <ktoggleaction.h>
72#include <kwindowconfig.h>
73#include <kacceleratormanager.h>
158#include <config-qmdiarea-always-show-subwindow-title.h>
167 QString
id()
const override {
168 return "sharedtooldocker";
187 , styleMenu(new KActionMenu(i18nc(
"@action:inmenu",
"Styles"), parent))
188 , dockWidgetMenu(new KActionMenu(i18nc(
"@action:inmenu",
"&Dockers"), parent))
189 , windowMenu(new KActionMenu(i18nc(
"@action:inmenu",
"&Window"), parent))
190 , documentMenu(new KActionMenu(i18nc(
"@action:inmenu",
"New &View"), parent))
191 , workspaceMenu(new KActionMenu(i18nc(
"@action:inmenu",
"Wor&kspace"), parent))
193 , widgetStack(new QStackedWidget(parent))
194 , mdiArea(new QMdiArea(parent))
198 if (
id.isNull()) this->
id = QUuid::createUuid();
200 welcomeScroller =
new QScrollArea();
201 welcomeScroller->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
202 welcomeScroller->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
203 welcomeScroller->setWidget(welcomePage);
204 welcomeScroller->setWidgetResizable(
true);
206 widgetStack->addWidget(welcomeScroller);
207 widgetStack->addWidget(mdiArea);
208 mdiArea->setTabsMovable(
true);
209 mdiArea->setActivationOrder(QMdiArea::ActivationHistoryOrder);
210 mdiArea->setDocumentMode(
true);
211 mdiArea->setOption(QMdiArea::DontMaximizeSubWindowOnActivation);
212#ifdef HAVE_QMDIAREA_ALWAYS_SHOW_SUBWINDOW_TITLE
213 mdiArea->setOption(QMdiArea::AlwaysShowSubwindowNameInTitleBar);
220 qDeleteAll(toolbarList);
233 bool firstTime {
true};
234 bool windowSizeDirty {
false};
266 KActionMenu *styleMenu {
nullptr};
267 QActionGroup* styleActions {
nullptr};
270 KActionMenu *dockWidgetMenu {
nullptr};
271 KActionMenu *windowMenu {
nullptr};
272 KActionMenu *documentMenu {
nullptr};
273 KActionMenu *workspaceMenu {
nullptr};
288 QCloseEvent *deferredClosingEvent {
nullptr};
292 QScrollArea *welcomeScroller {
nullptr};
296 QStackedWidget *widgetStack {
nullptr};
298 QMdiArea *mdiArea {
nullptr};
299 QMdiSubWindow *activeSubWindow {
nullptr};
315 return viewManager->actionManager();
319 QObjectList objects = mdiArea->children();
320 Q_FOREACH (QObject *
object, objects) {
321 QTabBar *bar = qobject_cast<QTabBar*>(
object);
337 widget->setEnabled(
false);
350 KAcceleratorManager::setNoAccel(
this);
353 connect(
d->workspacemodel, SIGNAL(modelReset()),
this, SLOT(
updateWindowMenu()));
354 connect(
d->workspacemodel, SIGNAL(rowsInserted(QModelIndex,
int,
int)),
this, SLOT(
updateWindowMenu()));
355 connect(
d->workspacemodel, SIGNAL(rowsRemoved(QModelIndex,
int,
int)),
this, SLOT(
updateWindowMenu()));
358 KConfigGroup group( KSharedConfig::openConfig(),
"theme");
362 d->windowStateConfig = KSharedConfig::openConfig()->group(
"MainWindow");
365 setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
366 setDockNestingEnabled(
true);
374 qApp->setStartDragDistance(25);
377 connect(
this, SIGNAL(
themeChanged()),
d->viewManager, SLOT(updateIcons()));
398 d->toolOptionsDocker = qobject_cast<KoToolDocker*>(
createDockWidget(&toolDockerFactory));
399 if (
d->toolOptionsDocker) {
400 d->toolOptionsDocker->toggleViewAction()->setEnabled(
true);
404 QMap<QString, QAction*> dockwidgetActions;
407 dockwidgetActions[toolbox->toggleViewAction()->text()] = toolbox->toggleViewAction();
413 dockwidgetActions[dw->toggleViewAction()->text()] = dw->toggleViewAction();
417 if (
d->toolOptionsDocker) {
418 dockwidgetActions[
d->toolOptionsDocker->toggleViewAction()->text()] =
d->toolOptionsDocker->toggleViewAction();
422 Q_FOREACH (QString title, dockwidgetActions.keys()) {
423 d->dockWidgetMenu->addAction(dockwidgetActions[title]);
428 d->styleActions =
new QActionGroup(
this);
431#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
437 Q_FOREACH (QString styleName, QStyleFactory::keys()) {
440 if (styleName.toLower().contains(
"android")) {
444 if (qgetenv(
"KRITA_NO_STYLE_OVERRIDE").isEmpty()) {
445 if (!allowableStyles.contains(styleName.toLower())) {
449 action =
new QAction(styleName,
d->styleActions);
450 action->setCheckable(
true);
451 d->actionMap.insert(styleName,
action);
452 d->styleMenu->addAction(
d->actionMap.value(styleName));
457 QString styleFromConfig = cfg.
widgetStyle().toLower();
458 QString styleToSelect = styleFromConfig ==
"" ? style()->objectName().toLower() : styleFromConfig;
460 Q_FOREACH (
auto key,
d->actionMap.keys()) {
461 if(key.toLower() == styleToSelect) {
462 d->actionMap.value(key)->setChecked(
true);
466 connect(
d->styleActions, SIGNAL(triggered(QAction*)),
478 if ((wdg->features() & QDockWidget::DockWidgetClosable) == 0) {
479 wdg->setVisible(
true);
486 if (mainwindowObserver) {
491 d->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
492 d->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
493 d->mdiArea->setTabPosition(QTabWidget::North);
494 d->mdiArea->setTabsClosable(
true);
495 d->mdiArea->setAcceptDrops(
true);
499 setCentralWidget(
d->widgetStack);
500 d->widgetStack->setCurrentIndex(0);
503 connect(
d->windowMapper, SIGNAL(mapped(QWidget*)),
this, SLOT(
setActiveSubWindow(QWidget*)));
504 connect(
d->documentMapper, SIGNAL(mapped(QObject*)),
this, SLOT(
newView(QObject*)));
512 d->welcomePage->setMainWindow(
this);
520 d->helpMenu =
new KisKHelpMenu(
this, KAboutData::applicationData(),
false);
535 if (helpContentsAction) {
536 actions->
addAction(helpContentsAction->objectName(), helpContentsAction);
538 if (whatsThisAction) {
539 actions->
addAction(whatsThisAction->objectName(), whatsThisAction);
541 if (reportBugAction) {
542 actions->
addAction(reportBugAction->objectName(), reportBugAction);
544 if (switchLanguageAction) {
545 actions->
addAction(switchLanguageAction->objectName(), switchLanguageAction);
547 if (aboutAppAction) {
548 actions->
addAction(aboutAppAction->objectName(), aboutAppAction);
550 if (aboutKdeAction) {
551 actions->
addAction(aboutKdeAction->objectName(), aboutKdeAction);
559 helpAction->disconnect();
560 connect(helpAction, SIGNAL(triggered()),
this, SLOT(
showManual()));
564 QSet<QKeySequence> existingShortcuts;
566 if(
action->shortcut() == QKeySequence(0)) {
570 Q_ASSERT(!existingShortcuts.contains(
action->shortcut()));
571 existingShortcuts.insert(
action->shortcut());
590 Q_FOREACH (QWidget* it,
guiFactory()->containers(
"ToolBar")) {
593 KToggleAction* act =
new KToggleAction(i18n(
"Show %1 Toolbar",
toolBar->windowTitle()),
this);
595 act->setCheckedState(KGuiItem(i18n(
"Hide %1 Toolbar",
toolBar->windowTitle())));
597 act->setChecked(!
toolBar->isHidden());
600 warnUI <<
"Toolbar list contains a " << it->metaObject()->className() <<
" which is not a toolbar!";
609 d->viewManager->updateGUI();
610 d->viewManager->updateIcons();
612 QTimer::singleShot(1000, Qt::CoarseTimer,
this, SLOT(
checkSanity()));
615 using namespace std::placeholders;
616 std::function<
void (
int)> callback(
619 d->tabSwitchCompressor.reset(
624 if (cfg.
readEntry(
"CanvasOnlyActive",
false)) {
625 QString currentWorkspace = cfg.
readEntry<QString>(
"CurrentWorkspace",
"Default");
632 menuBar()->setVisible(
true);
641 setFixedSize(KisApplication::primaryScreen()->availableGeometry().size());
643 QScreen *s = QGuiApplication::primaryScreen();
644 s->setOrientationUpdateMask(Qt::LandscapeOrientation|Qt::InvertedLandscapeOrientation|Qt::PortraitOrientation|Qt::InvertedPortraitOrientation);
650 QAndroidJniObject::callStaticMethod<void>(
"org/qtproject/qt5/android/QtNative",
"setApplicationState",
"(I)V", Qt::ApplicationActive);
653 setAcceptDrops(
true);
654 QTabBar *tabBar =
d->findTabBarHACK();
656 tabBar->setElideMode(Qt::ElideRight);
659 tabBar->setExpanding(
true);
660 tabBar->setAcceptDrops(
true);
661 tabBar->setChangeCurrentOnDrag(
true);
692 delete d->viewManager;
708 if (
d->activeView == view && !subWindow)
return;
711 d->activeView->disconnect(
this);
752 QMdiSubWindow *currentSubWin =
d->mdiArea->currentSubWindow();
753 bool shouldMaximize = currentSubWin ? currentSubWin->isMaximized() :
true;
754 subwin =
d->mdiArea->addSubWindow(imageView);
755 if (shouldMaximize) {
756 subwin->setWindowState(Qt::WindowMaximized);
759 subwin->setWidget(imageView);
762 subwin->setAttribute(Qt::WA_DeleteOnClose,
true);
766 subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.
readEntry<
int>(
"mdi_rubberband", cfg.
useOpenGL()));
767 subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.
readEntry<
int>(
"mdi_rubberband", cfg.
useOpenGL()));
768 subwin->setWindowIcon(qApp->windowIcon());
775 if (
d->mdiArea->subWindowList().size() == 1) {
776 imageView->showMaximized();
821 if (dlgPreferences->editPreferences()) {
844 d->viewManager->showHideScrollbars();
855 d->mdiArea->setPalette(qApp->palette());
856 for (
int i=0; i<
d->mdiArea->subWindowList().size(); i++) {
857 QMdiSubWindow *window =
d->mdiArea->subWindowList().at(i);
859 window->setPalette(qApp->palette());
860 KisView *view = qobject_cast<KisView*>(window->widget());
874 objects.append(aToolBar);
875 while (!objects.isEmpty()) {
876 QWidget*
widget = qobject_cast<QWidget*>(objects.takeFirst());
878 objects.append(
widget->children());
879 widget->setPalette(qApp->palette());
888 KConfigGroup group(KSharedConfig::openConfig(),
"theme");
890 if (group.readEntry(
"Theme",
"") ==
d->themeManager->currentThemeName())
return;
893 group.writeEntry(
"Theme",
d->themeManager->currentThemeName());
898 Q_FOREACH (QWidget* topLevelWidget, qApp->topLevelWidgets()) {
899 if (topLevelWidget ==
this) {
903 if (topLevelWidget->isHidden()) {
907 KisMainWindow *topLevelMainWindow = qobject_cast<KisMainWindow*>(topLevelWidget);
908 if (topLevelMainWindow) {
913 objects.append(topLevelWidget);
914 while (!objects.isEmpty()) {
915 QWidget*
widget = qobject_cast<QWidget*>(objects.takeFirst());
917 objects.append(
widget->children());
934 QString closeButtonImageUrl;
935 QString closeButtonHoverColor;
937 closeButtonImageUrl = QStringLiteral(
":/dark_close-tab.svg");
938 closeButtonHoverColor = QStringLiteral(
"lightcoral");
940 closeButtonImageUrl = QStringLiteral(
":/light_close-tab.svg");
941 closeButtonHoverColor = QStringLiteral(
"darkred");
943 QString tabStyleSheet = QStringLiteral(R
"(
944 QTabBar::close-button {
948 QTabBar::close-button:hover {
949 background-color: %2;
951 QTabBar::close-button:pressed {
952 background-color: red;
955 QHeaderView::section {
960 .arg(closeButtonImageUrl, closeButtonHoverColor);
963 QTabBar* tabBar = d->findTabBarHACK();
965 tabBar->setStyleSheet(tabStyleSheet);
972 return centralWidget() !=
d->widgetStack;
979 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"),
980 "Detach Canvas is unsupported on Android");
985 QWidget *outgoingWidget = centralWidget() ? takeCentralWidget() :
nullptr;
986 QWidget *incomingWidget =
d->canvasWindow->swapMainWidget(outgoingWidget);
988 if (incomingWidget) {
989 setCentralWidget(incomingWidget);
993 d->canvasWindow->show();
995 d->canvasWindow->hide();
997 d->toggleDetachCanvas->setChecked(detach);
1003 return d->canvasWindow;
1018 const QString fileName = QFileInfo(documentPath).fileName();
1020 if (!fileName.isEmpty()) {
1021 d->saveAction->setToolTip(i18n(
"Save as %1", fileName));
1024 d->saveAction->setToolTip(i18n(
"Save"));
1030 Q_UNUSED(readWrite);
1031 d->actionManager()->updateGUI();
1036 if (
d->activeView) {
1037 return d->activeView;
1045 QApplication::processEvents();
1047 if (!QFile(path).exists()) {
1049 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"The file %1 does not exist.", path));
1059 if (!QFile(path).exists()) {
1060 qWarning() <<
"KisMainWindow::openDocumentInternal. Could not open:" << path;
1070 d->firstTime =
true;
1072 connect(newdoc, SIGNAL(canceled(QString)),
this, SLOT(
slotLoadCanceled(QString)));
1091 ( path.startsWith(QDir::tempPath())
1092 || path.startsWith(QDir::homePath())
1094 ( QFileInfo(path).fileName().startsWith(
".krita")
1095 || QFileInfo(path).fileName().startsWith(
"krita")
1099 QString path = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
1100 if (!QFileInfo(path).exists()) {
1101 path = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
1103 newdoc->
setPath(path +
"/" + newdoc->objectName() +
".kra");
1110 Q_FOREACH(QMdiSubWindow *subwindow,
d->mdiArea->subWindowList()) {
1111 KisView *view = qobject_cast<KisView*>(subwindow->widget());
1115 if (view->
document() == document) {
1126 QMdiSubWindow *subWindow)
1146 QTimer::singleShot(0,
this, [
this] {
1148 QTimer::singleShot(0,
this, [
this] {
1161 dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
1163 dialog.setCaption(isImporting ? i18n(
"Import Images") : i18n(
"Open Images"));
1174 KisDocument *newdoc = qobject_cast<KisDocument*>(sender());
1175 if (newdoc && newdoc->
image()) {
1179 disconnect(newdoc, SIGNAL(canceled(QString)),
this, SLOT(
slotLoadCanceled(QString)));
1188 KisDocument* doc = qobject_cast<KisDocument*>(sender());
1191 disconnect(doc, SIGNAL(canceled(QString)),
this, SLOT(
slotLoadCanceled(QString)));
1196 if (!errMsg.isEmpty()) {
1198 QMessageBox::critical(
this, i18nc(
"@title:window",
"Krita"), errMsg);
1209 KisDocument* doc = qobject_cast<KisDocument*>(sender());
1212 disconnect(doc, SIGNAL(canceled(QString)),
this, SLOT(
slotSaveCanceled(QString)));
1215 if (
d->deferredClosingEvent) {
1222 std::unique_lock<QMutex> l(
d->savingEntryMutex, std::try_to_lock);
1223 return !l.owns_lock();
1228 QFileInfo from(fileName);
1231 QFile::remove(to.canonicalFilePath());
1233 return QFile::copy(fileName, to.absoluteFilePath());
1239 qreal scale = qreal(size)/qreal(qMax(geometry().width(), geometry().height()));
1240 QImage
layoutThumbnail = QImage(qRound(geometry().width()*scale), qRound(geometry().height()*scale), QImage::Format_ARGB32);
1244 Q_FOREACH(
const QObject *child, children()) {
1245 if (child->isWidgetType()) {
1246 const QWidget *w =
static_cast<const QWidget *
>(child);
1248 if (w->isVisible() && !w->property(
"_kis_excludeFromLayoutThumbnail").toBool()) {
1249 QRect wRect = QRectF(w->geometry().x()*scale
1250 , w->geometry().y()*scale
1251 , w->geometry().width()*scale
1252 , w->geometry().height()*scale
1255 wRect = wRect.intersected(
layoutThumbnail.rect().adjusted(-1, -1, -1, -1));
1257 gc.setBrush(this->
palette().window());
1258 if (w ==
d->widgetStack) {
1259 gc.setBrush(
d->mdiArea->background());
1261 gc.setPen(this->
palette().windowText().color());
1283 std::unique_lock<QMutex> l(
d->savingEntryMutex, std::try_to_lock);
1284 if (!l.owns_lock())
return false;
1294 QMessageBox::critical(qApp->activeWindow(),
1295 i18nc(
"@title:window",
"Krita"),
1296 i18n(
"You are saving a file while the image is "
1297 "still rendering. The saved file may be "
1298 "incomplete or corrupted.\n\n"
1299 "Please select a location where the original "
1300 "file will not be overridden!"));
1306 if (document->isRecovered()) {
1310 if (document->path().isEmpty()) {
1315 connect(document, SIGNAL(canceled(QString)),
this, SLOT(
slotSaveCanceled(QString)));
1317 QByteArray nativeFormat = document->nativeFormatMimeType();
1318 QByteArray oldMimeFormat = document->mimeType();
1320 QUrl suggestedURL = QUrl::fromLocalFile(document->path());
1325 if (!mimeFilter.contains(oldMimeFormat)) {
1326 dbgUI <<
"KisMainWindow::saveDocument no export filter for" << oldMimeFormat;
1332 QString suggestedFilename = QFileInfo(suggestedURL.toLocalFile()).completeBaseName();
1334 if (!suggestedFilename.isEmpty()) {
1336 suggestedURL = suggestedURL.adjusted(QUrl::RemoveFilename);
1337 suggestedURL.setPath(suggestedURL.path() + suggestedFilename);
1346 if (document->path().isEmpty() || isExporting || saveas) {
1349 bool justChangingFilterOptions =
false;
1352 dialog.setCaption(isExporting ? i18n(
"Exporting") : i18n(
"Saving As"));
1356 if (isExporting && !
d->lastExportLocation.isEmpty() && !
d->lastExportLocation.contains(QDir::tempPath())) {
1359 QString proposedPath = QFileInfo(
d->lastExportLocation).absolutePath();
1361 QString proposedFileName = suggestedURL.isEmpty() ? document->documentInfo()->aboutInfo(
"title") : QFileInfo(suggestedURL.toLocalFile()).completeBaseName();
1363 QString proposedMimeType =
d->lastExportedFormat.isEmpty() ?
"" :
d->lastExportedFormat;
1367 dialog.setDefaultDir(proposedPath +
"/" + proposedFileName +
"." + proposedExtension,
true);
1368 dialog.setMimeTypeFilters(mimeFilter, proposedMimeType);
1373 QByteArray default_mime_type = cfg.
exportMimeType(
false).toUtf8();
1374 QString proposedMimeType = QString::fromLatin1(default_mime_type);
1377 KConfigGroup group = KSharedConfig::openConfig()->group(
"File Dialogs");
1378 QString proposedPath = group.readEntry(
"SaveAs",
"");
1380 if (proposedPath.isEmpty()) {
1381 proposedPath = group.readEntry(
"OpenDocument",
"");
1384 if (proposedPath.isEmpty()) {
1385 proposedPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
1391 if(default_mime_type ==
"all/mime"){
1392 dialog.setDefaultDir(suggestedURL.isEmpty() ? proposedPath : proposedPath +
"/" + QFileInfo(suggestedURL.toLocalFile()).completeBaseName(),
true);
1395 if (default_mime_type !=
"all/mime" && !default_mime_type.isEmpty()) {
1398 dialog.setDefaultDir(suggestedURL.isEmpty() ? proposedPath : proposedPath +
"/" + QFileInfo(suggestedURL.toLocalFile()).completeBaseName() +
"." + proposedExtension,
true);
1403 dialog.setDefaultDir(suggestedURL.isEmpty() ? proposedPath : suggestedURL.toLocalFile(),
true);
1404 default_mime_type = document->mimeType().isEmpty() ? nativeFormat : document->mimeType();
1406 dialog.setMimeTypeFilters(mimeFilter, QString::fromLatin1(default_mime_type));
1409 QString newFilePath = dialog.filename();
1412 if (newFilePath.isEmpty()) {
1417 if (document->documentInfo()->aboutInfo(
"title") == i18n(
"Unnamed")) {
1418 QString fn = newFilePath;
1420 document->documentInfo()->setAboutInfo(
"title", info.completeBaseName());
1423 QByteArray outputFormat = nativeFormat;
1426 outputFormat = outputFormatString.toLatin1();
1430 justChangingFilterOptions = (newFilePath == document->path()) && (outputFormat == document->mimeType());
1433 QString path = QFileInfo(
d->lastExportLocation).absolutePath();
1434 QString filename = QFileInfo(document->path()).completeBaseName();
1435 justChangingFilterOptions = (QFileInfo(newFilePath).absolutePath() == path)
1436 && (QFileInfo(newFilePath).completeBaseName() == filename)
1437 && (outputFormat ==
d->lastExportedFormat);
1440 bool wantToSave =
true;
1443 if (!justChangingFilterOptions) {
1444 if (!document->isNativeFormat(outputFormat))
1450 ret = document->saveAs(newFilePath, outputFormat,
true);
1452 dbgUI <<
"Successful Save As!";
1455 dbgUI <<
"Failed Save As!";
1460 ret = document->exportDocument(newFilePath, outputFormat, isAdvancedExporting,
true);
1462 d->lastExportLocation = newFilePath;
1463 d->lastExportedFormat = outputFormat;
1479 if (document->isModified()) {
1480 ret = document->save(
true, 0);
1484 dbgUI <<
"Failed Save!";
1494 activeView()->document()->undoStack()->undo();
1501 activeView()->document()->undoStack()->redo();
1508 e->setAccepted(
false);
1513 QAction *
action=
d->viewManager->actionCollection()->action(
"view_show_canvas_only");
1515 action->setChecked(
false);
1522 if (!closeAllowed) {
1523 e->setAccepted(
false);
1529 d->mdiArea->closeAllSubWindows();
1533 if (childrenList.isEmpty()) {
1536 d->deferredClosingEvent = e;
1537 d->canvasWindow->close();
1539 e->setAccepted(
false);
1545 KSharedConfigPtr config = KSharedConfig::openConfig();
1547 if (
d->windowSizeDirty ) {
1548 dbgUI <<
"KisMainWindow::saveWindowSettings";
1549 KConfigGroup group =
d->windowStateConfig;
1550 KWindowConfig::saveWindowSize(windowHandle(), group);
1552 d->windowSizeDirty =
false;
1555 if (!
d->activeView ||
d->activeView->document()) {
1558 KConfigGroup group =
d->windowStateConfig;
1562 for (QMap<QString, QDockWidget*>::const_iterator i =
d->dockWidgetsMap.constBegin();
1563 i !=
d->dockWidgetsMap.constEnd(); ++i) {
1564 if (i.value()->widget()) {
1565 KConfigGroup dockGroup = group.group(QString(
"DockWidget ") + i.key());
1566 dockGroup.writeEntry(
"Locked", i.value()->property(
"Locked").toBool());
1567 dockGroup.writeEntry(
"DockArea", (
int) dockWidgetArea(i.value()));
1568 dockGroup.writeEntry(
"xPosition", (
int) i.value()->widget()->x());
1569 dockGroup.writeEntry(
"yPosition", (
int) i.value()->widget()->y());
1571 dockGroup.writeEntry(
"width", (
int) i.value()->widget()->width());
1572 dockGroup.writeEntry(
"height", (
int) i.value()->widget()->height());
1578 KSharedConfig::openConfig()->sync();
1585 d->windowSizeDirty =
true;
1586 KXmlGuiWindow::resizeEvent(e);
1604 QAction *
action=
d->viewManager->actionCollection()->action(
"view_show_canvas_only");
1612 if (!
event->spontaneous()) {
1616 Q_EMIT sigFullscreenOnShow(
true);
1618 return KXmlGuiWindow::showEvent(
event);
1624 if (widgetIndex == 0) {
1625 if (widgetIndexChanged) {
1631 if (
d->mdiArea->subWindowList().isEmpty()) {
1645 statusBar()->setVisible(
KisConfig(
true).showStatusBar());
1650 for (QAction *
action : actions) {
1652 action->setEnabled(widgetIndex);
1665 statusBar()->hide();
1668 for (QToolBar *toolbar : toolbars) {
1669 if (toolbar->objectName() !=
"mainToolBar") {
1677 d->activeView = view;
1679 if (
d->undoActionsUpdateManager) {
1680 d->undoActionsUpdateManager->setCurrentDocument(view ? view->
document() : 0);
1683 d->viewManager->setCurrentView(view);
1685 d->activeViewConnections.clear();
1686 d->activeViewConnections.addConnection(view->
document(),
1687 SIGNAL(sigPathChanged(QString)),
1690 d->activeViewConnections.addConnection(view->
document(),
1691 SIGNAL(sigReadWriteChanged(
bool)),
1702 d->activeViewConnections.clear();
1709 QTabBar *tabBar =
d->findTabBarHACK();
1711 if (!tabBar &&
d->mdiArea->viewMode() == QMdiArea::TabbedView) {
1712 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)!";
1715 if (tabBar && tabBar->isVisible()) {
1716 QPoint pos = tabBar->mapFromGlobal(mapToGlobal(
event->pos()));
1717 if (tabBar->rect().contains(pos)) {
1718 const int tabIndex = tabBar->tabAt(pos);
1720 if (tabIndex >= 0 && tabBar->currentIndex() != tabIndex) {
1721 d->tabSwitchCompressor->start(tabIndex);
1723 }
else if (
d->tabSwitchCompressor->isActive()) {
1724 d->tabSwitchCompressor->stop();
1731 if (
d->tabSwitchCompressor->isActive()) {
1732 d->tabSwitchCompressor->stop();
1739 QTabBar *tabBar =
d->findTabBarHACK();
1740 if (!tabBar)
return;
1742 tabBar->setCurrentIndex(index);
1747 const int currentIndex = show ? 0 : 1;
1748 if (
d->widgetStack->currentIndex() != currentIndex) {
1749 setUpdatesEnabled(
false);
1754 d->widgetStack->setCurrentIndex(currentIndex);
1756 d->widgetStack->setCurrentIndex(currentIndex);
1759 setUpdatesEnabled(
true);
1772 dbgUI <<
"slotImportFile()";
1784 Q_FOREACH (
const QString& url, urls) {
1786 if (!url.isEmpty()) {
1787 OpenFlags flags = isImporting ?
Import :
None;
1790 warnKrita <<
"Loading" << url <<
"failed";
1803 if (
saveDocument(
d->activeView->document(),
false,
false,
false)) {
1810 if (
saveDocument(
d->activeView->document(),
true,
false,
false)) {
1817 if (
saveDocument(
d->activeView->document(),
true,
true,
false)) {
1823 if (
saveDocument(
d->activeView->document(),
true,
true,
true)) {
1834 return d->viewManager->canvasResourceProvider()->resourceManager();
1839 return d->mdiArea->subWindowList().size();
1844 return d->windowStateConfig;
1850 if (
d->widgetStack->currentIndex() == 0) {
1855 if (restoreNormalState) {
1856 QAction *showCanvasOnly =
d->viewManager->actionCollection()->action(
"view_show_canvas_only");
1858 if (showCanvasOnly && showCanvasOnly->isChecked()) {
1859 showCanvasOnly->setChecked(
false);
1862 d->windowStateConfig.writeEntry(
"ko_geometry", saveGeometry().toBase64());
1863 d->windowStateConfig.writeEntry(
"State", saveState().toBase64());
1866 if (!
d->toggleDockers->isChecked()) {
1867 restoreState(
d->dockerStateBeforeHiding);
1870 statusBar()->setVisible(
true);
1871 menuBar()->setVisible(
true);
1883 QByteArray oldState = saveState();
1889 dock->setProperty(
"Locked",
false);
1890 dock->toggleViewAction()->setEnabled(
true);
1892 if (dock->titleBarWidget() && !dock->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
1893 dock->titleBarWidget()->setVisible(showTitlebars);
1898 bool success = KXmlGuiWindow::restoreState(state);
1901 KXmlGuiWindow::restoreState(oldState);
1903 if (dock->titleBarWidget() && !dock->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
1904 dock->titleBarWidget()->setVisible(showTitlebars || dock->isFloating());
1914 QString md5 = sender()->property(
"md5").toString();
1921 qWarning() <<
"Could not retrieve resource for" << md5;
1930 int actionsCount = 0;
1935 if (
auto collection = c->actionCollection()) {
1936 actionCollections.append(collection);
1937 actionsCount += collection->count();
1946 actionCollections.append(layerActionCollection);
1947 actionsCount += layerActionCollection->
count();
1950 d->commandBar->updateBar(actionCollections, actionsCount);
1956 d->commandBar->activateWindow();
1969 warning = i18n(
"You don't have any resource bundles enabled.");
1973 warning += i18n(
"\nThere are no brush presets available. Please enable a bundle that has presets before continuing.\n");
1974 QMessageBox::critical(
this, i18nc(
"@title:window",
"Krita"), warning);
1983 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"), warning + i18n(
"\nOnly your local resources are available."));
1996 if (dock->titleBarWidget() && !dock->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
1997 dock->titleBarWidget()->setVisible(showTitlebars || dock->isFloating());
2002 activeKisView()->resourceProvider()->notifyLoadingWorkspace(workspace);
2005 d->viewManager->notifyWorkspaceLoaded();
2012 QByteArray currentWorkspace = saveState();
2014 if (!
d->workspaceBorrowedBy.isNull()) {
2015 if (other->
id() ==
d->workspaceBorrowedBy) {
2017 d->workspaceBorrowedBy = QUuid();
2018 return currentWorkspace;
2026 d->workspaceBorrowedBy = other->
id();
2027 return originalLayout;
2032 d->workspaceBorrowedBy = other->
id();
2033 return currentWorkspace;
2039 QByteArray workspaceB = b->borrowWorkspace(a);
2042 b->restoreWorkspaceState(workspaceA);
2047 return d->viewManager;
2052 if (!
d->activeView->document())
2060 KoDocumentInfoDlg *dlg =
d->activeView->document()->createDocumentInfoDialog(
this, docInfo);
2064 d->activeView->document()->setModified(
false);
2066 d->activeView->document()->setModified(
true);
2075 Q_FOREACH (QMdiSubWindow *subwin,
d->mdiArea->subWindowList()) {
2077 if(!subwin->close())
2101 if (!document)
return;
2105 if (dlg.exec() == QDialog::Accepted) {
2107 int firstFrame = dlg.firstFrame();
2108 int step = dlg.step();
2109 bool startFrom1 = dlg.startFrom1();
2110 bool autoAddHoldframes = dlg.autoAddHoldframes();
2116 int isAscending = dlg.isAscending();
2117 KisImportExportErrorCode status = importer.import(files, firstFrame, step, autoAddHoldframes, startFrom1, isAscending);
2122 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"Could not finish import animation:\n%1", msg));
2124 activeView()->canvasBase()->refetchDataFromImage();
2133 if (dlg.exec() == QDialog::Accepted) {
2134 const QTemporaryDir outputLocation(QDir::tempPath() + QDir::separator() +
"krita" + QDir::separator() +
"import_files");
2135 RenderedFrames renderedFrames = dlg.renderFrames(QDir(outputLocation.path()));
2136 dbgFile <<
"Frames rendered to directory: " << outputLocation.path();
2137 QStringList documentInfoList = dlg.documentInfo();
2139 if (renderedFrames.
isEmpty())
return;
2141 dbgFile <<
"Animation Import options: " << documentInfoList;
2144 const int step = documentInfoList[0].toInt();
2145 const int fps = documentInfoList[1].toInt();
2147 const QString
name = QFileInfo(documentInfoList[3]).fileName();
2148 const bool useCurrentDocument = documentInfoList[4].toInt();
2149 bool useDocumentColorSpace =
false;
2151 if ( useCurrentDocument ) {
2154 dbgFile <<
"Current frames:" << document->image()->animationInterface()->totalLength() <<
"total frames:" << totalFrames;
2155 if ( document->image()->animationInterface()->totalLength() < totalFrames ) {
2156 document->image()->animationInterface()->setDocumentRangeStartFrame(0);
2157 document->image()->animationInterface()->setDocumentRangeEndFrame(totalFrames);
2160 const int width = documentInfoList[5].toInt();
2161 const int height = documentInfoList[6].toInt();
2162 const double resolution = documentInfoList[7].toDouble();
2164 const QString colorModel = documentInfoList[8];
2165 const QString colorDepth = documentInfoList[9];
2166 const QString profile = documentInfoList[10];
2167 useDocumentColorSpace = profile !=
"Default";
2170 document->setObjectName(name);
2176 QColor qc(Qt::white);
2180 if (!document->newImage(name, width, height, cs, bgColor,
KisConfig::RASTER_LAYER, 1,
"",
double(resolution / 72) )) {
2181 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"Failed to create new document. Animation import aborted."));
2185 document->image()->animationInterface()->setFramerate(fps);
2186 document->image()->animationInterface()->setDocumentRangeStartFrame(0);
2187 document->image()->animationInterface()->setDocumentRangeEndFrame(totalFrames);
2200 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"Could not finish import animation:\n%1", msg));
2203 activeView()->canvasBase()->refetchDataFromImage();
2204 document->image()->refreshGraphAsync();
2205 document->image()->waitForDone();
2222 dlgAnimationRenderer.setCaption(i18n(
"Render Animation"));
2223 if (dlgAnimationRenderer.exec() == QDialog::Accepted) {
2300 if (
d->activeView &&
d->activeView->document()) {
2304 warnUI <<
"slotToolbarToggled : Toolbar " << sender()->objectName() <<
" not found!";
2313 setWindowState(windowState() | Qt::WindowFullScreen);
2315 setWindowState(windowState() & ~Qt::WindowFullScreen);
2317 d->fullScreenMode->setChecked(isFullScreen());
2325 if (!
d->dockWidgetsMap.contains(
factory->id())) {
2347 if (
dockWidget->titleBarWidget() && !
dockWidget->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
2353 if (!showTitlebars) {
2354 if (
dockWidget->titleBarWidget() && !
dockWidget->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
2355 dockWidget->titleBarWidget()->setVisible(
false);
2357 dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
2360 dockWidget->widget()->layout()->setContentsMargins(1, 1, 1, 1);
2362 Qt::DockWidgetArea side = Qt::RightDockWidgetArea;
2363 bool visible =
true;
2365 switch (
factory->defaultDockPosition()) {
2370 side = Qt::TopDockWidgetArea;
break;
2372 side = Qt::LeftDockWidgetArea;
break;
2374 side = Qt::BottomDockWidgetArea;
break;
2376 side = Qt::RightDockWidgetArea;
break;
2379 side = Qt::RightDockWidgetArea;
2383 KConfigGroup group =
d->windowStateConfig.group(
"DockWidget " +
factory->id());
2384 side =
static_cast<Qt::DockWidgetArea
>(group.readEntry(
"DockArea",
static_cast<int>(side)));
2385 if (side == Qt::NoDockWidgetArea) side = Qt::RightDockWidgetArea;
2392 bool locked = group.readEntry(
"Locked",
false);
2393 if (titleBar && locked) {
2396 else if (
dockWidget->titleBarWidget()->inherits(
"KisUtilityTitleBar") && locked){
2408 dockWidget->setAttribute(Qt::WA_MacSmallSize,
true);
2419 Q_FOREACH (QObject *child, children()) {
2420 if (child->inherits(
"QTabBar")) {
2431 Q_FOREACH (
auto key,
d->actionMap.keys()) {
2432 if(
d->actionMap.value(key)->isChecked()) {
2435 qApp->setStyle(key);
2439#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
2440 if (qApp->style()->objectName() ==
"macintosh") {
2441 d->themeManager->setCurrentTheme(
"System");
2444 if (qApp->style()->name() ==
"macos") {
2445 d->themeManager->setCurrentTheme(
"System");
2455 return d->dockWidgetsMap.values();
2460 if (!
d->dockWidgetsMap.contains(
id))
return 0;
2461 return d->dockWidgetsMap[
id];
2473 observers << observer;
2476 warnKrita << docker <<
"is not a canvas observer";
2487 d->dockerStateBeforeHiding = saveState();
2489 Q_FOREACH (QObject*
widget, children()) {
2490 if (
widget->inherits(
"QDockWidget")) {
2491 QDockWidget* dw =
static_cast<QDockWidget*
>(
widget);
2492 if (dw->isVisible() && !(onWelcomePage && dw->property(
"ShowOnWelcomePage").toBool())) {
2499 restoreState(
d->dockerStateBeforeHiding);
2507 d->mdiCascade->setEnabled(enabled);
2508 d->mdiNextWindow->setEnabled(enabled);
2509 d->mdiPreviousWindow->setEnabled(enabled);
2510 d->mdiTile->setEnabled(enabled);
2511 d->close->setEnabled(enabled);
2512 d->closeAll->setEnabled(enabled);
2525 QMdiSubWindow *subWindow =
d->mdiArea->currentSubWindow();
2527 QMenu *menu = subWindow->systemMenu();
2528 if (menu && menu->actions().size() == 8) {
2529 Q_FOREACH (QAction *
action, menu->actions()) {
2530 action->setShortcut(QKeySequence());
2533 menu->actions().last()->deleteLater();
2537 d->actionManager()->updateGUI();
2554 if (primary.isNull())
return;
2556 if (
d->id == primary) {
2557 if (!
d->workspaceBorrowedBy.isNull()) {
2559 if (!borrower)
return;
2563 if (
d->workspaceBorrowedBy == primary)
return;
2566 if (!primaryWindow)
return;
2574 QMenu *menu =
d->windowMenu->menu();
2578 menu->addAction(
d->newWindow);
2580 menu->addAction(
d->documentMenu);
2582 QMenu *docMenu =
d->documentMenu->menu();
2585 QFontMetrics fontMetrics = docMenu->fontMetrics();
2586 QRect geom = this->geometry();
2587 QPoint
p(geom.width() / 2 + geom.left(), geom.height() / 2 + geom.top());
2588 QScreen *screen = qApp->screenAt(
p);
2589 int fileStringWidth = 300;
2591 fileStringWidth = int(screen->availableGeometry().width() * .40f);
2595 QString title = fontMetrics.elidedText(doc->path(), Qt::ElideMiddle, fileStringWidth);
2596 if (title.isEmpty() && doc->image()) {
2597 title = doc->image()->objectName();
2599 QAction *
action = docMenu->addAction(title);
2600 action->setIcon(qApp->windowIcon());
2601 connect(
action, SIGNAL(triggered()),
d->documentMapper, SLOT(map()));
2602 d->documentMapper->setMapping(
action, doc);
2606 menu->addAction(
d->workspaceMenu);
2613 while (resourceIterator.
hasNext()) {
2616 action->setProperty(
"md5", QVariant::fromValue<QString>(resource->md5sum()));
2620 connect(
workspaceMenu->addAction(i18nc(
"@action:inmenu",
"&Import Workspace...")),
2621 &QAction::triggered,
2628 dialog.setMimeTypeFilters(mimeTypes);
2629 dialog.setCaption(i18nc(
"@title:window",
"Choose File to Add"));
2630 QString filename = dialog.filename();
2635 connect(
workspaceMenu->addAction(i18nc(
"@action:inmenu",
"&New Workspace...")),
2636 &QAction::triggered,
2639 name = QInputDialog::getText(
this, i18nc(
"@title:window",
"New Workspace..."),
2640 i18nc(
"@label:textbox",
"Name:"));
2641 if (name.isEmpty()) {
2646 workspace->setDockerState(m_this->saveState());
2648 workspace->setValid(
true);
2652 d->viewManager->canvasResourceProvider()->notifySavingWorkspace(workspace);
2653 workspace->setValid(
true);
2655 workspace->setFilename(name.replace(
" ",
"_") + workspace->defaultFileExtension());
2656 workspace->setName(name);
2664 menu->addSeparator();
2665 menu->addAction(
d->close);
2666 menu->addAction(
d->closeAll);
2667 if (
d->mdiArea->viewMode() == QMdiArea::SubWindowView) {
2668 menu->addSeparator();
2669 menu->addAction(
d->mdiTile);
2670 menu->addAction(
d->mdiCascade);
2672 menu->addSeparator();
2673 menu->addAction(
d->mdiNextWindow);
2674 menu->addAction(
d->mdiPreviousWindow);
2675 menu->addSeparator();
2678 for (
int i = 0; i < windows.size(); ++i) {
2680 if (child && child->document()) {
2683 text = i18n(
"&%1 %2", i + 1, fontMetrics.elidedText(child->document()->path(), Qt::ElideMiddle, fileStringWidth));
2686 text = i18n(
"%1 %2", i + 1, fontMetrics.elidedText(child->document()->path(), Qt::ElideMiddle, fileStringWidth));
2689 QAction *
action = menu->addAction(text);
2690 action->setIcon(qApp->windowIcon());
2691 action->setCheckable(
true);
2693 connect(
action, SIGNAL(triggered()),
d->windowMapper, SLOT(map()));
2694 d->windowMapper->setMapping(
action, windows.at(i));
2698 bool showMdiArea = windows.count( ) > 0;
2704 Q_FOREACH (QObject*
widget, children()) {
2705 if (
widget->inherits(
"QDockWidget")) {
2706 QDockWidget* dw =
static_cast<QDockWidget*
>(
widget);
2708 if ( dw->objectName() ==
"ToolBox") {
2709 dw->setEnabled(showMdiArea);
2717 bool onlyOne =
false;
2718 if (
d->mdiArea->subWindowList().size() == 1 &&
d->mdiArea->viewMode() == QMdiArea::SubWindowView) {
2721 Q_FOREACH (QMdiSubWindow *subwin,
d->mdiArea->subWindowList()) {
2723 subwin->setWindowFlags(subwin->windowFlags() | Qt::FramelessWindowHint);
2724 subwin->showMaximized();
2726 subwin->setWindowFlags((subwin->windowFlags() | Qt::FramelessWindowHint) ^ Qt::FramelessWindowHint);
2737 QMdiSubWindow *subwin = qobject_cast<QMdiSubWindow *>(window);
2740 if (subwin && subwin !=
d->activeSubWindow) {
2741 KisView *view = qobject_cast<KisView *>(subwin->widget());
2746 d->activeSubWindow = subwin;
2749 d->actionManager()->updateGUI();
2755 QMdiArea::ViewMode viewMode = (QMdiArea::ViewMode)cfg.
readEntry<
int>(
"mdi_viewmode", (
int)QMdiArea::TabbedView);
2756 d->mdiArea->setViewMode(viewMode);
2757 Q_FOREACH (QMdiSubWindow *subwin,
d->mdiArea->subWindowList()) {
2758 subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.
readEntry<
int>(
"mdi_rubberband", cfg.
useOpenGL()));
2759 subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.
readEntry<
int>(
"mdi_rubberband", cfg.
useOpenGL()));
2760 if (viewMode == QMdiArea::TabbedView) {
2761 subwin->setWindowState(Qt::WindowMaximized);
2771 if (viewMode == QMdiArea::TabbedView) {
2772 Qt::WindowFlags oldFlags = subwin->windowFlags();
2773 Qt::WindowFlags flags = oldFlags;
2775 flags &= ~Qt::WindowStaysOnTopHint;
2776 flags &= ~Qt::WindowStaysOnBottomHint;
2778 if (flags != oldFlags) {
2779 subwin->setWindowFlags(flags);
2780 subwin->showMaximized();
2788 KConfigGroup group( KSharedConfig::openConfig(),
"theme");
2790 d->themeManager->setCurrentTheme(group.readEntry(
"Theme",
"Krita dark"));
2792 d->actionManager()->updateGUI();
2797 d->mdiArea->setBackground(brush);
2800 if (backgroundImage !=
"") {
2801 QImage image(backgroundImage);
2802 QBrush brush(image);
2803 d->mdiArea->setBackground(brush);
2806 d->mdiArea->update();
2810 Q_FOREACH (QObject*
widget, children()) {
2811 if (
widget->inherits(
"QDockWidget")) {
2812 QDockWidget* dw =
static_cast<QDockWidget*
>(
widget);
2820 KisDocument *doc = qobject_cast<KisDocument*>(document);
2822 d->actionManager()->updateGUI();
2832 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"),
2833 "Creating a New Main Window is unsupported on Android");
2844 if (
d->mdiArea->currentSubWindow()) {
2845 d->mdiArea->currentSubWindow()->close();
2846 d->actionManager()->updateGUI();
2855 m_errorMessage = i18n(
"The Krita LittleCMS color management plugin is not installed. Krita will quit now.");
2871 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Installation error"),
m_errorMessage);
2885 if (!
d->mdiArea)
return 0;
2895 bool isOurOwnView =
false;
2898 if (view && view->canvasController() == controller) {
2899 isOurOwnView = view->mainWindow() ==
this;
2903 if (!isOurOwnView)
return;
2905 Q_FOREACH (QWidget *w, optionWidgetList) {
2907 w->setAttribute(Qt::WA_MacSmallSize,
true);
2912 if (
d->toolOptionsDocker) {
2913 d->toolOptionsDocker->setOptionWidgets(optionWidgetList);
2916 d->viewManager->paintOpBox()->newOptionWidgets(optionWidgetList);
2947 d->undoActionsUpdateManager->setCurrentDocument(
d->activeView ?
d->activeView->document() : 0);
2950 connect(
d->importAnimation, SIGNAL(triggered()),
this, SLOT(
importAnimation()));
2957 connect(
d->renderAnimation, SIGNAL(triggered()),
this, SLOT(
renderAnimation()));
2968 connect(
d->importFile, SIGNAL(triggered(
bool)),
this, SLOT(
slotImportFile()));
2971 connect(
d->exportFile, SIGNAL(triggered(
bool)),
this, SLOT(
slotExportFile()));
2974 connect(
d->exportFileAdvance, SIGNAL(triggered(
bool)),
this, SLOT(
slotExportAdvance()));
2979 connect(
d->showDocumentInfo, SIGNAL(triggered(
bool)),
this, SLOT(
slotDocumentInfo()));
2981 d->themeManager->setThemeMenuAction(
new KActionMenu(i18nc(
"@action:inmenu",
"&Themes"),
this));
2983 connect(
d->themeManager, SIGNAL(signalThemeChanged()),
this, SLOT(
slotThemeChanged()), Qt::QueuedConnection);
2984 connect(
this, SIGNAL(
themeChanged()),
d->welcomePage, SLOT(slotUpdateThemeColors()), Qt::UniqueConnection);
2990 d->toggleDockers->setChecked(
true);
2998 d->toggleDetachCanvas->setChecked(
false);
2999 connect(
d->toggleDetachCanvas, SIGNAL(toggled(
bool)), SLOT(
setCanvasDetached(
bool)));
3013 connect(
d->mdiCascade, SIGNAL(triggered()),
d->mdiArea, SLOT(cascadeSubWindows()));
3016 connect(
d->mdiTile, SIGNAL(triggered()),
d->mdiArea, SLOT(tileSubWindows()));
3019 connect(
d->mdiNextWindow, SIGNAL(triggered()),
d->mdiArea, SLOT(activateNextSubWindow()));
3022 connect(
d->mdiPreviousWindow, SIGNAL(triggered()),
d->mdiArea, SLOT(activatePreviousSubWindow()));
3026 connect(
d->newWindow, SIGNAL(triggered(
bool)),
this, SLOT(
newWindow()));
3035 connect(
d->commandBarAction, SIGNAL(triggered(
bool)),
this, SLOT(
openCommandBar()));
3039 for (
int i = 0; i < 2; i++) {
3040 d->expandingSpacers[i] =
new KisAction(i18n(
"Expanding Spacer"));
3041 d->expandingSpacers[i]->setDefaultWidget(
new QWidget(
this));
3042 d->expandingSpacers[i]->defaultWidget()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
3057 toolBar->layout()->setSpacing(4);
3058 toolBar->setStyleSheet(
"QToolBar { border: none }");
3061 Q_FOREACH (QAction *ac,
toolBar->actions()){
3062 if (ac->icon().pixmap(QSize(1,1)).isNull() ==
false){
3063 ac->setPriority(QAction::LowPriority);
3065 ac->setIcon(QIcon());
3075 KConfigGroup cfg =
d->windowStateConfig;
3076 QByteArray geom = QByteArray::fromBase64(cfg.readEntry(
"ko_geometry", QByteArray()));
3077 if (!restoreGeometry(geom)) {
3078 QRect desk = this->screen()->availableGeometry();
3080 quint32 x = desk.x();
3081 quint32 y = desk.y();
3086 const int deskWidth = desk.width();
3087 if (deskWidth > 1024) {
3090 w = (deskWidth / 3) * 2;
3091 h = (desk.height() / 3) * 2;
3098 x += (desk.width() - w) / 2;
3099 y += (desk.height() - h) / 2;
3102 setGeometry(geometry().x(), geometry().y(), w, h);
3104 d->fullScreenMode->setChecked(isFullScreen());
3109 QDesktopServices::openUrl(QUrl(
"https://docs.krita.org"));
3115 if (dock->titleBarWidget() && !dock->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
3116 dock->titleBarWidget()->setVisible(show || dock->isFloating());
3133 QScreen *screen = QGuiApplication::primaryScreen();
3135 for (QWindow* window: QGuiApplication::topLevelWindows()) {
3137 if ((window->type() == Qt::Popup)
3138 && (window->flags() & Qt::FramelessWindowHint) == 0
3139 && (window->geometry().topLeft() != QPoint(0, 0))) {
3142 int screenHeight = screen->geometry().width();
3143 int screenWidth = screen->geometry().height();
3146 int new_x = (window->position().x() * screenWidth) / screenHeight;
3147 int new_y = (window->position().y() * screenHeight) / screenWidth;
3150 int winWidth = window->geometry().width();
3151 int winHeight = window->geometry().height();
3154 if (new_x > screenWidth - winWidth) {
3155 new_x = screenWidth - winWidth;
3159 if (new_y > screenHeight - winHeight) {
3160 new_y = screenHeight - winHeight;
3165 window->setPosition(QPoint(new_x, new_y));
3178 return (proxy.rowCount() > 0);
3196 QFile file(xmlPath);
3197 if (!file.exists()) {
3202 if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file)) {
3206 QDomNodeList overridesList = doc.elementsByTagName(QStringLiteral(
"ActionIconOverrides"));
3207 if (!overridesList.isEmpty()) {
3208 QDomElement overridesElement = overridesList.at(0).toElement();
3209 QDomNodeList actions = overridesElement.elementsByTagName(QStringLiteral(
"Action"));
3210 for (
int i = 0; i < actions.count(); ++i) {
3211 QDomElement actionElement = actions.at(i).toElement();
3212 QString name = actionElement.attribute(QStringLiteral(
"name"));
3213 QString icon = actionElement.attribute(QStringLiteral(
"icon"));
3214 if (!name.isEmpty() && !icon.isEmpty()) {
3228 QString menuLocation =
action->property(
"menulocation").toString();
3229 if (!menuLocation.isEmpty()) {
3232 Q_FOREACH(
const QString &name, menuLocation.split(
"/")) {
3233 Q_FOREACH(QAction *candidate, candidates) {
3234 if (candidate->objectName().toLower() == name.toLower()) {
3236 candidates = candidate->menu()->actions();
3240 if (candidates.isEmpty()) {
3245 if (found && found->menu()) {
3248 if (std::find_if(existingActions.begin(),
3249 existingActions.end(),
3251 == existingActions.end()) {
3253 if (std::is_sorted(existingActions.begin(),
3254 existingActions.end(),
3257 auto it = std::upper_bound(existingActions.begin(),
3258 existingActions.end(),
3261 found->menu()->insertAction(it != existingActions.end() ? *it :
nullptr,
action);
3264 found->menu()->addAction(
action);
3272#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)
void setFullscreenMode(const bool value) 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
QString exportMimeType(bool defaultValue) const
void setShowDockerTitleBars(const bool value) const
bool toolOptionsInDocker(bool defaultValue=false) const
T readEntry(const QString &name, const T &defaultValue=T())
bool showDockers(bool defaultValue=false) const
bool useOpenGL(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.
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()
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
bool framesNeedRelocation() const
QList< int > renderedFrameTargetTimes
QStringList renderedFrameFiles