diff --git a/krita/kritamenu.action b/krita/kritamenu.action
index efc698bd37..9a2ccf7ebe 100644
--- a/krita/kritamenu.action
+++ b/krita/kritamenu.action
@@ -1,1830 +1,1830 @@
File
document-new
&New
Create new document
New
0
0
Ctrl+N
false
document-open
&Open...
Open an existing document
Open
0
0
Ctrl+O
false
document-open-recent
Open &Recent
Open a document which was recently opened
Open Recent
1
0
false
document-save
&Save
Save
Save
1
0
Ctrl+S
false
document-save-as
Save &As...
Save document under a new name
Save As
1
0
Ctrl+Shift+S
false
Sessions...
Open session manager
Sessions
0
0
false
document-import
Open ex&isting Document as Untitled Document...
Open existing Document as Untitled Document
Open existing Document as Untitled Document
0
0
false
document-export
E&xport...
Export
Export
1
0
false
application-pdf
&Export as PDF...
Export as PDF
Export as PDF
1
0
false
Import animation frames...
Import animation frames
Import animation frames
1
0
false
&Render Animation...
Render Animation to GIF, Image Sequence or Video
Render Animation
1000
0
false
&Render Image Sequence Again
Render Animation to Image Sequence Again
Render Animation
1000
0
false
Save Incremental &Version
Save Incremental Version
Save Incremental Version
1
0
Ctrl+Alt+S
false
Save Incremental &Backup
Save Incremental Backup
Save Incremental Backup
1
0
F4
false
&Create Template From Image...
Create Template From Image
Create Template From Image
1
0
false
Create Copy &From Current Image
Create Copy From Current Image
Create Copy From Current Image
1
0
false
document-print
&Print...
Print document
Print
1
0
Ctrl+P
false
document-print-preview
Print Previe&w
Show a print preview of document
Print Preview
1
0
false
configure
&Document Information
Document Information
Document Information
1
0
false
&Close All
Close All
Close All
1
0
Ctrl+Shift+W
false
C&lose
Close
Close
1
0
false
&Quit
Quit application
Quit
0
0
Ctrl+Q
false
Edit
edit-undo
Undo
Undo last action
Undo
1
0
Ctrl+Z
false
edit-redo
Redo
Redo last undone action
Redo
1
0
Ctrl+Shift+Z
false
edit-cut
Cu&t
Cut selection to clipboard
Cut
0
0
Ctrl+X
false
edit-copy
&Copy
Copy selection to clipboard
Copy
0
0
Ctrl+C
false
C&opy (sharp)
Copy (sharp)
Copy (sharp)
100000000
0
false
Cut (&sharp)
Cut (sharp)
Cut (sharp)
100000000
0
false
Copy &merged
Copy merged
Copy merged
100000000
0
Ctrl+Shift+C
false
edit-paste
&Paste
Paste clipboard content
Paste
0
0
Ctrl+V
false
Paste at Cursor
Paste at cursor
Paste at cursor
0
0
Ctrl+Alt+V
false
Paste into &New Image
Paste into New Image
Paste into New Image
0
0
Ctrl+Shift+N
false
edit-clear
C&lear
Clear
Clear
1
0
Del
false
&Fill with Foreground Color
Fill with Foreground Color
Fill with Foreground Color
10000
1
Shift+Backspace
false
Fill &with Background Color
Fill with Background Color
Fill with Background Color
10000
1
Backspace
false
F&ill with Pattern
Fill with Pattern
Fill with Pattern
10000
1
false
Fill Special
Fill with Foreground Color (Opacity)
Fill with Foreground Color (Opacity)
Fill with Foreground Color (Opacity)
10000
1
Ctrl+Shift+Backspace
false
Fill with Background Color (Opacity)
Fill with Background Color (Opacity)
Fill with Background Color (Opacity)
10000
1
Ctrl+Backspace
false
Fill with Pattern (Opacity)
Fill with Pattern (Opacity)
Fill with Pattern (Opacity)
10000
1
false
Stro&ke selected shapes
Stroke selected shapes
Stroke selected shapes
1000000000
0
false
Stroke Selec&tion...
Stroke selection
Stroke selection
10000000000
0
false
Delete keyframe
Delete keyframe
Delete keyframe
100000
0
false
Window
window-new
&New Window
New Window
New Window
0
0
false
N&ext
Next
Next
10
0
false
Previous
Previous
Previous
false
View
&Show Canvas Only
Show just the canvas or the whole window
Show Canvas Only
0
0
Tab
true
view-fullscreen
F&ull Screen Mode
Display the window in full screen
Full Screen Mode
0
0
Ctrl+Shift+F
true
&Wrap Around Mode
Wrap Around Mode
Wrap Around Mode
1
0
W
true
&Instant Preview Mode
Instant Preview Mode
Instant Preview Mode
1
0
Shift+L
true
Soft Proofing
Turns on Soft Proofing
Turns on Soft Proofing
Ctrl+Y
true
Out of Gamut Warnings
Turns on warnings for colors out of proofed gamut, needs soft proofing to be turned on.
Turns on warnings for colors out of proofed gamut, needs soft proofing to be turned on.
Ctrl+Shift+Y
true
mirror-view
Mirror View
Mirror View
Mirror View
M
false
zoom-original
&Reset zoom
Reset zoom
Reset zoom
1
0
Ctrl+0
false
zoom-in
Zoom &In
Zoom In
0
0
Ctrl++
false
zoom-out
Zoom &Out
Zoom Out
0
0
Ctrl+-
false
rotate-canvas-right
Rotate &Canvas Right
Rotate Canvas Right
Rotate Canvas Right
1
0
Ctrl+]
false
rotate-canvas-left
Rotate Canvas &Left
Rotate Canvas Left
Rotate Canvas Left
1
0
Ctrl+[
false
rotation-reset
Reset Canvas Rotation
Reset Canvas Rotation
Reset Canvas Rotation
1
0
false
Show &Rulers
The rulers show the horizontal and vertical positions of the mouse on the image and can be used to position your mouse at the right place on the canvas. <p>Uncheck this to hide the rulers.</p>
Show Rulers
Show Rulers
1
0
true
Rulers Track Pointer
The rulers will track current mouse position and show it on screen. It can cause suptle performance slowdown
Rulers Track Pointer
Rulers Track Pointer
1
0
true
Show Guides
Show or hide guides
Show Guides
1
0
true
Lock Guides
Lock or unlock guides
Lock Guides
1
0
true
Snap to Guides
Snap cursor to guides position
Snap to Guides
1
0
true
Show Status &Bar
Show or hide the status bar
Show Status Bar
0
0
true
Show Pixel Grid
Show Pixel Grid
Show Pixel Grid
1000
- 0
+ 1000
true
view-grid
Show &Grid
Show Grid
Show Grid
1000
0
Ctrl+Shift+'
true
Snap To Grid
Snap To Grid
Snap To Grid
1000
Ctrl+Shift+;
true
Show Snap Options Popup
Show Snap Options Popup
Show Snap Options Popup
1000
Shift+s
false
Snap Orthogonal
Snap Orthogonal
Snap Orthogonal
1000
true
Snap Node
Snap Node
Snap Node
1000
true
Snap Extension
Snap Extension
Snap Extension
1000
true
Snap Intersection
Snap Intersection
Snap Intersection
1000
true
Snap Bounding Box
Snap Bounding Box
Snap Bounding Box
1000
true
Snap Image Bounds
Snap Image Bounds
Snap Image Bounds
1000
true
Snap Image Center
Snap Image Center
Snap Image Center
1000
true
S&how Painting Assistants
Show Painting Assistants
Show Painting Assistants
1000
0
true
Show &Assistant Previews
Show Assistant Previews
Show Assistant Previews
1000
0
true
S&how Reference Images
Show Reference Images
Show Reference Images
1000
0
true
Image
document-properties
&Properties...
Properties
Properties
1000
0
false
format-stroke-color
&Image Background Color and Transparency...
Change the background color of the image
Image Background Color and Transparency
1000
0
false
&Convert Image Color Space...
Convert Image Color Space
Convert Image Color Space
1000
0
false
trim-to-image
&Trim to Image Size
Trim to Image Size
Trim to Image Size
1
0
false
Trim to Current &Layer
Trim to Current Layer
Trim to Current Layer
100000
0
false
Trim to S&election
Trim to Selection
Trim to Selection
100000000
0
false
&Rotate Image...
Rotate Image
Rotate Image
1000
0
false
object-rotate-right
Rotate &Image 90° to the Right
Rotate Image 90° to the Right
Rotate Image 90° to the Right
1000
0
false
object-rotate-left
Rotate Image &90° to the Left
Rotate Image 90° to the Left
Rotate Image 90° to the Left
1000
0
false
Rotate Image &180°
Rotate Image 180°
Rotate Image 180°
1000
0
false
&Shear Image...
Shear Image
Shear Image
1000
0
false
symmetry-horizontal
&Mirror Image Horizontally
Mirror Image Horizontally
Mirror Image Horizontally
1000
0
false
symmetry-vertical
Mirror Image &Vertically
Mirror Image Vertically
Mirror Image Vertically
1000
0
false
Scale Image To &New Size...
Scale Image To New Size
Scale Image To New Size
1000
0
Ctrl+Alt+I
false
&Offset Image...
Offset Image
Offset Image
1000
0
false
R&esize Canvas...
Resize Canvas
Resize Canvas
1000
0
Ctrl+Alt+C
false
Im&age Split
Image Split
Image Split
1000
0
false
Separate Ima&ge...
Separate Image
Separate Image
1000
0
false
Select
edit-select-all
Select &All
Select All
Select All
0
0
Ctrl+A
false
edit-select-all
&Deselect
Deselect
Deselect
1100000000
0
Ctrl+Shift+A
false
&Reselect
Reselect
Reselect
0
0
Ctrl+Shift+D
false
&Invert Selection
Invert Selection
Invert Selection
10000
0
Ctrl+I
false
&Convert to Vector Selection
Convert to Vector Selection
Convert to Vector Selection
100000000000000000
0
false
&Convert to Raster Selection
Convert to Raster Selection
Convert to Raster Selection
10000000000000000
0
false
Edit Selection
Edit Selection
Edit Selection
10000000000
100
false
Convert Shapes to &Vector Selection
Convert Shapes to Vector Selection
Convert Shapes to Vector Selection
1000000000
0
false
&Feather Selection...
Feather Selection
Feather Selection
10000000000
100
Shift+F6
false
Dis&play Selection
Display Selection
Display Selection
1000
0
Ctrl+H
true
Sca&le...
Scale
Scale
100000000
100
false
S&elect from Color Range...
Select from Color Range
Select from Color Range
10000
100
false
Select &Opaque (Replace)
Select Opaque
Select Opaque
10000
100
false
Select Opaque (&Add)
Select Opaque (Add)
Select Opaque (Add)
10000
100
false
Select Opaque (&Subtract)
Select Opaque (Subtract)
Select Opaque (Subtract)
10000
100
false
Select Opaque (&Intersect)
Select Opaque (Intersect)
Select Opaque (Intersect)
10000
100
false
&Grow Selection...
Grow Selection
Grow Selection
10000000000
100
false
S&hrink Selection...
Shrink Selection
Shrink Selection
10000000000
100
false
&Border Selection...
Border Selection
Border Selection
10000000000
100
false
S&mooth
Smooth
Smooth
10000000000
100
false
Filter
&Apply Filter Again
Apply Filter Again
Apply Filter Again
0
0
Ctrl+F
false
Adjust
Adjust
Adjust
false
Artistic
Artistic
Artistic
false
Blur
Blur
Blur
false
Colors
Colors
Colors
false
Edge Detection
Edge Detection
Edge Detection
false
Enhance
Enhance
Enhance
false
Emboss
Emboss
Emboss
false
Map
Map
Map
false
Other
Other
Other
false
gmic
Start G'MIC-Qt
Start G'Mic-Qt
Start G'Mic-Qt
false
gmic
Re-apply the last G'MIC filter
Apply the last G'Mic-Qt action again
Apply the last G'Mic-Qt action again
false
Settings
configure
&Configure Krita...
Configure Krita
Configure Krita
0
0
false
&Manage Resources...
Manage Resources
Manage Resources
0
0
false
preferences-desktop-locale
Switch Application &Language...
Switch Application Language
Switch Application Language
false
&Show Dockers
Show Dockers
Show Dockers
0
0
true
configure
Configure Tool&bars...
Configure Toolbars
Configure Toolbars
0
0
false
Dockers
Dockers
Dockers
false
&Themes
Themes
Themes
false
im-user
Active Author Profile
Active Author Profile
Active Author Profile
configure-shortcuts
Configure S&hortcuts...
Configure Shortcuts
Configure Shortcuts
0
0
false
&Window
Window
Window
false
Help
help-contents
Krita &Handbook
Krita Handbook
Krita Handbook
F1
false
tools-report-bug
&Report Bug...
Report Bug
Report Bug
false
calligrakrita
&About Krita
About Krita
About Krita
false
kde
About &KDE
About KDE
About KDE
false
Brushes and Stuff
&Gradients
Gradients
Gradients
false
&Patterns
Patterns
Patterns
false
&Color
Color
Color
false
&Painter's Tools
Painter's Tools
Painter's Tools
false
Brush composite
Brush composite
Brush composite
false
Brush option slider 1
Brush option slider 1
Brush option slider 1
false
Brush option slider 2
Brush option slider 2
Brush option slider 2
false
Brush option slider 3
Brush option slider 3
Brush option slider 3
false
Mirror
Mirror
Mirror
false
Layouts
Select layout
false
Workspaces
Workspaces
Workspaces
false
diff --git a/libs/ui/KisViewManager.cpp b/libs/ui/KisViewManager.cpp
index 89139fd21f..49f340d0e9 100644
--- a/libs/ui/KisViewManager.cpp
+++ b/libs/ui/KisViewManager.cpp
@@ -1,1392 +1,1392 @@
/*
* This file is part of KimageShop^WKrayon^WKrita
*
* Copyright (c) 1999 Matthias Elter
* 1999 Michael Koch
* 1999 Carsten Pfeiffer
* 2002 Patrick Julien
* 2003-2011 Boudewijn Rempt
* 2004 Clarence Dang
* 2011 José Luis Vergara
* 2017 L. E. Segovia
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include
#include "KisViewManager.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "input/kis_input_manager.h"
#include "canvas/kis_canvas2.h"
#include "canvas/kis_canvas_controller.h"
#include "canvas/kis_grid_manager.h"
#include "dialogs/kis_dlg_blacklist_cleanup.h"
#include "input/kis_input_profile_manager.h"
#include "kis_action_manager.h"
#include "kis_action.h"
#include "kis_canvas_controls_manager.h"
#include "kis_canvas_resource_provider.h"
#include "kis_composite_progress_proxy.h"
#include
#include "kis_config.h"
#include "kis_config_notifier.h"
#include "kis_control_frame.h"
#include "kis_coordinates_converter.h"
#include "KisDocument.h"
#include "kis_favorite_resource_manager.h"
#include "kis_filter_manager.h"
#include "kis_group_layer.h"
#include
#include
#include "kis_image_manager.h"
#include
#include "kis_mainwindow_observer.h"
#include "kis_mask_manager.h"
#include "kis_mimedata.h"
#include "kis_mirror_manager.h"
#include "kis_node_commands_adapter.h"
#include "kis_node.h"
#include "kis_node_manager.h"
#include "KisDecorationsManager.h"
#include
#include "kis_paintop_box.h"
#include
#include "KisPart.h"
#include "KisPrintJob.h"
#include
#include "KisResourceServerProvider.h"
#include "kis_selection.h"
#include "kis_selection_mask.h"
#include "kis_selection_manager.h"
#include "kis_shape_controller.h"
#include "kis_shape_layer.h"
#include
#include "kis_statusbar.h"
#include
#include
#include "kis_tooltip_manager.h"
#include
#include "KisView.h"
#include "kis_zoom_manager.h"
#include "widgets/kis_floating_message.h"
#include "kis_signal_auto_connection.h"
#include "kis_icon_utils.h"
#include "kis_guides_manager.h"
#include "kis_derived_resources.h"
#include "dialogs/kis_delayed_save_dialog.h"
#include
#include "kis_signals_blocker.h"
class BlockingUserInputEventFilter : public QObject
{
bool eventFilter(QObject *watched, QEvent *event) override
{
Q_UNUSED(watched);
if(dynamic_cast(event)
|| dynamic_cast(event)
|| dynamic_cast(event)) {
return true;
}
else {
return false;
}
}
};
class KisViewManager::KisViewManagerPrivate
{
public:
KisViewManagerPrivate(KisViewManager *_q, KActionCollection *_actionCollection, QWidget *_q_parent)
: filterManager(_q)
, createTemplate(0)
, saveIncremental(0)
, saveIncrementalBackup(0)
, openResourcesDirectory(0)
, rotateCanvasRight(0)
, rotateCanvasLeft(0)
, resetCanvasRotation(0)
, wrapAroundAction(0)
, levelOfDetailAction(0)
, showRulersAction(0)
, rulersTrackMouseAction(0)
, zoomTo100pct(0)
, zoomIn(0)
, zoomOut(0)
, selectionManager(_q)
, statusBar(_q)
, controlFrame(_q, _q_parent)
, nodeManager(_q)
, imageManager(_q)
, gridManager(_q)
, canvasControlsManager(_q)
, paintingAssistantsManager(_q)
, actionManager(_q, _actionCollection)
, mainWindow(0)
, showFloatingMessage(true)
, currentImageView(0)
, canvasResourceProvider(_q)
, canvasResourceManager()
, guiUpdateCompressor(30, KisSignalCompressor::POSTPONE, _q)
, actionCollection(_actionCollection)
, mirrorManager(_q)
, inputManager(_q)
, actionAuthor(0)
, showPixelGrid(0)
{
KisViewManager::initializeResourceManager(&canvasResourceManager);
}
public:
KisFilterManager filterManager;
KisAction *createTemplate;
KisAction *createCopy;
KisAction *saveIncremental;
KisAction *saveIncrementalBackup;
KisAction *openResourcesDirectory;
KisAction *rotateCanvasRight;
KisAction *rotateCanvasLeft;
KisAction *resetCanvasRotation;
KisAction *wrapAroundAction;
KisAction *levelOfDetailAction;
KisAction *showRulersAction;
KisAction *rulersTrackMouseAction;
KisAction *zoomTo100pct;
KisAction *zoomIn;
KisAction *zoomOut;
KisAction *softProof;
KisAction *gamutCheck;
KisSelectionManager selectionManager;
KisGuidesManager guidesManager;
KisStatusBar statusBar;
QPointer persistentImageProgressUpdater;
QScopedPointer persistentUnthreadedProgressUpdaterRouter;
QPointer persistentUnthreadedProgressUpdater;
KisControlFrame controlFrame;
KisNodeManager nodeManager;
KisImageManager imageManager;
KisGridManager gridManager;
KisCanvasControlsManager canvasControlsManager;
KisDecorationsManager paintingAssistantsManager;
BlockingUserInputEventFilter blockingEventFilter;
KisActionManager actionManager;
QMainWindow* mainWindow;
QPointer savedFloatingMessage;
bool showFloatingMessage;
QPointer currentImageView;
KisCanvasResourceProvider canvasResourceProvider;
KoCanvasResourceManager canvasResourceManager;
KisSignalCompressor guiUpdateCompressor;
KActionCollection *actionCollection;
KisMirrorManager mirrorManager;
KisInputManager inputManager;
KisSignalAutoConnectionsStore viewConnections;
KSelectAction *actionAuthor; // Select action for author profile.
KisAction *showPixelGrid;
QByteArray canvasState;
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
QFlags windowFlags;
#endif
bool blockUntilOperationsFinishedImpl(KisImageSP image, bool force);
};
KisViewManager::KisViewManager(QWidget *parent, KActionCollection *_actionCollection)
: d(new KisViewManagerPrivate(this, _actionCollection, parent))
{
d->actionCollection = _actionCollection;
d->mainWindow = dynamic_cast(parent);
d->canvasResourceProvider.setResourceManager(&d->canvasResourceManager);
connect(&d->guiUpdateCompressor, SIGNAL(timeout()), this, SLOT(guiUpdateTimeout()));
createActions();
setupManagers();
// These initialization functions must wait until KisViewManager ctor is complete.
d->statusBar.setup();
d->persistentImageProgressUpdater =
d->statusBar.progressUpdater()->startSubtask(1, "", true);
// reset state to "completed"
d->persistentImageProgressUpdater->setRange(0,100);
d->persistentImageProgressUpdater->setValue(100);
d->persistentUnthreadedProgressUpdater =
d->statusBar.progressUpdater()->startSubtask(1, "", true);
// reset state to "completed"
d->persistentUnthreadedProgressUpdater->setRange(0,100);
d->persistentUnthreadedProgressUpdater->setValue(100);
d->persistentUnthreadedProgressUpdaterRouter.reset(
new KoProgressUpdater(d->persistentUnthreadedProgressUpdater,
KoProgressUpdater::Unthreaded));
d->persistentUnthreadedProgressUpdaterRouter->setAutoNestNames(true);
d->controlFrame.setup(parent);
//Check to draw scrollbars after "Canvas only mode" toggle is created.
this->showHideScrollbars();
QScopedPointer dummy(new KoDummyCanvasController(actionCollection()));
KoToolManager::instance()->registerToolActions(actionCollection(), dummy.data());
QTimer::singleShot(0, this, SLOT(initializeStatusBarVisibility()));
connect(KoToolManager::instance(), SIGNAL(inputDeviceChanged(KoInputDevice)),
d->controlFrame.paintopBox(), SLOT(slotInputDeviceChanged(KoInputDevice)));
connect(KoToolManager::instance(), SIGNAL(changedTool(KoCanvasController*,int)),
d->controlFrame.paintopBox(), SLOT(slotToolChanged(KoCanvasController*,int)));
connect(&d->nodeManager, SIGNAL(sigNodeActivated(KisNodeSP)),
resourceProvider(), SLOT(slotNodeActivated(KisNodeSP)));
connect(KisPart::instance(), SIGNAL(sigViewAdded(KisView*)), SLOT(slotViewAdded(KisView*)));
connect(KisPart::instance(), SIGNAL(sigViewRemoved(KisView*)), SLOT(slotViewRemoved(KisView*)));
connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotUpdateAuthorProfileActions()));
connect(KisConfigNotifier::instance(), SIGNAL(pixelGridModeChanged()), SLOT(slotUpdatePixelGridAction()));
KisInputProfileManager::instance()->loadProfiles();
KisConfig cfg(true);
d->showFloatingMessage = cfg.showCanvasMessages();
const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
KoColor foreground(Qt::black, cs);
d->canvasResourceProvider.setFGColor(cfg.readKoColor("LastForeGroundColor",foreground));
KoColor background(Qt::white, cs);
d->canvasResourceProvider.setBGColor(cfg.readKoColor("LastBackGroundColor",background));
}
KisViewManager::~KisViewManager()
{
KisConfig cfg(false);
if (resourceProvider() && resourceProvider()->currentPreset()) {
cfg.writeEntry("LastPreset", resourceProvider()->currentPreset()->name());
cfg.writeKoColor("LastForeGroundColor",resourceProvider()->fgColor());
cfg.writeKoColor("LastBackGroundColor",resourceProvider()->bgColor());
}
cfg.writeEntry("baseLength", KoResourceItemChooserSync::instance()->baseLength());
delete d;
}
void KisViewManager::initializeResourceManager(KoCanvasResourceManager *resourceManager)
{
resourceManager->addDerivedResourceConverter(toQShared(new KisCompositeOpResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisEffectiveCompositeOpResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisOpacityResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisFlowResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisSizeResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisLodAvailabilityResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisLodSizeThresholdResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisLodSizeThresholdSupportedResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisEraserModeResourceConverter));
resourceManager->addResourceUpdateMediator(toQShared(new KisPresetUpdateMediator));
}
KActionCollection *KisViewManager::actionCollection() const
{
return d->actionCollection;
}
void KisViewManager::slotViewAdded(KisView *view)
{
// WARNING: this slot is called even when a view from another main windows is added!
// Don't expect \p view be a child of this view manager!
Q_UNUSED(view);
if (viewCount() == 0) {
d->statusBar.showAllStatusBarItems();
}
}
void KisViewManager::slotViewRemoved(KisView *view)
{
// WARNING: this slot is called even when a view from another main windows is removed!
// Don't expect \p view be a child of this view manager!
Q_UNUSED(view);
if (viewCount() == 0) {
d->statusBar.hideAllStatusBarItems();
}
}
void KisViewManager::setCurrentView(KisView *view)
{
bool first = true;
if (d->currentImageView) {
d->currentImageView->notifyCurrentStateChanged(false);
d->currentImageView->canvasBase()->setCursor(QCursor(Qt::ArrowCursor));
first = false;
KisDocument* doc = d->currentImageView->document();
if (doc) {
doc->image()->compositeProgressProxy()->removeProxy(d->persistentImageProgressUpdater);
doc->disconnect(this);
}
d->currentImageView->canvasController()->proxyObject->disconnect(&d->statusBar);
d->viewConnections.clear();
}
QPointer imageView = qobject_cast(view);
d->currentImageView = imageView;
if (imageView) {
d->softProof->setChecked(imageView->softProofing());
d->gamutCheck->setChecked(imageView->gamutCheck());
// Wait for the async image to have loaded
KisDocument* doc = view->document();
if (KisConfig(true).readEntry("EnablePositionLabel", false)) {
connect(d->currentImageView->canvasController()->proxyObject,
SIGNAL(documentMousePositionChanged(QPointF)),
&d->statusBar,
SLOT(documentMousePositionChanged(QPointF)));
}
// Restore the last used brush preset, color and background color.
if (first) {
KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer();
QString defaultPresetName = "basic_tip_default";
bool foundTip = false;
for (int i=0; iresourceCount(); i++) {
KisPaintOpPresetSP resource = rserver->resources().at(i);
if (resource->name().toLower().contains("basic_tip_default")) {
defaultPresetName = resource->name();
foundTip = true;
} else if (foundTip == false && (resource->name().toLower().contains("default") ||
resource->filename().toLower().contains("default"))) {
defaultPresetName = resource->name();
foundTip = true;
}
}
KisConfig cfg(true);
QString lastPreset = cfg.readEntry("LastPreset", defaultPresetName);
KisPaintOpPresetSP preset = rserver->resourceByName(lastPreset);
if (!preset) {
preset = rserver->resourceByName(defaultPresetName);
}
if (!preset && !rserver->resources().isEmpty()) {
preset = rserver->resources().first();
}
if (preset) {
paintOpBox()->restoreResource(preset.data());
}
}
KisCanvasController *canvasController = dynamic_cast(d->currentImageView->canvasController());
d->viewConnections.addUniqueConnection(&d->nodeManager, SIGNAL(sigNodeActivated(KisNodeSP)), doc->image(), SLOT(requestStrokeEndActiveNode()));
d->viewConnections.addUniqueConnection(d->rotateCanvasRight, SIGNAL(triggered()), canvasController, SLOT(rotateCanvasRight15()));
d->viewConnections.addUniqueConnection(d->rotateCanvasLeft, SIGNAL(triggered()),canvasController, SLOT(rotateCanvasLeft15()));
d->viewConnections.addUniqueConnection(d->resetCanvasRotation, SIGNAL(triggered()),canvasController, SLOT(resetCanvasRotation()));
d->viewConnections.addUniqueConnection(d->wrapAroundAction, SIGNAL(toggled(bool)), canvasController, SLOT(slotToggleWrapAroundMode(bool)));
d->wrapAroundAction->setChecked(canvasController->wrapAroundMode());
d->viewConnections.addUniqueConnection(d->levelOfDetailAction, SIGNAL(toggled(bool)), canvasController, SLOT(slotToggleLevelOfDetailMode(bool)));
d->levelOfDetailAction->setChecked(canvasController->levelOfDetailMode());
d->viewConnections.addUniqueConnection(d->currentImageView->image(), SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), d->controlFrame.paintopBox(), SLOT(slotColorSpaceChanged(const KoColorSpace*)));
d->viewConnections.addUniqueConnection(d->showRulersAction, SIGNAL(toggled(bool)), imageView->zoomManager(), SLOT(setShowRulers(bool)));
d->viewConnections.addUniqueConnection(d->rulersTrackMouseAction, SIGNAL(toggled(bool)), imageView->zoomManager(), SLOT(setRulersTrackMouse(bool)));
d->viewConnections.addUniqueConnection(d->zoomTo100pct, SIGNAL(triggered()), imageView->zoomManager(), SLOT(zoomTo100()));
d->viewConnections.addUniqueConnection(d->zoomIn, SIGNAL(triggered()), imageView->zoomController()->zoomAction(), SLOT(zoomIn()));
d->viewConnections.addUniqueConnection(d->zoomOut, SIGNAL(triggered()), imageView->zoomController()->zoomAction(), SLOT(zoomOut()));
d->viewConnections.addUniqueConnection(d->softProof, SIGNAL(toggled(bool)), view, SLOT(slotSoftProofing(bool)) );
d->viewConnections.addUniqueConnection(d->gamutCheck, SIGNAL(toggled(bool)), view, SLOT(slotGamutCheck(bool)) );
// set up progrress reporting
doc->image()->compositeProgressProxy()->addProxy(d->persistentImageProgressUpdater);
d->viewConnections.addUniqueConnection(&d->statusBar, SIGNAL(sigCancellationRequested()), doc->image(), SLOT(requestStrokeCancellation()));
d->viewConnections.addUniqueConnection(d->showPixelGrid, SIGNAL(toggled(bool)), canvasController, SLOT(slotTogglePixelGrid(bool)));
imageView->zoomManager()->setShowRulers(d->showRulersAction->isChecked());
imageView->zoomManager()->setRulersTrackMouse(d->rulersTrackMouseAction->isChecked());
showHideScrollbars();
}
d->filterManager.setView(imageView);
d->selectionManager.setView(imageView);
d->guidesManager.setView(imageView);
d->nodeManager.setView(imageView);
d->imageManager.setView(imageView);
d->canvasControlsManager.setView(imageView);
d->actionManager.setView(imageView);
d->gridManager.setView(imageView);
d->statusBar.setView(imageView);
d->paintingAssistantsManager.setView(imageView);
d->mirrorManager.setView(imageView);
if (d->currentImageView) {
d->currentImageView->notifyCurrentStateChanged(true);
d->currentImageView->canvasController()->activate();
d->currentImageView->canvasController()->setFocus();
d->viewConnections.addUniqueConnection(
image(), SIGNAL(sigSizeChanged(const QPointF&, const QPointF&)),
resourceProvider(), SLOT(slotImageSizeChanged()));
d->viewConnections.addUniqueConnection(
image(), SIGNAL(sigResolutionChanged(double,double)),
resourceProvider(), SLOT(slotOnScreenResolutionChanged()));
d->viewConnections.addUniqueConnection(
image(), SIGNAL(sigNodeChanged(KisNodeSP)),
this, SLOT(updateGUI()));
d->viewConnections.addUniqueConnection(
d->currentImageView->zoomManager()->zoomController(),
SIGNAL(zoomChanged(KoZoomMode::Mode,qreal)),
resourceProvider(), SLOT(slotOnScreenResolutionChanged()));
}
d->actionManager.updateGUI();
resourceProvider()->slotImageSizeChanged();
resourceProvider()->slotOnScreenResolutionChanged();
Q_EMIT viewChanged();
}
KoZoomController *KisViewManager::zoomController() const
{
if (d->currentImageView) {
return d->currentImageView->zoomController();
}
return 0;
}
KisImageWSP KisViewManager::image() const
{
if (document()) {
return document()->image();
}
return 0;
}
KisCanvasResourceProvider * KisViewManager::resourceProvider()
{
return &d->canvasResourceProvider;
}
KisCanvas2 * KisViewManager::canvasBase() const
{
if (d && d->currentImageView) {
return d->currentImageView->canvasBase();
}
return 0;
}
QWidget* KisViewManager::canvas() const
{
if (d && d->currentImageView && d->currentImageView->canvasBase()->canvasWidget()) {
return d->currentImageView->canvasBase()->canvasWidget();
}
return 0;
}
KisStatusBar * KisViewManager::statusBar() const
{
return &d->statusBar;
}
KisPaintopBox* KisViewManager::paintOpBox() const
{
return d->controlFrame.paintopBox();
}
QPointer KisViewManager::createUnthreadedUpdater(const QString &name)
{
return d->persistentUnthreadedProgressUpdaterRouter->startSubtask(1, name, false);
}
QPointer KisViewManager::createThreadedUpdater(const QString &name)
{
return d->statusBar.progressUpdater()->startSubtask(1, name, false);
}
KisSelectionManager * KisViewManager::selectionManager()
{
return &d->selectionManager;
}
KisNodeSP KisViewManager::activeNode()
{
return d->nodeManager.activeNode();
}
KisLayerSP KisViewManager::activeLayer()
{
return d->nodeManager.activeLayer();
}
KisPaintDeviceSP KisViewManager::activeDevice()
{
return d->nodeManager.activePaintDevice();
}
KisZoomManager * KisViewManager::zoomManager()
{
if (d->currentImageView) {
return d->currentImageView->zoomManager();
}
return 0;
}
KisFilterManager * KisViewManager::filterManager()
{
return &d->filterManager;
}
KisImageManager * KisViewManager::imageManager()
{
return &d->imageManager;
}
KisInputManager* KisViewManager::inputManager() const
{
return &d->inputManager;
}
KisSelectionSP KisViewManager::selection()
{
if (d->currentImageView) {
return d->currentImageView->selection();
}
return 0;
}
bool KisViewManager::selectionEditable()
{
KisLayerSP layer = activeLayer();
if (layer) {
KisSelectionMaskSP mask = layer->selectionMask();
if (mask) {
return mask->isEditable();
}
}
// global selection is always editable
return true;
}
KisUndoAdapter * KisViewManager::undoAdapter()
{
if (!document()) return 0;
KisImageWSP image = document()->image();
Q_ASSERT(image);
return image->undoAdapter();
}
void KisViewManager::createActions()
{
KisConfig cfg(true);
d->saveIncremental = actionManager()->createAction("save_incremental_version");
connect(d->saveIncremental, SIGNAL(triggered()), this, SLOT(slotSaveIncremental()));
d->saveIncrementalBackup = actionManager()->createAction("save_incremental_backup");
connect(d->saveIncrementalBackup, SIGNAL(triggered()), this, SLOT(slotSaveIncrementalBackup()));
connect(mainWindow(), SIGNAL(documentSaved()), this, SLOT(slotDocumentSaved()));
d->saveIncremental->setEnabled(false);
d->saveIncrementalBackup->setEnabled(false);
KisAction *tabletDebugger = actionManager()->createAction("tablet_debugger");
connect(tabletDebugger, SIGNAL(triggered()), this, SLOT(toggleTabletLogger()));
d->createTemplate = actionManager()->createAction("create_template");
connect(d->createTemplate, SIGNAL(triggered()), this, SLOT(slotCreateTemplate()));
d->createCopy = actionManager()->createAction("create_copy");
connect(d->createCopy, SIGNAL(triggered()), this, SLOT(slotCreateCopy()));
d->openResourcesDirectory = actionManager()->createAction("open_resources_directory");
connect(d->openResourcesDirectory, SIGNAL(triggered()), SLOT(openResourcesDirectory()));
d->rotateCanvasRight = actionManager()->createAction("rotate_canvas_right");
d->rotateCanvasLeft = actionManager()->createAction("rotate_canvas_left");
d->resetCanvasRotation = actionManager()->createAction("reset_canvas_rotation");
d->wrapAroundAction = actionManager()->createAction("wrap_around_mode");
d->levelOfDetailAction = actionManager()->createAction("level_of_detail_mode");
d->softProof = actionManager()->createAction("softProof");
d->gamutCheck = actionManager()->createAction("gamutCheck");
KisAction *tAction = actionManager()->createAction("showStatusBar");
tAction->setChecked(cfg.showStatusBar());
connect(tAction, SIGNAL(toggled(bool)), this, SLOT(showStatusBar(bool)));
tAction = actionManager()->createAction("view_show_canvas_only");
tAction->setChecked(false);
connect(tAction, SIGNAL(toggled(bool)), this, SLOT(switchCanvasOnly(bool)));
//Workaround, by default has the same shortcut as mirrorCanvas
KisAction *a = dynamic_cast(actionCollection()->action("format_italic"));
if (a) {
a->setDefaultShortcut(QKeySequence());
}
a = actionManager()->createAction("edit_blacklist_cleanup");
connect(a, SIGNAL(triggered()), this, SLOT(slotBlacklistCleanup()));
actionManager()->createAction("ruler_pixel_multiple2");
d->showRulersAction = actionManager()->createAction("view_ruler");
d->showRulersAction->setChecked(cfg.showRulers());
connect(d->showRulersAction, SIGNAL(toggled(bool)), SLOT(slotSaveShowRulersState(bool)));
d->rulersTrackMouseAction = actionManager()->createAction("rulers_track_mouse");
d->rulersTrackMouseAction->setChecked(cfg.rulersTrackMouse());
connect(d->rulersTrackMouseAction, SIGNAL(toggled(bool)), SLOT(slotSaveRulersTrackMouseState(bool)));
d->zoomTo100pct = actionManager()->createAction("zoom_to_100pct");
d->zoomIn = actionManager()->createStandardAction(KStandardAction::ZoomIn, 0, "");
d->zoomOut = actionManager()->createStandardAction(KStandardAction::ZoomOut, 0, "");
d->actionAuthor = new KSelectAction(KisIconUtils::loadIcon("im-user"), i18n("Active Author Profile"), this);
connect(d->actionAuthor, SIGNAL(triggered(const QString &)), this, SLOT(changeAuthorProfile(const QString &)));
actionCollection()->addAction("settings_active_author", d->actionAuthor);
slotUpdateAuthorProfileActions();
d->showPixelGrid = actionManager()->createAction("view_pixel_grid");
slotUpdatePixelGridAction();
}
void KisViewManager::setupManagers()
{
// Create the managers for filters, selections, layers etc.
// XXX: When the currentlayer changes, call updateGUI on all
// managers
d->filterManager.setup(actionCollection(), actionManager());
d->selectionManager.setup(actionManager());
d->guidesManager.setup(actionManager());
d->nodeManager.setup(actionCollection(), actionManager());
d->imageManager.setup(actionManager());
d->gridManager.setup(actionManager());
d->paintingAssistantsManager.setup(actionManager());
d->canvasControlsManager.setup(actionManager());
d->mirrorManager.setup(actionCollection());
}
void KisViewManager::updateGUI()
{
d->guiUpdateCompressor.start();
}
void KisViewManager::slotBlacklistCleanup()
{
KisDlgBlacklistCleanup dialog;
dialog.exec();
}
KisNodeManager * KisViewManager::nodeManager() const
{
return &d->nodeManager;
}
KisActionManager* KisViewManager::actionManager() const
{
return &d->actionManager;
}
KisGridManager * KisViewManager::gridManager() const
{
return &d->gridManager;
}
KisGuidesManager * KisViewManager::guidesManager() const
{
return &d->guidesManager;
}
KisDocument *KisViewManager::document() const
{
if (d->currentImageView && d->currentImageView->document()) {
return d->currentImageView->document();
}
return 0;
}
int KisViewManager::viewCount() const
{
KisMainWindow *mw = qobject_cast(d->mainWindow);
if (mw) {
return mw->viewCount();
}
return 0;
}
bool KisViewManager::KisViewManagerPrivate::blockUntilOperationsFinishedImpl(KisImageSP image, bool force)
{
const int busyWaitDelay = 1000;
KisDelayedSaveDialog dialog(image, !force ? KisDelayedSaveDialog::GeneralDialog : KisDelayedSaveDialog::ForcedDialog, busyWaitDelay, mainWindow);
dialog.blockIfImageIsBusy();
return dialog.result() == QDialog::Accepted;
}
bool KisViewManager::blockUntilOperationsFinished(KisImageSP image)
{
return d->blockUntilOperationsFinishedImpl(image, false);
}
void KisViewManager::blockUntilOperationsFinishedForced(KisImageSP image)
{
d->blockUntilOperationsFinishedImpl(image, true);
}
void KisViewManager::slotCreateTemplate()
{
if (!document()) return;
KisTemplateCreateDia::createTemplate( QStringLiteral("templates/"), ".kra", document(), mainWindow());
}
void KisViewManager::slotCreateCopy()
{
KisDocument *srcDoc = document();
if (!srcDoc) return;
if (!this->blockUntilOperationsFinished(srcDoc->image())) return;
KisDocument *doc = 0;
{
KisImageBarrierLocker l(srcDoc->image());
doc = srcDoc->clone();
}
KIS_SAFE_ASSERT_RECOVER_RETURN(doc);
QString name = srcDoc->documentInfo()->aboutInfo("name");
if (name.isEmpty()) {
name = document()->url().toLocalFile();
}
name = i18n("%1 (Copy)", name);
doc->documentInfo()->setAboutInfo("title", name);
KisPart::instance()->addDocument(doc);
KisMainWindow *mw = qobject_cast(d->mainWindow);
mw->addViewAndNotifyLoadingCompleted(doc);
}
QMainWindow* KisViewManager::qtMainWindow() const
{
if (d->mainWindow)
return d->mainWindow;
//Fallback for when we have not yet set the main window.
QMainWindow* w = qobject_cast(qApp->activeWindow());
if(w)
return w;
return mainWindow();
}
void KisViewManager::setQtMainWindow(QMainWindow* newMainWindow)
{
d->mainWindow = newMainWindow;
}
void KisViewManager::slotDocumentSaved()
{
d->saveIncremental->setEnabled(true);
d->saveIncrementalBackup->setEnabled(true);
}
void KisViewManager::slotSaveIncremental()
{
if (!document()) return;
if (document()->url().isEmpty()) {
KisMainWindow *mw = qobject_cast(d->mainWindow);
mw->saveDocument(document(), true, false);
return;
}
bool foundVersion;
bool fileAlreadyExists;
bool isBackup;
QString version = "000";
QString newVersion;
QString letter;
QString fileName = document()->localFilePath();
// Find current version filenames
// v v Regexp to find incremental versions in the filename, taking our backup scheme into account as well
// Considering our incremental version and backup scheme, format is filename_001~001.ext
QRegExp regex("_\\d{1,4}[.]|_\\d{1,4}[a-z][.]|_\\d{1,4}[~]|_\\d{1,4}[a-z][~]");
regex.indexIn(fileName); // Perform the search
QStringList matches = regex.capturedTexts();
foundVersion = matches.at(0).isEmpty() ? false : true;
// Ensure compatibility with Save Incremental Backup
// If this regex is not kept separate, the entire algorithm needs modification;
// It's simpler to just add this.
QRegExp regexAux("_\\d{1,4}[~]|_\\d{1,4}[a-z][~]");
regexAux.indexIn(fileName); // Perform the search
QStringList matchesAux = regexAux.capturedTexts();
isBackup = matchesAux.at(0).isEmpty() ? false : true;
// If the filename has a version, prepare it for incrementation
if (foundVersion) {
version = matches.at(matches.count() - 1); // Look at the last index, we don't care about other matches
if (version.contains(QRegExp("[a-z]"))) {
version.chop(1); // Trim "."
letter = version.right(1); // Save letter
version.chop(1); // Trim letter
} else {
version.chop(1); // Trim "."
}
version.remove(0, 1); // Trim "_"
} else {
// TODO: this will not work with files extensions like jp2
// ...else, simply add a version to it so the next loop works
QRegExp regex2("[.][a-z]{2,4}$"); // Heuristic to find file extension
regex2.indexIn(fileName);
QStringList matches2 = regex2.capturedTexts();
QString extensionPlusVersion = matches2.at(0);
extensionPlusVersion.prepend(version);
extensionPlusVersion.prepend("_");
fileName.replace(regex2, extensionPlusVersion);
}
// Prepare the base for new version filename
int intVersion = version.toInt(0);
++intVersion;
QString baseNewVersion = QString::number(intVersion);
while (baseNewVersion.length() < version.length()) {
baseNewVersion.prepend("0");
}
// Check if the file exists under the new name and search until options are exhausted (test appending a to z)
do {
newVersion = baseNewVersion;
newVersion.prepend("_");
if (!letter.isNull()) newVersion.append(letter);
if (isBackup) {
newVersion.append("~");
} else {
newVersion.append(".");
}
fileName.replace(regex, newVersion);
fileAlreadyExists = QFile(fileName).exists();
if (fileAlreadyExists) {
if (!letter.isNull()) {
char letterCh = letter.at(0).toLatin1();
++letterCh;
letter = QString(QChar(letterCh));
} else {
letter = 'a';
}
}
} while (fileAlreadyExists && letter != "{"); // x, y, z, {...
if (letter == "{") {
QMessageBox::critical(mainWindow(), i18nc("@title:window", "Couldn't save incremental version"), i18n("Alternative names exhausted, try manually saving with a higher number"));
return;
}
document()->setFileBatchMode(true);
document()->saveAs(QUrl::fromUserInput(fileName), document()->mimeType(), true);
document()->setFileBatchMode(false);
if (mainWindow()) {
mainWindow()->updateCaption();
}
}
void KisViewManager::slotSaveIncrementalBackup()
{
if (!document()) return;
if (document()->url().isEmpty()) {
KisMainWindow *mw = qobject_cast(d->mainWindow);
mw->saveDocument(document(), true, false);
return;
}
bool workingOnBackup;
bool fileAlreadyExists;
QString version = "000";
QString newVersion;
QString letter;
QString fileName = document()->localFilePath();
// First, discover if working on a backup file, or a normal file
QRegExp regex("~\\d{1,4}[.]|~\\d{1,4}[a-z][.]");
regex.indexIn(fileName); // Perform the search
QStringList matches = regex.capturedTexts();
workingOnBackup = matches.at(0).isEmpty() ? false : true;
if (workingOnBackup) {
// Try to save incremental version (of backup), use letter for alt versions
version = matches.at(matches.count() - 1); // Look at the last index, we don't care about other matches
if (version.contains(QRegExp("[a-z]"))) {
version.chop(1); // Trim "."
letter = version.right(1); // Save letter
version.chop(1); // Trim letter
} else {
version.chop(1); // Trim "."
}
version.remove(0, 1); // Trim "~"
// Prepare the base for new version filename
int intVersion = version.toInt(0);
++intVersion;
QString baseNewVersion = QString::number(intVersion);
QString backupFileName = document()->localFilePath();
while (baseNewVersion.length() < version.length()) {
baseNewVersion.prepend("0");
}
// Check if the file exists under the new name and search until options are exhausted (test appending a to z)
do {
newVersion = baseNewVersion;
newVersion.prepend("~");
if (!letter.isNull()) newVersion.append(letter);
newVersion.append(".");
backupFileName.replace(regex, newVersion);
fileAlreadyExists = QFile(backupFileName).exists();
if (fileAlreadyExists) {
if (!letter.isNull()) {
char letterCh = letter.at(0).toLatin1();
++letterCh;
letter = QString(QChar(letterCh));
} else {
letter = 'a';
}
}
} while (fileAlreadyExists && letter != "{"); // x, y, z, {...
if (letter == "{") {
QMessageBox::critical(mainWindow(), i18nc("@title:window", "Couldn't save incremental backup"), i18n("Alternative names exhausted, try manually saving with a higher number"));
return;
}
QFile::copy(fileName, backupFileName);
document()->saveAs(QUrl::fromUserInput(fileName), document()->mimeType(), true);
if (mainWindow()) mainWindow()->updateCaption();
}
else { // if NOT working on a backup...
// Navigate directory searching for latest backup version, ignore letters
const quint8 HARDCODED_DIGIT_COUNT = 3;
QString baseNewVersion = "000";
QString backupFileName = document()->localFilePath();
QRegExp regex2("[.][a-z]{2,4}$"); // Heuristic to find file extension
regex2.indexIn(backupFileName);
QStringList matches2 = regex2.capturedTexts();
QString extensionPlusVersion = matches2.at(0);
extensionPlusVersion.prepend(baseNewVersion);
extensionPlusVersion.prepend("~");
backupFileName.replace(regex2, extensionPlusVersion);
// Save version with 1 number higher than the highest version found ignoring letters
do {
newVersion = baseNewVersion;
newVersion.prepend("~");
newVersion.append(".");
backupFileName.replace(regex, newVersion);
fileAlreadyExists = QFile(backupFileName).exists();
if (fileAlreadyExists) {
// Prepare the base for new version filename, increment by 1
int intVersion = baseNewVersion.toInt(0);
++intVersion;
baseNewVersion = QString::number(intVersion);
while (baseNewVersion.length() < HARDCODED_DIGIT_COUNT) {
baseNewVersion.prepend("0");
}
}
} while (fileAlreadyExists);
// Save both as backup and on current file for interapplication workflow
document()->setFileBatchMode(true);
QFile::copy(fileName, backupFileName);
document()->saveAs(QUrl::fromUserInput(fileName), document()->mimeType(), true);
document()->setFileBatchMode(false);
if (mainWindow()) mainWindow()->updateCaption();
}
}
void KisViewManager::disableControls()
{
// prevents possible crashes, if somebody changes the paintop during dragging by using the mousewheel
// this is for Bug 250944
// the solution blocks all wheel, mouse and key event, while dragging with the freehand tool
// see KisToolFreehand::initPaint() and endPaint()
d->controlFrame.paintopBox()->installEventFilter(&d->blockingEventFilter);
Q_FOREACH (QObject* child, d->controlFrame.paintopBox()->children()) {
child->installEventFilter(&d->blockingEventFilter);
}
}
void KisViewManager::enableControls()
{
d->controlFrame.paintopBox()->removeEventFilter(&d->blockingEventFilter);
Q_FOREACH (QObject* child, d->controlFrame.paintopBox()->children()) {
child->removeEventFilter(&d->blockingEventFilter);
}
}
void KisViewManager::showStatusBar(bool toggled)
{
KisMainWindow *mw = mainWindow();
if(mw && mw->statusBar()) {
mw->statusBar()->setVisible(toggled);
KisConfig cfg(false);
cfg.setShowStatusBar(toggled);
}
}
void KisViewManager::switchCanvasOnly(bool toggled)
{
KisConfig cfg(false);
KisMainWindow* main = mainWindow();
if(!main) {
dbgUI << "Unable to switch to canvas-only mode, main window not found";
return;
}
if (toggled) {
d->canvasState = qtMainWindow()->saveState();
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
d->windowFlags = main->windowState();
#endif
}
if (cfg.hideStatusbarFullscreen()) {
if (main->statusBar()) {
if (!toggled) {
if (main->statusBar()->dynamicPropertyNames().contains("wasvisible")) {
if (main->statusBar()->property("wasvisible").toBool()) {
main->statusBar()->setVisible(true);
}
}
}
else {
main->statusBar()->setProperty("wasvisible", main->statusBar()->isVisible());
main->statusBar()->setVisible(false);
}
}
}
if (cfg.hideDockersFullscreen()) {
KisAction* action = qobject_cast(main->actionCollection()->action("view_toggledockers"));
if (action) {
action->setCheckable(true);
if (toggled) {
if (action->isChecked()) {
cfg.setShowDockers(action->isChecked());
action->setChecked(false);
} else {
cfg.setShowDockers(false);
}
} else {
action->setChecked(cfg.showDockers());
}
}
}
// QT in windows does not return to maximized upon 4th tab in a row
// https://bugreports.qt.io/browse/QTBUG-57882, https://bugreports.qt.io/browse/QTBUG-52555, https://codereview.qt-project.org/#/c/185016/
if (cfg.hideTitlebarFullscreen() && !cfg.fullscreenMode()) {
if(toggled) {
main->setWindowState( main->windowState() | Qt::WindowFullScreen);
} else {
main->setWindowState( main->windowState() & ~Qt::WindowFullScreen);
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
// If window was maximized prior to fullscreen, restore that
if (d->windowFlags & Qt::WindowMaximized) {
main->setWindowState( main->windowState() | Qt::WindowMaximized);
}
#endif
}
}
if (cfg.hideMenuFullscreen()) {
if (!toggled) {
if (main->menuBar()->dynamicPropertyNames().contains("wasvisible")) {
if (main->menuBar()->property("wasvisible").toBool()) {
main->menuBar()->setVisible(true);
}
}
}
else {
main->menuBar()->setProperty("wasvisible", main->menuBar()->isVisible());
main->menuBar()->setVisible(false);
}
}
if (cfg.hideToolbarFullscreen()) {
QList toolBars = main->findChildren();
Q_FOREACH (QToolBar* toolbar, toolBars) {
if (!toggled) {
if (toolbar->dynamicPropertyNames().contains("wasvisible")) {
if (toolbar->property("wasvisible").toBool()) {
toolbar->setVisible(true);
}
}
}
else {
toolbar->setProperty("wasvisible", toolbar->isVisible());
toolbar->setVisible(false);
}
}
}
showHideScrollbars();
if (toggled) {
// show a fading heads-up display about the shortcut to go back
showFloatingMessage(i18n("Going into Canvas-Only mode.\nPress %1 to go back.",
actionCollection()->action("view_show_canvas_only")->shortcut().toString()), QIcon());
}
else {
main->restoreState(d->canvasState);
}
}
void KisViewManager::toggleTabletLogger()
{
d->inputManager.toggleTabletLogger();
}
void KisViewManager::openResourcesDirectory()
{
QString dir = KoResourcePaths::locateLocal("data", "");
QDesktopServices::openUrl(QUrl::fromLocalFile(dir));
}
void KisViewManager::updateIcons()
{
if (mainWindow()) {
QList dockers = mainWindow()->dockWidgets();
Q_FOREACH (QDockWidget* dock, dockers) {
QObjectList objects;
objects.append(dock);
while (!objects.isEmpty()) {
QObject* object = objects.takeFirst();
objects.append(object->children());
KisIconUtils::updateIconCommon(object);
}
}
}
}
void KisViewManager::initializeStatusBarVisibility()
{
KisConfig cfg(true);
d->mainWindow->statusBar()->setVisible(cfg.showStatusBar());
}
void KisViewManager::guiUpdateTimeout()
{
d->nodeManager.updateGUI();
d->selectionManager.updateGUI();
d->filterManager.updateGUI();
if (zoomManager()) {
zoomManager()->updateGUI();
}
d->gridManager.updateGUI();
d->actionManager.updateGUI();
}
void KisViewManager::showFloatingMessage(const QString &message, const QIcon& icon, int timeout, KisFloatingMessage::Priority priority, int alignment)
{
if (!d->currentImageView) return;
d->currentImageView->showFloatingMessageImpl(message, icon, timeout, priority, alignment);
emit floatingMessageRequested(message, icon.name());
}
KisMainWindow *KisViewManager::mainWindow() const
{
return qobject_cast(d->mainWindow);
}
void KisViewManager::showHideScrollbars()
{
if (!d->currentImageView) return;
if (!d->currentImageView->canvasController()) return;
KisConfig cfg(true);
bool toggled = actionCollection()->action("view_show_canvas_only")->isChecked();
if ( (toggled && cfg.hideScrollbarsFullscreen()) || (!toggled && cfg.hideScrollbars()) ) {
d->currentImageView->canvasController()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
d->currentImageView->canvasController()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
} else {
d->currentImageView->canvasController()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
d->currentImageView->canvasController()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
}
}
void KisViewManager::slotSaveShowRulersState(bool value)
{
KisConfig cfg(false);
cfg.setShowRulers(value);
}
void KisViewManager::slotSaveRulersTrackMouseState(bool value)
{
KisConfig cfg(false);
cfg.setRulersTrackMouse(value);
}
void KisViewManager::setShowFloatingMessage(bool show)
{
d->showFloatingMessage = show;
}
void KisViewManager::changeAuthorProfile(const QString &profileName)
{
KConfigGroup appAuthorGroup(KSharedConfig::openConfig(), "Author");
if (profileName.isEmpty() || profileName == i18nc("choice for author profile", "Anonymous")) {
appAuthorGroup.writeEntry("active-profile", "");
} else {
appAuthorGroup.writeEntry("active-profile", profileName);
}
appAuthorGroup.sync();
Q_FOREACH (KisDocument *doc, KisPart::instance()->documents()) {
doc->documentInfo()->updateParameters();
}
}
void KisViewManager::slotUpdateAuthorProfileActions()
{
Q_ASSERT(d->actionAuthor);
if (!d->actionAuthor) {
return;
}
d->actionAuthor->clear();
d->actionAuthor->addAction(i18nc("choice for author profile", "Anonymous"));
KConfigGroup authorGroup(KSharedConfig::openConfig(), "Author");
QStringList profiles = authorGroup.readEntry("profile-names", QStringList());
QString authorInfo = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/authorinfo/";
QStringList filters = QStringList() << "*.authorinfo";
QDir dir(authorInfo);
Q_FOREACH(QString entry, dir.entryList(filters)) {
int ln = QString(".authorinfo").size();
entry.chop(ln);
if (!profiles.contains(entry)) {
profiles.append(entry);
}
}
Q_FOREACH (const QString &profile , profiles) {
d->actionAuthor->addAction(profile);
}
KConfigGroup appAuthorGroup(KSharedConfig::openConfig(), "Author");
QString profileName = appAuthorGroup.readEntry("active-profile", "");
if (profileName == "anonymous" || profileName.isEmpty()) {
d->actionAuthor->setCurrentItem(0);
} else if (profiles.contains(profileName)) {
d->actionAuthor->setCurrentAction(profileName);
}
}
void KisViewManager::slotUpdatePixelGridAction()
{
KIS_SAFE_ASSERT_RECOVER_RETURN(d->showPixelGrid);
KisSignalsBlocker b(d->showPixelGrid);
KisConfig cfg(true);
- d->showPixelGrid->setChecked(cfg.pixelGridEnabled());
+ d->showPixelGrid->setChecked(cfg.pixelGridEnabled() && cfg.useOpenGL());
}
diff --git a/libs/ui/kis_action.h b/libs/ui/kis_action.h
index 8777a09e8b..527de5de1d 100644
--- a/libs/ui/kis_action.h
+++ b/libs/ui/kis_action.h
@@ -1,133 +1,134 @@
/*
* Copyright (c) 2013 Sven Langkamp
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_ACTION_H
#define KIS_ACTION_H
#include
#include
#include
#include
class KisActionManager;
/**
* KisAction, inheriting from QWidgetAction, is a convenience class for GUI
* actions, with Krita's configuration system and GUI states. A widget like a
* "save" button may be enabled/disabled, hidden or shown depending on the
* state of the application, e.g. whether the image currently being viewed was
* modified since it was opened.
*
* Copies of these actions are created for each MainWindow instance. They are
* owned by a KisActionManager, of which there is one for each MainWindow. Most
* of these instantiations happen inside the constructor for KisMainWindow as
* well as the various functions called in KisViewManager::setupManagers().
*
**/
class KRITAUI_EXPORT KisAction : public QWidgetAction
{
Q_OBJECT
public:
/**
* If you re-order these, you must change the associated values in
* krita.action and kritamenu.action!
*/
enum ActivationFlag {
NONE = 0x0000, ///< Always activate
ACTIVE_IMAGE = 0x0001, ///< Activate if there is at least one image
MULTIPLE_IMAGES = 0x0002, ///< Activate if there is more than one image open
CURRENT_IMAGE_MODIFIED = 0x0004, ///< Activate if the current image is modified
ACTIVE_NODE = 0x0008, ///< Activate if there's an active node (layer or mask)
ACTIVE_DEVICE = 0x0010, ///< Activate if the active node has a paint device, i.e. there are pixels to be modified
ACTIVE_LAYER = 0x0020, ///< Activate if the current node is a layer (vector or pixel)
ACTIVE_TRANSPARENCY_MASK = 0x0040, ///< Activate if the current node is a transparency mask
ACTIVE_SHAPE_LAYER = 0x0080, ///< Activate if the current node is a vector layer
PIXELS_SELECTED = 0x0100, ///< Activate if any pixels are selcted (with any kind of selection)
SHAPES_SELECTED = 0x0200, ///< Activate if any vector shape is selected
ANY_SELECTION_WITH_PIXELS = 0x0400, ///< ???
PIXELS_IN_CLIPBOARD = 0x0800, ///< Activate if the clipboard contains pixels
SHAPES_IN_CLIPBOARD = 0x1000, ///< Activate if the clipboard contains vector data
NEVER_ACTIVATE = 0x2000, ///< ???
LAYERS_IN_CLIPBOARD = 0x4000, ///< ???
IMAGE_HAS_ANIMATION = 0x8000, ///< Activate if the image has an animation
SHAPE_SELECTION_WITH_SHAPES = 0x10000, ///< Activate there is a vector selection active
PIXEL_SELECTION_WITH_PIXELS = 0x20000, ///< Activate there is a raster selection active
};
Q_DECLARE_FLAGS(ActivationFlags, ActivationFlag)
enum ActivationCondition {
NO_CONDITION = 0,
ACTIVE_NODE_EDITABLE = 0x1,
ACTIVE_NODE_EDITABLE_PAINT_DEVICE = 0x2,
- SELECTION_EDITABLE = 0x4
+ SELECTION_EDITABLE = 0x4,
+ OPENGL_ENABLED = 0x8,
};
Q_DECLARE_FLAGS(ActivationConditions, ActivationCondition)
explicit KisAction(QObject* parent = 0);
KisAction(const QString& text, QObject* parent = 0);
KisAction(const QIcon& icon, const QString& text, QObject* parent = 0);
~KisAction() override;
void setDefaultShortcut(const QKeySequence & shortcut);
QKeySequence defaultShortcut() const;
void setActivationFlags(ActivationFlags flags);
ActivationFlags activationFlags();
void setActivationConditions(ActivationConditions conditions);
ActivationConditions activationConditions();
void setExcludedNodeTypes(const QStringList &nodeTypes);
const QStringList& excludedNodeTypes() const;
virtual void setActionEnabled(bool enabled);
/**
* Set operation id. This will used to run an operation in the KisActionManager
*/
void setOperationID(const QString& id);
Q_SIGNALS:
void sigEnableSlaves(bool value);
private Q_SLOTS:
void slotTriggered();
void slotChanged();
private:
friend class KisActionManager;
/**
* Set the action manager. Only used by KisActionManager
*/
void setActionManager(KisActionManager* actionManager);
class Private;
Private* const d;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(KisAction::ActivationFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(KisAction::ActivationConditions)
#endif // KIS_ACTION_H
diff --git a/libs/ui/kis_action_manager.cpp b/libs/ui/kis_action_manager.cpp
index 3ad124c55a..16709928c4 100644
--- a/libs/ui/kis_action_manager.cpp
+++ b/libs/ui/kis_action_manager.cpp
@@ -1,491 +1,499 @@
/*
* Copyright (c) 2013 Sven Langkamp
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_action_manager.h"
#include
#include
#include
#include "KisPart.h"
#include "kis_action.h"
#include "KisViewManager.h"
#include "kis_selection_manager.h"
#include "operations/kis_operation_ui_factory.h"
#include "operations/kis_operation_registry.h"
#include "operations/kis_operation.h"
#include "kis_layer.h"
#include "KisDocument.h"
#include "kis_clipboard.h"
#include
+#include "kis_config.h"
#include
#include "QFile"
#include
#include
class Q_DECL_HIDDEN KisActionManager::Private {
public:
Private()
: viewManager(0)
{}
~Private()
{
qDeleteAll(uiRegistry.values());
}
KisViewManager* viewManager;
KActionCollection *actionCollection;
QList> actions;
KoGenericRegistry uiRegistry;
KisOperationRegistry operationRegistry;
};
KisActionManager::KisActionManager(KisViewManager* viewManager, KActionCollection *actionCollection)
: d(new Private)
{
d->viewManager = viewManager;
d->actionCollection = actionCollection;
connect(d->actionCollection,
SIGNAL(inserted(QAction*)), SLOT(slotActionAddedToCollection(QAction*)));
}
KisActionManager::~KisActionManager()
{
#if 0
if ((d->actions.size() > 0)) {
QDomDocument doc;
QDomElement e = doc.createElement("Actions");
e.setAttribute("version", "2");
doc.appendChild(e);
Q_FOREACH (KisAction *action, d->actions) {
QDomElement a = doc.createElement("Action");
a.setAttribute("name", action->objectName());
// But seriously, XML is the worst format ever designed
auto addElement = [&](QString title, QString content) {
QDomElement newNode = doc.createElement(title);
QDomText newText = doc.createTextNode(content);
newNode.appendChild(newText);
a.appendChild(newNode);
};
addElement("icon", action->icon().name());
addElement("text", action->text());
addElement("whatsThis" , action->whatsThis());
addElement("toolTip" , action->toolTip());
addElement("iconText" , action->iconText());
addElement("shortcut" , action->shortcut().toString());
addElement("activationFlags" , QString::number(action->activationFlags(),2));
addElement("activationConditions" , QString::number(action->activationConditions(),2));
addElement("defaultShortcut" , action->defaultShortcut().toString());
addElement("isCheckable" , QString((action->isChecked() ? "true" : "false")));
addElement("statusTip", action->statusTip());
e.appendChild(a);
}
QFile f("ActionManager.action");
f.open(QFile::WriteOnly);
f.write(doc.toString().toUtf8());
f.close();
}
#endif
delete d;
}
void KisActionManager::setView(QPointer imageView)
{
Q_UNUSED(imageView);
}
void KisActionManager::slotActionAddedToCollection(QAction *action)
{
/**
* Small hack alert: not all the actions are still created by the manager and
* immediately added to the action collection. Some plugins add actions
* directly to the action collection when a document is created. Here we
* catch these cases
*/
KisActionRegistry::instance()->updateShortcut(action->objectName(), action);
}
void KisActionManager::addAction(const QString& name, KisAction* action)
{
Q_ASSERT(!name.isEmpty());
Q_ASSERT(action);
Q_ASSERT(d->viewManager);
Q_ASSERT(d->actionCollection);
d->actionCollection->addAction(name, action);
action->setParent(d->actionCollection);
d->actions.append(action);
action->setActionManager(this);
}
void KisActionManager::takeAction(KisAction* action)
{
d->actions.removeOne(action);
if (!action->objectName().isEmpty()) {
KIS_ASSERT_RECOVER_RETURN(d->actionCollection);
d->actionCollection->takeAction(action);
}
}
KisAction *KisActionManager::actionByName(const QString &name) const
{
Q_FOREACH (KisAction *action, d->actions) {
if (action->objectName() == name) {
return action;
}
}
return 0;
}
KisAction *KisActionManager::createAction(const QString &name)
{
KisAction *a = actionByName(name); // Check if the action already exists
if (a) {
return a;
}
// There is some tension here. KisActionManager is supposed to be in control
// of global actions, but these actions are supposed to be duplicated. We
// will add them to the KisActionRegistry for the time being so we can get
// properly categorized shortcuts.
a = new KisAction();
KisActionRegistry *actionRegistry = KisActionRegistry::instance();
// Add extra properties
actionRegistry->propertizeAction(name, a);
bool ok; // We will skip this check
int activationFlags = actionRegistry->getActionProperty(name, "activationFlags").toInt(&ok, 2);
int activationConditions = actionRegistry->getActionProperty(name, "activationConditions").toInt(&ok, 2);
a->setActivationFlags((KisAction::ActivationFlags) activationFlags);
a->setActivationConditions((KisAction::ActivationConditions) activationConditions);
addAction(name, a);
return a;
}
void KisActionManager::updateGUI()
{
//TODO other flags
KisAction::ActivationFlags flags;
KisImageWSP image;
KisNodeSP node;
KisLayerSP layer;
KisSelectionManager *selectionManager = 0;
KisAction::ActivationConditions conditions = KisAction::NO_CONDITION;
if (d->viewManager) {
node = d->viewManager->activeNode();
selectionManager = d->viewManager->selectionManager();
// if there are no views, that means no document is open.
// we cannot have nodes (selections), devices, or documents without a view
if ( d->viewManager->viewCount() > 0 )
{
image = d->viewManager->image();
flags |= KisAction::ACTIVE_IMAGE;
if (image && image->animationInterface()->hasAnimation()) {
flags |= KisAction::IMAGE_HAS_ANIMATION;
}
if (d->viewManager->viewCount() > 1) {
flags |= KisAction::MULTIPLE_IMAGES;
}
if (d->viewManager->document() && d->viewManager->document()->isModified()) {
flags |= KisAction::CURRENT_IMAGE_MODIFIED;
}
if (d->viewManager->activeDevice()) {
flags |= KisAction::ACTIVE_DEVICE;
}
}
if (d->viewManager->selectionEditable()) {
conditions |= KisAction::SELECTION_EDITABLE;
}
}
// is there a selection/mask?
// you have to have at least one view (document) open for this to be true
if (node) {
// if a node exists, we know there is an active layer as well
flags |= KisAction::ACTIVE_NODE;
layer = qobject_cast(node.data());
if (layer) {
flags |= KisAction::ACTIVE_LAYER;
}
if (node->inherits("KisTransparencyMask")) {
flags |= KisAction::ACTIVE_TRANSPARENCY_MASK;
}
if (layer && layer->inherits("KisShapeLayer")) {
flags |= KisAction::ACTIVE_SHAPE_LAYER;
}
if (KisClipboard::instance()->hasLayers()) {
flags |= KisAction::LAYERS_IN_CLIPBOARD;
}
if (selectionManager) {
if (selectionManager->havePixelsSelected()) {
flags |= KisAction::PIXELS_SELECTED;
}
if (selectionManager->haveShapesSelected()) {
flags |= KisAction::SHAPES_SELECTED;
}
if (selectionManager->haveAnySelectionWithPixels()) {
flags |= KisAction::ANY_SELECTION_WITH_PIXELS;
}
if (selectionManager->haveShapeSelectionWithShapes()) {
flags |= KisAction::SHAPE_SELECTION_WITH_SHAPES;
}
if (selectionManager->haveRasterSelectionWithPixels()) {
flags |= KisAction::PIXEL_SELECTION_WITH_PIXELS;
}
if (selectionManager->havePixelsInClipboard()) {
flags |= KisAction::PIXELS_IN_CLIPBOARD;
}
if (selectionManager->haveShapesInClipboard()) {
flags |= KisAction::SHAPES_IN_CLIPBOARD;
}
}
if (node->isEditable(false)) {
conditions |= KisAction::ACTIVE_NODE_EDITABLE;
}
if (node->hasEditablePaintDevice()) {
conditions |= KisAction::ACTIVE_NODE_EDITABLE_PAINT_DEVICE;
}
}
+ KisConfig cfg(true);
+ if (cfg.useOpenGL()) {
+ conditions |= KisAction::OPENGL_ENABLED;
+ }
// loop through all actions in action manager and determine what should be enabled
Q_FOREACH (QPointer action, d->actions) {
bool enable;
if (action) {
if (action->activationFlags() == KisAction::NONE) {
enable = true;
}
else {
enable = action->activationFlags() & flags; // combine action flags with updateGUI flags
}
enable = enable && (int)(action->activationConditions() & conditions) == (int)action->activationConditions();
if (node && enable) {
Q_FOREACH (const QString &type, action->excludedNodeTypes()) {
if (node->inherits(type.toLatin1())) {
enable = false;
break;
}
}
}
action->setActionEnabled(enable);
}
}
}
KisAction *KisActionManager::createStandardAction(KStandardAction::StandardAction actionType, const QObject *receiver, const char *member)
{
QAction *standardAction = KStandardAction::create(actionType, receiver, member, 0);
KisAction *action = new KisAction(standardAction->icon(), standardAction->text());
const QList defaultShortcuts = standardAction->property("defaultShortcuts").value >();
const QKeySequence defaultShortcut = defaultShortcuts.isEmpty() ? QKeySequence() : defaultShortcuts.at(0);
action->setDefaultShortcut(standardAction->shortcut());
#ifdef Q_OS_WIN
if (actionType == KStandardAction::SaveAs && defaultShortcuts.isEmpty()) {
action->setShortcut(QKeySequence("CTRL+SHIFT+S"));
}
#endif
action->setCheckable(standardAction->isCheckable());
if (action->isCheckable()) {
action->setChecked(standardAction->isChecked());
}
action->setMenuRole(standardAction->menuRole());
action->setText(standardAction->text());
action->setToolTip(standardAction->toolTip());
if (receiver && member) {
if (actionType == KStandardAction::OpenRecent) {
QObject::connect(action, SIGNAL(urlSelected(QUrl)), receiver, member);
}
else if (actionType == KStandardAction::ConfigureToolbars) {
QObject::connect(action, SIGNAL(triggered(bool)), receiver, member, Qt::QueuedConnection);
}
else {
QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
}
}
KisActionRegistry *actionRegistry = KisActionRegistry::instance();
actionRegistry->propertizeAction(standardAction->objectName(), action);
addAction(standardAction->objectName(), action);
delete standardAction;
return action;
}
void KisActionManager::safePopulateMenu(QMenu *menu, const QString &actionId, KisActionManager *actionManager)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(actionManager);
KisAction *action = actionManager->actionByName(actionId);
KIS_SAFE_ASSERT_RECOVER_RETURN(action);
menu->addAction(action);
}
void KisActionManager::registerOperationUIFactory(KisOperationUIFactory* factory)
{
d->uiRegistry.add(factory);
}
void KisActionManager::registerOperation(KisOperation* operation)
{
d->operationRegistry.add(operation);
}
void KisActionManager::runOperation(const QString& id)
{
KisOperationConfigurationSP config = new KisOperationConfiguration(id);
KisOperationUIFactory* uiFactory = d->uiRegistry.get(id);
if (uiFactory) {
bool gotConfig = uiFactory->fetchConfiguration(d->viewManager, config);
if (!gotConfig) {
return;
}
}
runOperationFromConfiguration(config);
}
void KisActionManager::runOperationFromConfiguration(KisOperationConfigurationSP config)
{
KisOperation* operation = d->operationRegistry.get(config->id());
Q_ASSERT(operation);
operation->runFromXML(d->viewManager, *config);
}
void KisActionManager::dumpActionFlags()
{
QFile data("actions.txt");
if (data.open(QFile::WriteOnly | QFile::Truncate)) {
QTextStream out(&data);
out.setCodec("UTF-8");
Q_FOREACH (KisAction* action, d->actions) {
KisAction::ActivationFlags flags = action->activationFlags();
out << "-------- " << action->text() << " --------\n";
out << "Action will activate on: \n";
if (flags & KisAction::ACTIVE_IMAGE) {
out << " Active image\n";
}
if (flags & KisAction::MULTIPLE_IMAGES) {
out << " More than one image open\n";
}
if (flags & KisAction::CURRENT_IMAGE_MODIFIED) {
out << " Active image modified\n";
}
if (flags & KisAction::ACTIVE_DEVICE) {
out << " Active device\n";
}
if (flags & KisAction::ACTIVE_LAYER) {
out << " Active layer\n";
}
if (flags & KisAction::ACTIVE_TRANSPARENCY_MASK) {
out << " Active transparency mask\n";
}
if (flags & KisAction::ACTIVE_NODE) {
out << " Active node\n";
}
if (flags & KisAction::ACTIVE_SHAPE_LAYER) {
out << " Active shape layer\n";
}
if (flags & KisAction::PIXELS_SELECTED) {
out << " Pixels selected\n";
}
if (flags & KisAction::SHAPES_SELECTED) {
out << " Shapes selected\n";
}
if (flags & KisAction::ANY_SELECTION_WITH_PIXELS) {
out << " Any selection with pixels\n";
}
if (flags & KisAction::PIXELS_IN_CLIPBOARD) {
out << " Pixels in clipboard\n";
}
if (flags & KisAction::SHAPES_IN_CLIPBOARD) {
out << " Shape in clipboard\n";
}
if (flags & KisAction::IMAGE_HAS_ANIMATION) {
out << " Image has animation\n";
}
out << "\n\n";
out << "Action will only activate if the following conditions are met: \n";
KisAction::ActivationConditions conditions = action->activationConditions();
if ((int)conditions == 0) {
out << " -\n";
}
if (conditions & KisAction::ACTIVE_NODE_EDITABLE) {
out << " Active Node editable\n";
}
if (conditions & KisAction::ACTIVE_NODE_EDITABLE_PAINT_DEVICE) {
out << " Active Node has editable paint device\n";
}
if (conditions & KisAction::SELECTION_EDITABLE) {
out << " Selection is editable\n";
}
+ if (conditions & KisAction::OPENGL_ENABLED) {
+ out << " OpenGL is enabled\n";
+ }
out << "\n\n";
}
}
}