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();
819 std::optional<KisDlgPreferences::PageDesc>page = std::nullopt;
822 QVariant data =
action->data();
823 if (data.userType() == QMetaType::QVariantList) {
825 action->setData(QVariant());
828 Q_ASSERT(list.length() == 2);
829 Q_ASSERT(list[0].userType() == QMetaType::Int);
830 Q_ASSERT(list[1].userType() == QMetaType::Int);
833 int t = list[1].toInt();
839 if (dlgPreferences->editPreferences(page)) {
862 d->viewManager->showHideScrollbars();
873 d->mdiArea->setPalette(qApp->palette());
874 for (
int i=0; i<
d->mdiArea->subWindowList().size(); i++) {
875 QMdiSubWindow *window =
d->mdiArea->subWindowList().at(i);
877 window->setPalette(qApp->palette());
878 KisView *view = qobject_cast<KisView*>(window->widget());
892 objects.append(aToolBar);
893 while (!objects.isEmpty()) {
894 QWidget*
widget = qobject_cast<QWidget*>(objects.takeFirst());
896 objects.append(
widget->children());
897 widget->setPalette(qApp->palette());
906 KConfigGroup group(KSharedConfig::openConfig(),
"theme");
908 if (group.readEntry(
"Theme",
"") ==
d->themeManager->currentThemeName())
return;
911 group.writeEntry(
"Theme",
d->themeManager->currentThemeName());
916 Q_FOREACH (QWidget* topLevelWidget, qApp->topLevelWidgets()) {
917 if (topLevelWidget ==
this) {
921 if (topLevelWidget->isHidden()) {
925 KisMainWindow *topLevelMainWindow = qobject_cast<KisMainWindow*>(topLevelWidget);
926 if (topLevelMainWindow) {
931 objects.append(topLevelWidget);
932 while (!objects.isEmpty()) {
933 QWidget*
widget = qobject_cast<QWidget*>(objects.takeFirst());
935 objects.append(
widget->children());
952 QString closeButtonImageUrl;
953 QString closeButtonHoverColor;
955 closeButtonImageUrl = QStringLiteral(
":/dark_close-tab.svg");
956 closeButtonHoverColor = QStringLiteral(
"lightcoral");
958 closeButtonImageUrl = QStringLiteral(
":/light_close-tab.svg");
959 closeButtonHoverColor = QStringLiteral(
"darkred");
961 QString tabStyleSheet = QStringLiteral(R
"(
962 QTabBar::close-button {
966 QTabBar::close-button:hover {
967 background-color: %2;
969 QTabBar::close-button:pressed {
970 background-color: red;
973 QHeaderView::section {
978 .arg(closeButtonImageUrl, closeButtonHoverColor);
981 QTabBar* tabBar = d->findTabBarHACK();
983 tabBar->setStyleSheet(tabStyleSheet);
990 return centralWidget() !=
d->widgetStack;
997 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"),
998 "Detach Canvas is unsupported on Android");
1003 QWidget *outgoingWidget = centralWidget() ? takeCentralWidget() :
nullptr;
1004 QWidget *incomingWidget =
d->canvasWindow->swapMainWidget(outgoingWidget);
1006 if (incomingWidget) {
1007 setCentralWidget(incomingWidget);
1011 d->canvasWindow->show();
1013 d->canvasWindow->hide();
1015 d->toggleDetachCanvas->setChecked(detach);
1021 return d->canvasWindow;
1036 const QString fileName = QFileInfo(documentPath).fileName();
1038 if (!fileName.isEmpty()) {
1039 d->saveAction->setToolTip(i18n(
"Save as %1", fileName));
1042 d->saveAction->setToolTip(i18n(
"Save"));
1048 Q_UNUSED(readWrite);
1049 d->actionManager()->updateGUI();
1054 if (
d->activeView) {
1055 return d->activeView;
1063 QApplication::processEvents();
1065 if (!QFile(path).exists()) {
1067 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"The file %1 does not exist.", path));
1077 if (!QFile(path).exists()) {
1078 qWarning() <<
"KisMainWindow::openDocumentInternal. Could not open:" << path;
1088 d->firstTime =
true;
1090 connect(newdoc, SIGNAL(canceled(QString)),
this, SLOT(
slotLoadCanceled(QString)));
1109 ( path.startsWith(QDir::tempPath())
1110 || path.startsWith(QDir::homePath())
1112 ( QFileInfo(path).fileName().startsWith(
".krita")
1113 || QFileInfo(path).fileName().startsWith(
"krita")
1117 QString path = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
1118 if (!QFileInfo(path).exists()) {
1119 path = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
1121 newdoc->
setPath(path +
"/" + newdoc->objectName() +
".kra");
1128 Q_FOREACH(QMdiSubWindow *subwindow,
d->mdiArea->subWindowList()) {
1129 KisView *view = qobject_cast<KisView*>(subwindow->widget());
1133 if (view->
document() == document) {
1144 QMdiSubWindow *subWindow)
1164 QTimer::singleShot(0,
this, [
this] {
1166 QTimer::singleShot(0,
this, [
this] {
1179 dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
1181 dialog.setCaption(isImporting ? i18n(
"Import Images") : i18n(
"Open Images"));
1192 KisDocument *newdoc = qobject_cast<KisDocument*>(sender());
1193 if (newdoc && newdoc->
image()) {
1197 disconnect(newdoc, SIGNAL(canceled(QString)),
this, SLOT(
slotLoadCanceled(QString)));
1206 KisDocument* doc = qobject_cast<KisDocument*>(sender());
1209 disconnect(doc, SIGNAL(canceled(QString)),
this, SLOT(
slotLoadCanceled(QString)));
1214 if (!errMsg.isEmpty()) {
1216 QMessageBox::critical(
this, i18nc(
"@title:window",
"Krita"), errMsg);
1227 KisDocument* doc = qobject_cast<KisDocument*>(sender());
1230 disconnect(doc, SIGNAL(canceled(QString)),
this, SLOT(
slotSaveCanceled(QString)));
1233 if (
d->deferredClosingEvent) {
1240 std::unique_lock<QMutex> l(
d->savingEntryMutex, std::try_to_lock);
1241 return !l.owns_lock();
1246 QFileInfo from(fileName);
1249 QFile::remove(to.canonicalFilePath());
1251 return QFile::copy(fileName, to.absoluteFilePath());
1257 qreal scale = qreal(size)/qreal(qMax(geometry().width(), geometry().height()));
1258 QImage
layoutThumbnail = QImage(qRound(geometry().width()*scale), qRound(geometry().height()*scale), QImage::Format_ARGB32);
1262 Q_FOREACH(
const QObject *child, children()) {
1263 if (child->isWidgetType()) {
1264 const QWidget *w =
static_cast<const QWidget *
>(child);
1266 if (w->isVisible() && !w->property(
"_kis_excludeFromLayoutThumbnail").toBool()) {
1267 QRect wRect = QRectF(w->geometry().x()*scale
1268 , w->geometry().y()*scale
1269 , w->geometry().width()*scale
1270 , w->geometry().height()*scale
1273 wRect = wRect.intersected(
layoutThumbnail.rect().adjusted(-1, -1, -1, -1));
1275 gc.setBrush(this->
palette().window());
1276 if (w ==
d->widgetStack) {
1277 gc.setBrush(
d->mdiArea->background());
1279 gc.setPen(this->
palette().windowText().color());
1301 std::unique_lock<QMutex> l(
d->savingEntryMutex, std::try_to_lock);
1302 if (!l.owns_lock())
return false;
1312 QMessageBox::critical(qApp->activeWindow(),
1313 i18nc(
"@title:window",
"Krita"),
1314 i18n(
"You are saving a file while the image is "
1315 "still rendering. The saved file may be "
1316 "incomplete or corrupted.\n\n"
1317 "Please select a location where the original "
1318 "file will not be overridden!"));
1324 if (document->isRecovered()) {
1328 if (document->path().isEmpty()) {
1332 QFile
target(document->path());
1338 connect(document, SIGNAL(canceled(QString)),
this, SLOT(
slotSaveCanceled(QString)));
1340 QByteArray nativeFormat = document->nativeFormatMimeType();
1341 QByteArray oldMimeFormat = document->mimeType();
1343 QUrl suggestedURL = QUrl::fromLocalFile(document->path());
1348 if (!mimeFilter.contains(oldMimeFormat)) {
1349 dbgUI <<
"KisMainWindow::saveDocument no export filter for" << oldMimeFormat;
1355 QString suggestedFilename = QFileInfo(suggestedURL.toLocalFile()).completeBaseName();
1357 if (!suggestedFilename.isEmpty()) {
1359 suggestedURL = suggestedURL.adjusted(QUrl::RemoveFilename);
1360 suggestedURL.setPath(suggestedURL.path() + suggestedFilename);
1369 if (document->path().isEmpty() || isExporting || saveas) {
1372 bool justChangingFilterOptions =
false;
1375 dialog.setCaption(isExporting ? i18n(
"Exporting") : i18n(
"Saving As"));
1379 if (isExporting && !
d->lastExportLocation.isEmpty() && !
d->lastExportLocation.contains(QDir::tempPath())) {
1382 QString proposedPath = QFileInfo(
d->lastExportLocation).absolutePath();
1384 QString proposedFileName = suggestedURL.isEmpty() ? document->documentInfo()->aboutInfo(
"title") : QFileInfo(suggestedURL.toLocalFile()).completeBaseName();
1386 QString proposedMimeType =
d->lastExportedFormat.isEmpty() ?
"" :
d->lastExportedFormat;
1390 dialog.setDefaultDir(proposedPath +
"/" + proposedFileName +
"." + proposedExtension,
true);
1391 dialog.setMimeTypeFilters(mimeFilter, proposedMimeType);
1396 QByteArray default_mime_type = cfg.
exportMimeType(
false).toUtf8();
1397 QString proposedMimeType = QString::fromLatin1(default_mime_type);
1400 KConfigGroup group = KSharedConfig::openConfig()->group(
"File Dialogs");
1401 QString proposedPath = group.readEntry(
"SaveAs",
"");
1403 if (proposedPath.isEmpty()) {
1404 proposedPath = group.readEntry(
"OpenDocument",
"");
1407 if (proposedPath.isEmpty()) {
1408 proposedPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
1414 if(default_mime_type ==
"all/mime"){
1415 dialog.setDefaultDir(suggestedURL.isEmpty() ? proposedPath : proposedPath +
"/" + QFileInfo(suggestedURL.toLocalFile()).completeBaseName(),
true);
1418 if (default_mime_type !=
"all/mime" && !default_mime_type.isEmpty()) {
1421 dialog.setDefaultDir(suggestedURL.isEmpty() ? proposedPath : proposedPath +
"/" + QFileInfo(suggestedURL.toLocalFile()).completeBaseName() +
"." + proposedExtension,
true);
1426 dialog.setDefaultDir(suggestedURL.isEmpty() ? proposedPath : suggestedURL.toLocalFile(),
true);
1427 default_mime_type = document->mimeType().isEmpty() ? nativeFormat : document->mimeType();
1429 dialog.setMimeTypeFilters(mimeFilter, QString::fromLatin1(default_mime_type));
1432 QString newFilePath = dialog.filename();
1435 if (newFilePath.isEmpty()) {
1440 if (document->documentInfo()->aboutInfo(
"title") == i18n(
"Unnamed")) {
1441 QString fn = newFilePath;
1443 document->documentInfo()->setAboutInfo(
"title", info.completeBaseName());
1446 QByteArray outputFormat = nativeFormat;
1449 outputFormat = outputFormatString.toLatin1();
1453 justChangingFilterOptions = (newFilePath == document->path()) && (outputFormat == document->mimeType());
1456 QString path = QFileInfo(
d->lastExportLocation).absolutePath();
1457 QString filename = QFileInfo(document->path()).completeBaseName();
1458 justChangingFilterOptions = (QFileInfo(newFilePath).absolutePath() == path)
1459 && (QFileInfo(newFilePath).completeBaseName() == filename)
1460 && (outputFormat ==
d->lastExportedFormat);
1463 bool wantToSave =
true;
1466 if (!justChangingFilterOptions) {
1467 if (!document->isNativeFormat(outputFormat))
1473 ret = document->saveAs(newFilePath, outputFormat,
true);
1475 dbgUI <<
"Successful Save As!";
1478 dbgUI <<
"Failed Save As!";
1483 ret = document->exportDocument(newFilePath, outputFormat, isAdvancedExporting,
true);
1485 d->lastExportLocation = newFilePath;
1486 d->lastExportedFormat = outputFormat;
1502 if (document->isModified()) {
1503 ret = document->save(
true, 0);
1507 dbgUI <<
"Failed Save!";
1517 activeView()->document()->undoStack()->undo();
1524 activeView()->document()->undoStack()->redo();
1531 e->setAccepted(
false);
1536 QAction *
action=
d->viewManager->actionCollection()->action(
"view_show_canvas_only");
1538 action->setChecked(
false);
1545 if (!closeAllowed) {
1546 e->setAccepted(
false);
1552 d->mdiArea->closeAllSubWindows();
1556 if (childrenList.isEmpty()) {
1559 d->deferredClosingEvent = e;
1560 d->canvasWindow->close();
1562 e->setAccepted(
false);
1568 KSharedConfigPtr config = KSharedConfig::openConfig();
1570 if (
d->windowSizeDirty ) {
1571 dbgUI <<
"KisMainWindow::saveWindowSettings";
1572 KConfigGroup group =
d->windowStateConfig;
1573 KWindowConfig::saveWindowSize(windowHandle(), group);
1575 d->windowSizeDirty =
false;
1578 if (!
d->activeView ||
d->activeView->document()) {
1581 KConfigGroup group =
d->windowStateConfig;
1585 for (QMap<QString, QDockWidget*>::const_iterator i =
d->dockWidgetsMap.constBegin();
1586 i !=
d->dockWidgetsMap.constEnd(); ++i) {
1587 if (i.value()->widget()) {
1588 KConfigGroup dockGroup = group.group(QString(
"DockWidget ") + i.key());
1589 dockGroup.writeEntry(
"Locked", i.value()->property(
"Locked").toBool());
1590 dockGroup.writeEntry(
"DockArea", (
int) dockWidgetArea(i.value()));
1591 dockGroup.writeEntry(
"xPosition", (
int) i.value()->widget()->x());
1592 dockGroup.writeEntry(
"yPosition", (
int) i.value()->widget()->y());
1594 dockGroup.writeEntry(
"width", (
int) i.value()->widget()->width());
1595 dockGroup.writeEntry(
"height", (
int) i.value()->widget()->height());
1601 KSharedConfig::openConfig()->sync();
1608 d->windowSizeDirty =
true;
1609 KXmlGuiWindow::resizeEvent(e);
1627 QAction *
action=
d->viewManager->actionCollection()->action(
"view_show_canvas_only");
1635 if (!
event->spontaneous()) {
1639 Q_EMIT sigFullscreenOnShow(
true);
1641 return KXmlGuiWindow::showEvent(
event);
1647 if (widgetIndex == 0) {
1648 if (widgetIndexChanged) {
1654 if (
d->mdiArea->subWindowList().isEmpty()) {
1668 statusBar()->setVisible(
KisConfig(
true).showStatusBar());
1673 for (QAction *
action : actions) {
1675 action->setEnabled(widgetIndex);
1688 statusBar()->hide();
1691 for (QToolBar *toolbar : toolbars) {
1692 if (toolbar->objectName() !=
"mainToolBar") {
1700 d->activeView = view;
1702 if (
d->undoActionsUpdateManager) {
1703 d->undoActionsUpdateManager->setCurrentDocument(view ? view->
document() : 0);
1706 d->viewManager->setCurrentView(view);
1708 d->activeViewConnections.clear();
1709 d->activeViewConnections.addConnection(view->
document(),
1710 SIGNAL(sigPathChanged(QString)),
1713 d->activeViewConnections.addConnection(view->
document(),
1714 SIGNAL(sigReadWriteChanged(
bool)),
1725 d->activeViewConnections.clear();
1732 QTabBar *tabBar =
d->findTabBarHACK();
1734 if (!tabBar &&
d->mdiArea->viewMode() == QMdiArea::TabbedView) {
1735 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)!";
1738 if (tabBar && tabBar->isVisible()) {
1739 QPoint pos = tabBar->mapFromGlobal(mapToGlobal(
event->pos()));
1740 if (tabBar->rect().contains(pos)) {
1741 const int tabIndex = tabBar->tabAt(pos);
1743 if (tabIndex >= 0 && tabBar->currentIndex() != tabIndex) {
1744 d->tabSwitchCompressor->start(tabIndex);
1746 }
else if (
d->tabSwitchCompressor->isActive()) {
1747 d->tabSwitchCompressor->stop();
1754 if (
d->tabSwitchCompressor->isActive()) {
1755 d->tabSwitchCompressor->stop();
1762 QTabBar *tabBar =
d->findTabBarHACK();
1763 if (!tabBar)
return;
1765 tabBar->setCurrentIndex(index);
1770 const int currentIndex = show ? 0 : 1;
1771 if (
d->widgetStack->currentIndex() != currentIndex) {
1772 setUpdatesEnabled(
false);
1777 d->widgetStack->setCurrentIndex(currentIndex);
1779 d->widgetStack->setCurrentIndex(currentIndex);
1782 setUpdatesEnabled(
true);
1795 dbgUI <<
"slotImportFile()";
1807 Q_FOREACH (
const QString& url, urls) {
1809 if (!url.isEmpty()) {
1810 OpenFlags flags = isImporting ?
Import :
None;
1813 warnKrita <<
"Loading" << url <<
"failed";
1826 if (
saveDocument(
d->activeView->document(),
false,
false,
false)) {
1833 if (
saveDocument(
d->activeView->document(),
true,
false,
false)) {
1840 if (
saveDocument(
d->activeView->document(),
true,
true,
false)) {
1846 if (
saveDocument(
d->activeView->document(),
true,
true,
true)) {
1857 return d->viewManager->canvasResourceProvider()->resourceManager();
1862 return d->mdiArea->subWindowList().size();
1867 return d->windowStateConfig;
1873 if (
d->widgetStack->currentIndex() == 0) {
1878 if (restoreNormalState) {
1879 QAction *showCanvasOnly =
d->viewManager->actionCollection()->action(
"view_show_canvas_only");
1881 if (showCanvasOnly && showCanvasOnly->isChecked()) {
1882 showCanvasOnly->setChecked(
false);
1885 d->windowStateConfig.writeEntry(
"ko_geometry", saveGeometry().toBase64());
1886 d->windowStateConfig.writeEntry(
"State", saveState().toBase64());
1889 if (!
d->toggleDockers->isChecked()) {
1890 restoreState(
d->dockerStateBeforeHiding);
1893 statusBar()->setVisible(
true);
1894 menuBar()->setVisible(
true);
1906 QByteArray oldState = saveState();
1912 dock->setProperty(
"Locked",
false);
1913 dock->toggleViewAction()->setEnabled(
true);
1915 if (dock->titleBarWidget() && !dock->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
1916 dock->titleBarWidget()->setVisible(showTitlebars);
1921 bool success = KXmlGuiWindow::restoreState(state);
1924 KXmlGuiWindow::restoreState(oldState);
1926 if (dock->titleBarWidget() && !dock->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
1927 dock->titleBarWidget()->setVisible(showTitlebars || dock->isFloating());
1937 QString md5 = sender()->property(
"md5").toString();
1944 qWarning() <<
"Could not retrieve resource for" << md5;
1953 int actionsCount = 0;
1958 if (
auto collection = c->actionCollection()) {
1959 actionCollections.append(collection);
1960 actionsCount += collection->count();
1969 actionCollections.append(layerActionCollection);
1970 actionsCount += layerActionCollection->
count();
1973 d->commandBar->updateBar(actionCollections, actionsCount);
1979 d->commandBar->activateWindow();
1992 warning = i18n(
"You don't have any resource bundles enabled.");
1996 warning += i18n(
"\nThere are no brush presets available. Please enable a bundle that has presets before continuing.\n");
1997 QMessageBox::critical(
this, i18nc(
"@title:window",
"Krita"), warning);
2006 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"), warning + i18n(
"\nOnly your local resources are available."));
2019 if (dock->titleBarWidget() && !dock->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
2020 dock->titleBarWidget()->setVisible(showTitlebars || dock->isFloating());
2025 activeKisView()->resourceProvider()->notifyLoadingWorkspace(workspace);
2028 d->viewManager->notifyWorkspaceLoaded();
2035 QByteArray currentWorkspace = saveState();
2037 if (!
d->workspaceBorrowedBy.isNull()) {
2038 if (other->
id() ==
d->workspaceBorrowedBy) {
2040 d->workspaceBorrowedBy = QUuid();
2041 return currentWorkspace;
2049 d->workspaceBorrowedBy = other->
id();
2050 return originalLayout;
2055 d->workspaceBorrowedBy = other->
id();
2056 return currentWorkspace;
2062 QByteArray workspaceB = b->borrowWorkspace(a);
2065 b->restoreWorkspaceState(workspaceA);
2070 return d->viewManager;
2075 if (!
d->activeView->document())
2083 KoDocumentInfoDlg *dlg =
d->activeView->document()->createDocumentInfoDialog(
this, docInfo);
2087 d->activeView->document()->setModified(
false);
2089 d->activeView->document()->setModified(
true);
2098 Q_FOREACH (QMdiSubWindow *subwin,
d->mdiArea->subWindowList()) {
2100 if(!subwin->close())
2124 if (!document)
return;
2128 if (dlg.exec() == QDialog::Accepted) {
2130 int firstFrame = dlg.firstFrame();
2131 int step = dlg.step();
2132 bool startFrom1 = dlg.startFrom1();
2133 bool autoAddHoldframes = dlg.autoAddHoldframes();
2139 int isAscending = dlg.isAscending();
2140 KisImportExportErrorCode status = importer.import(files, firstFrame, step, autoAddHoldframes, startFrom1, isAscending);
2145 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"Could not finish import animation:\n%1", msg));
2147 activeView()->canvasBase()->refetchDataFromImage();
2156 if (dlg.exec() == QDialog::Accepted) {
2157 const QTemporaryDir outputLocation(QDir::tempPath() + QDir::separator() +
"krita" + QDir::separator() +
"import_files");
2158 RenderedFrames renderedFrames = dlg.renderFrames(QDir(outputLocation.path()));
2159 dbgFile <<
"Frames rendered to directory: " << outputLocation.path();
2160 QStringList documentInfoList = dlg.documentInfo();
2162 if (renderedFrames.
isEmpty())
return;
2164 dbgFile <<
"Animation Import options: " << documentInfoList;
2167 const int step = documentInfoList[0].toInt();
2168 const int fps = documentInfoList[1].toInt();
2170 const QString
name = QFileInfo(documentInfoList[3]).fileName();
2171 const bool useCurrentDocument = documentInfoList[4].toInt();
2172 bool useDocumentColorSpace =
false;
2174 if ( useCurrentDocument ) {
2177 dbgFile <<
"Current frames:" << document->image()->animationInterface()->totalLength() <<
"total frames:" << totalFrames;
2178 if ( document->image()->animationInterface()->totalLength() < totalFrames ) {
2179 document->image()->animationInterface()->setDocumentRangeStartFrame(0);
2180 document->image()->animationInterface()->setDocumentRangeEndFrame(totalFrames);
2183 const int width = documentInfoList[5].toInt();
2184 const int height = documentInfoList[6].toInt();
2185 const double resolution = documentInfoList[7].toDouble();
2187 const QString colorModel = documentInfoList[8];
2188 const QString colorDepth = documentInfoList[9];
2189 const QString profile = documentInfoList[10];
2190 useDocumentColorSpace = profile !=
"Default";
2193 document->setObjectName(name);
2199 QColor qc(Qt::white);
2203 if (!document->newImage(name, width, height, cs, bgColor,
KisConfig::RASTER_LAYER, 1,
"",
double(resolution / 72) )) {
2204 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"Failed to create new document. Animation import aborted."));
2208 document->image()->animationInterface()->setFramerate(fps);
2209 document->image()->animationInterface()->setDocumentRangeStartFrame(0);
2210 document->image()->animationInterface()->setDocumentRangeEndFrame(totalFrames);
2223 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"Could not finish import animation:\n%1", msg));
2226 activeView()->canvasBase()->refetchDataFromImage();
2227 document->image()->refreshGraphAsync();
2228 document->image()->waitForDone();
2245 dlgAnimationRenderer.setCaption(i18n(
"Render Animation"));
2246 if (dlgAnimationRenderer.exec() == QDialog::Accepted) {
2323 if (
d->activeView &&
d->activeView->document()) {
2327 warnUI <<
"slotToolbarToggled : Toolbar " << sender()->objectName() <<
" not found!";
2336 setWindowState(windowState() | Qt::WindowFullScreen);
2338 setWindowState(windowState() & ~Qt::WindowFullScreen);
2340 d->fullScreenMode->setChecked(isFullScreen());
2348 if (!
d->dockWidgetsMap.contains(
factory->id())) {
2370 if (
dockWidget->titleBarWidget() && !
dockWidget->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
2376 if (!showTitlebars) {
2377 if (
dockWidget->titleBarWidget() && !
dockWidget->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
2378 dockWidget->titleBarWidget()->setVisible(
false);
2380 dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
2383 dockWidget->widget()->layout()->setContentsMargins(1, 1, 1, 1);
2385 Qt::DockWidgetArea side = Qt::RightDockWidgetArea;
2386 bool visible =
true;
2388 switch (
factory->defaultDockPosition()) {
2393 side = Qt::TopDockWidgetArea;
break;
2395 side = Qt::LeftDockWidgetArea;
break;
2397 side = Qt::BottomDockWidgetArea;
break;
2399 side = Qt::RightDockWidgetArea;
break;
2402 side = Qt::RightDockWidgetArea;
2406 KConfigGroup group =
d->windowStateConfig.group(
"DockWidget " +
factory->id());
2407 side =
static_cast<Qt::DockWidgetArea
>(group.readEntry(
"DockArea",
static_cast<int>(side)));
2408 if (side == Qt::NoDockWidgetArea) side = Qt::RightDockWidgetArea;
2415 bool locked = group.readEntry(
"Locked",
false);
2416 if (titleBar && locked) {
2419 else if (
dockWidget->titleBarWidget()->inherits(
"KisUtilityTitleBar") && locked){
2431 dockWidget->setAttribute(Qt::WA_MacSmallSize,
true);
2442 Q_FOREACH (QObject *child, children()) {
2443 if (child->inherits(
"QTabBar")) {
2454 Q_FOREACH (
auto key,
d->actionMap.keys()) {
2455 if(
d->actionMap.value(key)->isChecked()) {
2458 qApp->setStyle(key);
2462#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
2463 if (qApp->style()->objectName() ==
"macintosh") {
2464 d->themeManager->setCurrentTheme(
"System");
2467 if (qApp->style()->name() ==
"macos") {
2468 d->themeManager->setCurrentTheme(
"System");
2478 return d->dockWidgetsMap.values();
2483 if (!
d->dockWidgetsMap.contains(
id))
return 0;
2484 return d->dockWidgetsMap[
id];
2496 observers << observer;
2499 warnKrita << docker <<
"is not a canvas observer";
2510 d->dockerStateBeforeHiding = saveState();
2512 Q_FOREACH (QObject*
widget, children()) {
2513 if (
widget->inherits(
"QDockWidget")) {
2514 QDockWidget* dw =
static_cast<QDockWidget*
>(
widget);
2515 if (dw->isVisible() && !(onWelcomePage && dw->property(
"ShowOnWelcomePage").toBool())) {
2522 restoreState(
d->dockerStateBeforeHiding);
2530 d->mdiCascade->setEnabled(enabled);
2531 d->mdiNextWindow->setEnabled(enabled);
2532 d->mdiPreviousWindow->setEnabled(enabled);
2533 d->mdiTile->setEnabled(enabled);
2534 d->close->setEnabled(enabled);
2535 d->closeAll->setEnabled(enabled);
2548 QMdiSubWindow *subWindow =
d->mdiArea->currentSubWindow();
2550 QMenu *menu = subWindow->systemMenu();
2551 if (menu && menu->actions().size() == 8) {
2552 Q_FOREACH (QAction *
action, menu->actions()) {
2553 action->setShortcut(QKeySequence());
2556 menu->actions().last()->deleteLater();
2560 d->actionManager()->updateGUI();
2577 if (primary.isNull())
return;
2579 if (
d->id == primary) {
2580 if (!
d->workspaceBorrowedBy.isNull()) {
2582 if (!borrower)
return;
2586 if (
d->workspaceBorrowedBy == primary)
return;
2589 if (!primaryWindow)
return;
2597 QMenu *menu =
d->windowMenu->menu();
2601 menu->addAction(
d->newWindow);
2603 menu->addAction(
d->documentMenu);
2605 QMenu *docMenu =
d->documentMenu->menu();
2608 QFontMetrics fontMetrics = docMenu->fontMetrics();
2609 QRect geom = this->geometry();
2610 QPoint
p(geom.width() / 2 + geom.left(), geom.height() / 2 + geom.top());
2611 QScreen *screen = qApp->screenAt(
p);
2612 int fileStringWidth = 300;
2614 fileStringWidth = int(screen->availableGeometry().width() * .40f);
2618 QString title = fontMetrics.elidedText(doc->path(), Qt::ElideMiddle, fileStringWidth);
2619 if (title.isEmpty() && doc->image()) {
2620 title = doc->image()->objectName();
2622 QAction *
action = docMenu->addAction(title);
2623 action->setIcon(qApp->windowIcon());
2624 connect(
action, SIGNAL(triggered()),
d->documentMapper, SLOT(map()));
2625 d->documentMapper->setMapping(
action, doc);
2629 menu->addAction(
d->workspaceMenu);
2636 while (resourceIterator.
hasNext()) {
2639 action->setProperty(
"md5", QVariant::fromValue<QString>(resource->md5sum()));
2643 connect(
workspaceMenu->addAction(i18nc(
"@action:inmenu",
"&Import Workspace...")),
2644 &QAction::triggered,
2651 dialog.setMimeTypeFilters(mimeTypes);
2652 dialog.setCaption(i18nc(
"@title:window",
"Choose File to Add"));
2653 QString filename = dialog.filename();
2658 connect(
workspaceMenu->addAction(i18nc(
"@action:inmenu",
"&New Workspace...")),
2659 &QAction::triggered,
2662 name = QInputDialog::getText(
this, i18nc(
"@title:window",
"New Workspace..."),
2663 i18nc(
"@label:textbox",
"Name:"));
2664 if (name.isEmpty()) {
2669 workspace->setDockerState(m_this->saveState());
2671 workspace->setValid(
true);
2675 d->viewManager->canvasResourceProvider()->notifySavingWorkspace(workspace);
2676 workspace->setValid(
true);
2678 workspace->setFilename(name.replace(
" ",
"_") + workspace->defaultFileExtension());
2679 workspace->setName(name);
2687 menu->addSeparator();
2688 menu->addAction(
d->close);
2689 menu->addAction(
d->closeAll);
2690 if (
d->mdiArea->viewMode() == QMdiArea::SubWindowView) {
2691 menu->addSeparator();
2692 menu->addAction(
d->mdiTile);
2693 menu->addAction(
d->mdiCascade);
2695 menu->addSeparator();
2696 menu->addAction(
d->mdiNextWindow);
2697 menu->addAction(
d->mdiPreviousWindow);
2698 menu->addSeparator();
2701 for (
int i = 0; i < windows.size(); ++i) {
2703 if (child && child->document()) {
2706 text = i18n(
"&%1 %2", i + 1, fontMetrics.elidedText(child->document()->path(), Qt::ElideMiddle, fileStringWidth));
2709 text = i18n(
"%1 %2", i + 1, fontMetrics.elidedText(child->document()->path(), Qt::ElideMiddle, fileStringWidth));
2712 QAction *
action = menu->addAction(text);
2713 action->setIcon(qApp->windowIcon());
2714 action->setCheckable(
true);
2716 connect(
action, SIGNAL(triggered()),
d->windowMapper, SLOT(map()));
2717 d->windowMapper->setMapping(
action, windows.at(i));
2721 bool showMdiArea = windows.count( ) > 0;
2727 Q_FOREACH (QObject*
widget, children()) {
2728 if (
widget->inherits(
"QDockWidget")) {
2729 QDockWidget* dw =
static_cast<QDockWidget*
>(
widget);
2731 if ( dw->objectName() ==
"ToolBox") {
2732 dw->setEnabled(showMdiArea);
2740 bool onlyOne =
false;
2741 if (
d->mdiArea->subWindowList().size() == 1 &&
d->mdiArea->viewMode() == QMdiArea::SubWindowView) {
2744 Q_FOREACH (QMdiSubWindow *subwin,
d->mdiArea->subWindowList()) {
2746 subwin->setWindowFlags(subwin->windowFlags() | Qt::FramelessWindowHint);
2747 subwin->showMaximized();
2749 subwin->setWindowFlags((subwin->windowFlags() | Qt::FramelessWindowHint) ^ Qt::FramelessWindowHint);
2760 QMdiSubWindow *subwin = qobject_cast<QMdiSubWindow *>(window);
2763 if (subwin && subwin !=
d->activeSubWindow) {
2764 KisView *view = qobject_cast<KisView *>(subwin->widget());
2769 d->activeSubWindow = subwin;
2772 d->actionManager()->updateGUI();
2778 QMdiArea::ViewMode viewMode = (QMdiArea::ViewMode)cfg.
readEntry<
int>(
"mdi_viewmode", (
int)QMdiArea::TabbedView);
2779 d->mdiArea->setViewMode(viewMode);
2780 Q_FOREACH (QMdiSubWindow *subwin,
d->mdiArea->subWindowList()) {
2781 subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.
readEntry<
int>(
"mdi_rubberband", cfg.
useOpenGL()));
2782 subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.
readEntry<
int>(
"mdi_rubberband", cfg.
useOpenGL()));
2783 if (viewMode == QMdiArea::TabbedView) {
2784 subwin->setWindowState(Qt::WindowMaximized);
2794 if (viewMode == QMdiArea::TabbedView) {
2795 Qt::WindowFlags oldFlags = subwin->windowFlags();
2796 Qt::WindowFlags flags = oldFlags;
2798 flags &= ~Qt::WindowStaysOnTopHint;
2799 flags &= ~Qt::WindowStaysOnBottomHint;
2801 if (flags != oldFlags) {
2802 subwin->setWindowFlags(flags);
2803 subwin->showMaximized();
2811 KConfigGroup group( KSharedConfig::openConfig(),
"theme");
2813 d->themeManager->setCurrentTheme(group.readEntry(
"Theme",
"Krita dark"));
2815 d->actionManager()->updateGUI();
2820 d->mdiArea->setBackground(brush);
2823 if (backgroundImage !=
"") {
2824 QImage image(backgroundImage);
2825 QBrush brush(image);
2826 d->mdiArea->setBackground(brush);
2829 d->mdiArea->update();
2833 Q_FOREACH (QObject*
widget, children()) {
2834 if (
widget->inherits(
"QDockWidget")) {
2835 QDockWidget* dw =
static_cast<QDockWidget*
>(
widget);
2843 KisDocument *doc = qobject_cast<KisDocument*>(document);
2845 d->actionManager()->updateGUI();
2855 QMessageBox::warning(
this, i18nc(
"@title:window",
"Krita"),
2856 "Creating a New Main Window is unsupported on Android");
2867 if (
d->mdiArea->currentSubWindow()) {
2868 d->mdiArea->currentSubWindow()->close();
2869 d->actionManager()->updateGUI();
2878 m_errorMessage = i18n(
"The Krita LittleCMS color management plugin is not installed. Krita will quit now.");
2894 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Installation error"),
m_errorMessage);
2908 if (!
d->mdiArea)
return 0;
2918 bool isOurOwnView =
false;
2921 if (view && view->canvasController() == controller) {
2922 isOurOwnView = view->mainWindow() ==
this;
2926 if (!isOurOwnView)
return;
2928 Q_FOREACH (QWidget *w, optionWidgetList) {
2930 w->setAttribute(Qt::WA_MacSmallSize,
true);
2935 if (
d->toolOptionsDocker) {
2936 d->toolOptionsDocker->setOptionWidgets(optionWidgetList);
2939 d->viewManager->paintOpBox()->newOptionWidgets(optionWidgetList);
2970 d->undoActionsUpdateManager->setCurrentDocument(
d->activeView ?
d->activeView->document() : 0);
2973 connect(
d->importAnimation, SIGNAL(triggered()),
this, SLOT(
importAnimation()));
2980 connect(
d->renderAnimation, SIGNAL(triggered()),
this, SLOT(
renderAnimation()));
2991 connect(
d->importFile, SIGNAL(triggered(
bool)),
this, SLOT(
slotImportFile()));
2994 connect(
d->exportFile, SIGNAL(triggered(
bool)),
this, SLOT(
slotExportFile()));
2997 connect(
d->exportFileAdvance, SIGNAL(triggered(
bool)),
this, SLOT(
slotExportAdvance()));
3002 connect(
d->showDocumentInfo, SIGNAL(triggered(
bool)),
this, SLOT(
slotDocumentInfo()));
3004 d->themeManager->setThemeMenuAction(
new KActionMenu(i18nc(
"@action:inmenu",
"&Themes"),
this));
3006 connect(
d->themeManager, SIGNAL(signalThemeChanged()),
this, SLOT(
slotThemeChanged()), Qt::QueuedConnection);
3007 connect(
this, SIGNAL(
themeChanged()),
d->welcomePage, SLOT(slotUpdateThemeColors()), Qt::UniqueConnection);
3013 d->toggleDockers->setChecked(
true);
3021 d->toggleDetachCanvas->setChecked(
false);
3022 connect(
d->toggleDetachCanvas, SIGNAL(toggled(
bool)), SLOT(
setCanvasDetached(
bool)));
3036 connect(
d->mdiCascade, SIGNAL(triggered()),
d->mdiArea, SLOT(cascadeSubWindows()));
3039 connect(
d->mdiTile, SIGNAL(triggered()),
d->mdiArea, SLOT(tileSubWindows()));
3042 connect(
d->mdiNextWindow, SIGNAL(triggered()),
d->mdiArea, SLOT(activateNextSubWindow()));
3045 connect(
d->mdiPreviousWindow, SIGNAL(triggered()),
d->mdiArea, SLOT(activatePreviousSubWindow()));
3049 connect(
d->newWindow, SIGNAL(triggered(
bool)),
this, SLOT(
newWindow()));
3058 connect(
d->commandBarAction, SIGNAL(triggered(
bool)),
this, SLOT(
openCommandBar()));
3062 for (
int i = 0; i < 2; i++) {
3063 d->expandingSpacers[i] =
new KisAction(i18n(
"Expanding Spacer"));
3064 d->expandingSpacers[i]->setDefaultWidget(
new QWidget(
this));
3065 d->expandingSpacers[i]->defaultWidget()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
3080 toolBar->layout()->setSpacing(4);
3081 toolBar->setStyleSheet(
"QToolBar { border: none }");
3084 Q_FOREACH (QAction *ac,
toolBar->actions()){
3085 if (ac->icon().pixmap(QSize(1,1)).isNull() ==
false){
3086 ac->setPriority(QAction::LowPriority);
3088 ac->setIcon(QIcon());
3098 KConfigGroup cfg =
d->windowStateConfig;
3099 QByteArray geom = QByteArray::fromBase64(cfg.readEntry(
"ko_geometry", QByteArray()));
3100 if (!restoreGeometry(geom)) {
3101 QRect desk = this->screen()->availableGeometry();
3103 quint32 x = desk.x();
3104 quint32 y = desk.y();
3109 const int deskWidth = desk.width();
3110 if (deskWidth > 1024) {
3113 w = (deskWidth / 3) * 2;
3114 h = (desk.height() / 3) * 2;
3121 x += (desk.width() - w) / 2;
3122 y += (desk.height() - h) / 2;
3125 setGeometry(geometry().x(), geometry().y(), w, h);
3127 d->fullScreenMode->setChecked(isFullScreen());
3132 QDesktopServices::openUrl(QUrl(
"https://docs.krita.org"));
3138 if (dock->titleBarWidget() && !dock->titleBarWidget()->inherits(
"KisUtilityTitleBar")) {
3139 dock->titleBarWidget()->setVisible(show || dock->isFloating());
3156 QScreen *screen = QGuiApplication::primaryScreen();
3158 for (QWindow* window: QGuiApplication::topLevelWindows()) {
3160 if ((window->type() == Qt::Popup)
3161 && (window->flags() & Qt::FramelessWindowHint) == 0
3162 && (window->geometry().topLeft() != QPoint(0, 0))) {
3165 int screenHeight = screen->geometry().width();
3166 int screenWidth = screen->geometry().height();
3169 int new_x = (window->position().x() * screenWidth) / screenHeight;
3170 int new_y = (window->position().y() * screenHeight) / screenWidth;
3173 int winWidth = window->geometry().width();
3174 int winHeight = window->geometry().height();
3177 if (new_x > screenWidth - winWidth) {
3178 new_x = screenWidth - winWidth;
3182 if (new_y > screenHeight - winHeight) {
3183 new_y = screenHeight - winHeight;
3188 window->setPosition(QPoint(new_x, new_y));
3201 return (proxy.rowCount() > 0);
3219 QFile file(xmlPath);
3220 if (!file.exists()) {
3225 if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file)) {
3229 QDomNodeList overridesList = doc.elementsByTagName(QStringLiteral(
"ActionIconOverrides"));
3230 if (!overridesList.isEmpty()) {
3231 QDomElement overridesElement = overridesList.at(0).toElement();
3232 QDomNodeList actions = overridesElement.elementsByTagName(QStringLiteral(
"Action"));
3233 for (
int i = 0; i < actions.count(); ++i) {
3234 QDomElement actionElement = actions.at(i).toElement();
3235 QString name = actionElement.attribute(QStringLiteral(
"name"));
3236 QString icon = actionElement.attribute(QStringLiteral(
"icon"));
3237 if (!name.isEmpty() && !icon.isEmpty()) {
3251 QString menuLocation =
action->property(
"menulocation").toString();
3252 if (!menuLocation.isEmpty()) {
3255 Q_FOREACH(
const QString &name, menuLocation.split(
"/")) {
3256 Q_FOREACH(QAction *candidate, candidates) {
3257 if (candidate->objectName().toLower() == name.toLower()) {
3259 candidates = candidate->menu()->actions();
3263 if (candidates.isEmpty()) {
3268 if (found && found->menu()) {
3271 if (std::find_if(existingActions.begin(),
3272 existingActions.end(),
3274 == existingActions.end()) {
3276 if (std::is_sorted(existingActions.begin(),
3277 existingActions.end(),
3280 auto it = std::upper_bound(existingActions.begin(),
3281 existingActions.end(),
3284 found->menu()->insertAction(it != existingActions.end() ? *it :
nullptr,
action);
3287 found->menu()->addAction(
action);
3295#include <moc_KisMainWindow.cpp>
KisMagneticGraph::vertex_descriptor target(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
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