1 
2 /*
3    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
4    All rights reserved.
5 
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9 
10    1. Redistributions of source code must retain the above copyright
11       notice, this list of conditions and the following disclaimer.
12    2. Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in the
14       documentation and/or other materials provided with the distribution.
15 
16    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 
29 #ifndef KP_MAIN_WINDOW_H
30 #define KP_MAIN_WINDOW_H
31 
32 
33 #include <QUrl>
34 
35 #include <kxmlguiwindow.h>
36 
37 #include "kpDefs.h"
38 #include "pixmapfx/kpPixmapFX.h"
39 #include "imagelib/kpImage.h"
40 
41 
42 class QAction;
43 class QActionGroup;
44 class QDragEnterEvent;
45 class QDropEvent;
46 class QMenu;
47 class QMoveEvent;
48 class QPoint;
49 class QRect;
50 class QSize;
51 
52 class KConfigGroup;
53 class KToolBar;
54 class QPrinter;
55 
56 class kpColor;
57 class kpColorCells;
58 class kpColorToolBar;
59 class kpCommand;
60 class kpCommandEnvironment;
61 class kpCommandHistory;
62 class kpDocument;
63 class kpDocumentEnvironment;
64 class kpDocumentMetaInfo;
65 class kpDocumentSaveOptions;
66 class kpViewManager;
67 class kpImageSelectionTransparency;
68 class kpTextStyle;
69 class kpThumbnail;
70 class kpTool;
71 class kpToolEnvironment;
72 class kpToolSelectionEnvironment;
73 class kpToolToolBar;
74 class kpTransformDialogEnvironment;
75 class kpAbstractSelection;
76 
77 class kpMainWindow : public KXmlGuiWindow
78 {
79 Q_OBJECT
80 
81 public:
82     // Opens a new window with a blank document.
83     kpMainWindow ();
84 
85     // Opens a new window with the document specified by <url>
86     // or creates a blank document if <url> could not be opened.
87     kpMainWindow (const QUrl &url);
88 
89     // Opens a new window with the document <newDoc>
90     // (<newDoc> can be 0 although this would result in a new
91     //  window without a document at all).
92     kpMainWindow (kpDocument *newDoc);
93 
94     void finalizeGUI(KXMLGUIClient *client) override;
95 
96 private:
97     void readGeneralSettings ();
98     void readThumbnailSettings ();
99 
100     void init ();
101 
102     // (only called for restoring a previous session e.g. starting KDE with
103     //  a previously saved session; it's not called on normal KolourPaint
104     //  startup)
105     void readProperties (const KConfigGroup &configGroup) override;
106     // (only called for saving the current session e.g. logging out of KDE
107     //  with the KolourPaint window open; it's not called on normal KolourPaint
108     //  exit)
109     void saveProperties (KConfigGroup &configGroup) override;
110 
111 public:
112     ~kpMainWindow () override;
113 
114 public:
115     kpDocument *document () const;
116     kpDocumentEnvironment *documentEnvironment ();
117     kpViewManager *viewManager () const;
118     kpColorToolBar *colorToolBar () const;
119     kpColorCells *colorCells () const;
120     kpToolToolBar *toolToolBar () const;
121     kpCommandHistory *commandHistory () const;
122     kpCommandEnvironment *commandEnvironment ();
123 
124 private:
125     void setupActions ();
126     void enableDocumentActions (bool enable = true);
127 
128     void setDocument (kpDocument *newDoc);
129 
130     void dragEnterEvent (QDragEnterEvent *e) override;
131     void dropEvent (QDropEvent *e) override;
132     void moveEvent (QMoveEvent *e) override;
133 
134 private slots:
135     void slotScrollViewAfterScroll ();
136     void slotUpdateCaption ();
137     void slotDocumentRestored ();
138 
139 
140 //
141 // Tools
142 //
143 
144 private:
145     kpToolSelectionEnvironment *toolSelectionEnvironment ();
146     kpToolEnvironment *toolEnvironment ();
147 
148     void setupToolActions ();
149     void createToolBox ();
150     void enableToolsDocumentActions (bool enable = true);
151 
152 private slots:
153     void updateToolOptionPrevNextActionsEnabled ();
154     void updateActionDrawOpaqueChecked ();
155 private:
156     void updateActionDrawOpaqueEnabled ();
157 
158 public:
159     QActionGroup *toolsActionGroup ();
160 
161     kpTool *tool () const;
162 
163     bool toolHasBegunShape () const;
164     bool toolIsASelectionTool (bool includingTextTool = true) const;
165     bool toolIsTextTool () const;
166 
167 private:
168     // Ends the current shape.  If there is no shape currently being drawn,
169     // it does nothing.
170     //
171     // In general, call this at the start of every kpMainWindow slot,
172     // directly invoked by the _user_ (by activating an action or via another
173     // way), so that:
174     //
175     // 1. The document contains the pixels of that shape:
176     //
177     //    Most tools have the shape, currently being drawn, layered above the
178     //    document as a kpTempImage.  In other words, the document does not
179     //    yet contain the pixels of that shape.  By ending the shape, the layer
180     //    is pushed down onto the document so that it now contains those
181     //    pixels.  Your slot can now safely read the document as it's now
182     //    consistent with what's on the screen.
183     //
184     //    For example, consider the case where a line is being dragged out and
185     //    CTRL+I is pressed to invert the image, while the mouse is still held
186     //    down.  The CTRL+I invert code (kpMainWindow::slotInvertColors()) must
187     //    push the line kpTempImage onto the document before the invert can
188     //    meaningfully proceed (else the invert will see the state of the document
189     //    before the line was dragged out).
190     //
191     //    Note that selection layers are not pushed down by this method.
192     //    This is a feature, not a bug.  The user would be annoyed if e.g.
193     //    slotSave() happened to push down the selection.  Use
194     //    kpDocument::imageWithSelection() to get around this problem.  You
195     //    should still call toolEndShape() even if a selection is active
196     //    -- this ends selection "shapes", which are actually things like
197     //    selection moves or smearing operations, rather than the selections
198     //    themselves.
199     //
200     // AND/OR:
201     //
202     // 2. The current tool is no longer in a drawing state:
203     //
204     //    If your slot is going to bring up a new main window or modal dialog
205     //    or at least some widget that acquires mouse or keyboard focus, this
206     //    could confuse the tool if the tool is in the middle of a drawing
207     //    operation.
208     //
209     // Do not call this in slots not invoked by the user.  For instance,
210     // calling this method in response to an internal timer tick would be
211     // wrong.  The user's drawing operation would unexpectedly finish and
212     // this would bewilder and irritate the user.
213     //
214     // TODO: Help / KolourPaint Handbook does not call this.  I'm sure there
215     //       are a few other actions that don't call this but should.
216     void toolEndShape ();
217 
218 public:
219     kpImageSelectionTransparency imageSelectionTransparency () const;
220     // The drawing background color is set to <transparency>.transparentColor()
221     // if the <transparency> is in Transparent mode or if <forceColorChange>
222     // is true (not the default).  [x]
223     //
224     // If <transparency> is in Opaque mode and <forceColorChange> is false,
225     // the background color is not changed because:
226     //
227     //   1. It is ignored by the selection in Opaque mode anyway.
228     //   2. This avoids irritating the user with an unnecessary background
229     //      color change.
230     //
231     // The only case where you should set <forceColorChange> to true is in
232     // kpToolImageSelectionTransparencyCommand to ensure that the state
233     // is identical to when the command was constructed.
234     // Later: I don't think setting it to true is ever necessary since:
235     //
236     //          1. The background color only counts in Transparent mode.
237     //
238     //          2. Any kpToolImageSelectionTransparencyCommand that switches to
239     //             Transparent mode will automatically set the background
240     //             color due to the first part of [x] anyway.
241     //
242     // The other fields of <transparency> are copied into the main window
243     // as expected.
244     void setImageSelectionTransparency (const kpImageSelectionTransparency &transparency,
245                                    bool forceColorChange = false);
246     int settingImageSelectionTransparency () const;
247 
248 private slots:
249     void slotToolSelected (kpTool *tool);
250 
251 private:
252     void readLastTool ();
253     int toolNumber () const;
254     void saveLastTool ();
255 
256 private:
257     bool maybeDragScrollingMainView () const;
258 private slots:
259     bool slotDragScroll (const QPoint &docPoint,
260                          const QPoint &docLastPoint,
261                          int zoomLevel,
262                          bool *didSomething);
263     bool slotEndDragScroll ();
264 
265 private slots:
266     void slotBeganDocResize ();
267     void slotContinuedDocResize (const QSize &size);
268     void slotCancelledDocResize ();
269     void slotEndedDocResize (const QSize &size);
270 
271     void slotDocResizeMessageChanged (const QString &string);
272 
273 private slots:
274     void slotActionPrevToolOptionGroup1 ();
275     void slotActionNextToolOptionGroup1 ();
276     void slotActionPrevToolOptionGroup2 ();
277     void slotActionNextToolOptionGroup2 ();
278 
279     void slotActionDrawOpaqueToggled ();
280     void slotActionDrawColorSimilarity ();
281 
282 public slots:
283     void slotToolRectSelection();
284     void slotToolEllipticalSelection();
285     void slotToolFreeFormSelection();
286     void slotToolText();
287 
288 //
289 // File Menu
290 //
291 
292 private:
293     void setupFileMenuActions ();
294     void enableFileMenuDocumentActions (bool enable = true);
295 
296     void addRecentURL (const QUrl &url);
297 
298 private slots:
299     void slotNew ();
300 
301 private:
302     QSize defaultDocSize () const;
303     void saveDefaultDocSize (const QSize &size);
304 
305 private:
306     bool shouldOpen ();
307     void setDocumentChoosingWindow (kpDocument *doc);
308 
309 private:
310     kpDocument *openInternal (const QUrl &url,
311         const QSize &fallbackDocSize,
312         bool newDocSameNameIfNotExist);
313     // Same as above except that it:
314     //
315     // 1. Assumes a default fallback document size.
316     // 2. If the URL is successfully opened (with the special exception of
317     //    the "kolourpaint doesnotexist.png" case), it is bubbled up to the
318     //    top in the Recent Files Action.
319     //
320     // As a result of this behavior, this should only be called in response
321     // to a user open request e.g. File / Open or "kolourpaint doesexist.png".
322     // It should not be used for session restore - in that case, it does not
323     // make sense to bubble the Recent Files list.
324     bool open (const QUrl &url, bool newDocSameNameIfNotExist = false);
325 
326     QList<QUrl> askForOpenURLs(const QString &caption,
327                               bool allowMultipleURLs = true);
328 
329 private slots:
330     void slotOpen ();
331     void slotOpenRecent (const QUrl &url);
332     void slotRecentListCleared();
333 
334 #if HAVE_KSANE
335     void slotScan ();
336     void slotScanned (const QImage &image, int);
337 #endif // HAVE_KSANE
338 
339     void slotScreenshot();
340     void slotMakeScreenshot();
341 
342     void slotProperties ();
343 
344     bool save (bool localOnly = false);
345     bool slotSave ();
346 
347 private:
348     QUrl askForSaveURL (const QString &caption,
349                         const QString &startURL,
350                         const kpImage &imageToBeSaved,
351                         const kpDocumentSaveOptions &startSaveOptions,
352                         const kpDocumentMetaInfo &docMetaInfo,
353                         const QString &forcedSaveOptionsGroup,
354                         bool localOnly,
355                         kpDocumentSaveOptions *chosenSaveOptions,
356                         bool isSavingForFirstTime,
357                         bool *allowLossyPrompt);
358 
359 private slots:
360     bool saveAs (bool localOnly = false);
361     bool slotSaveAs ();
362 
363     bool slotExport ();
364 
365     void slotEnableReload ();
366     bool slotReload ();
367     void sendPreviewToPrinter(QPrinter *printer);
368 
369 private:
370     void sendDocumentNameToPrinter (QPrinter *printer);
371     void setPrinterPageOrientation(QPrinter *printer);
372     void sendImageToPrinter(QPrinter *printer, bool showPrinterSetupDialog);
373 
374 private slots:
375     void slotPrint ();
376     void slotPrintPreview ();
377 
378     void slotMail ();
379 
380     bool queryCloseDocument ();
381     bool queryClose () override;
382 
383     void slotClose ();
384     void slotQuit ();
385 
386 
387 //
388 // Edit Menu
389 //
390 
391 private:
392     void setupEditMenuActions ();
393     void enableEditMenuDocumentActions (bool enable = true);
394 
395 public:
396     QMenu *selectionToolRMBMenu ();
397 
398 private slots:
399     void slotCut ();
400     void slotCopy ();
401     void slotEnablePaste ();
402 private:
403     QRect calcUsefulPasteRect (int imageWidth, int imageHeight);
404     // (it is possible to paste a selection border i.e. a selection with no content)
405     void paste (const kpAbstractSelection &sel,
406                 bool forceTopLeft = false);
407 public:
408     // (<forceNewTextSelection> is ignored if <text> is empty)
409     void pasteText (const QString &text,
410                     bool forceNewTextSelection = false,
411                     const QPoint &newTextSelectionTopLeft = KP_INVALID_POINT);
412     void pasteTextAt (const QString &text, const QPoint &point,
413                       // Allow tiny adjustment of <point> so that mouse
414                       // pointer is not exactly on top of the topLeft of
415                       // any new text selection (so that it doesn't look
416                       // weird by being on top of a resize handle just after
417                       // a paste).
418                       bool allowNewTextSelectionPointShift = false);
419 public slots:
420     void slotPaste ();
421 private slots:
422     void slotPasteInNewWindow ();
423 public slots:
424     void slotDelete ();
425 
426     void slotSelectAll ();
427 private:
428     void addDeselectFirstCommand (kpCommand *cmd);
429 public slots:
430     void slotDeselect ();
431 private slots:
432     void slotCopyToFile ();
433     void slotPasteFromFile ();
434 
435 
436 //
437 // View Menu
438 //
439 
440 private:
441     void setupViewMenuActions ();
442 
443     bool viewMenuDocumentActionsEnabled () const;
444     void enableViewMenuDocumentActions (bool enable = true);
445     void actionShowGridUpdate ();
446     void updateMainViewGrid ();
447     QRect mapToGlobal (const QRect &rect) const;
448     QRect mapFromGlobal (const QRect &rect) const;
449 
450 private slots:
451     void slotShowGridToggled ();
452 
453 
454 //
455 // View Menu - Zoom
456 //
457 
458 private:
459     void setupViewMenuZoomActions ();
460     void enableViewMenuZoomDocumentActions (bool enable);
461 
462     void sendZoomListToActionZoom ();
463 
464     void zoomToPre (int zoomLevel);
465     void zoomToPost ();
466 
467 public:
468     void zoomTo (int zoomLevel, bool centerUnderCursor = false);
469     void zoomToRect (const QRect &normalizedDocRect,
470         bool accountForGrips,
471         bool careAboutWidth, bool careAboutHeight);
472 
473 public slots:
474     void slotActualSize ();
475     void slotFitToPage ();
476     void slotFitToWidth ();
477     void slotFitToHeight ();
478 
479 public:
480     void zoomIn (bool centerUnderCursor = false);
481     void zoomOut (bool centerUnderCursor = false);
482 
483 public slots:
484     void slotZoomIn ();
485     void slotZoomOut ();
486 
487 private:
488     void zoomAccordingToZoomAction (bool centerUnderCursor = false);
489 
490 private slots:
491     void slotZoom ();
492 
493 
494 //
495 // View Menu - Thumbnail
496 //
497 
498 private:
499     void setupViewMenuThumbnailActions ();
500     void enableViewMenuThumbnailDocumentActions (bool enable);
501 
502 private slots:
503     void slotDestroyThumbnail ();
504     void slotDestroyThumbnailInitatedByUser ();
505     void slotCreateThumbnail ();
506 
507 public:
508     void notifyThumbnailGeometryChanged ();
509 
510 private slots:
511     void slotSaveThumbnailGeometry ();
512     void slotShowThumbnailToggled ();
513     void updateThumbnailZoomed ();
514     void slotZoomedThumbnailToggled ();
515     void slotThumbnailShowRectangleToggled ();
516 
517 private:
518     void enableViewZoomedThumbnail (bool enable = true);
519     void enableViewShowThumbnailRectangle (bool enable = true);
520     void enableThumbnailOptionActions (bool enable = true);
521     void createThumbnailView ();
522     void destroyThumbnailView ();
523     void updateThumbnail ();
524 
525 
526 //
527 // Image Menu
528 //
529 
530 private:
531     kpTransformDialogEnvironment *transformDialogEnvironment ();
532 
533     bool isSelectionActive () const;
534     bool isTextSelection () const;
535 
536     QString autoCropText () const;
537 
538     void setupImageMenuActions ();
539     void enableImageMenuDocumentActions (bool enable = true);
540 
541 private slots:
542     void slotImageMenuUpdateDueToSelection ();
543 
544 public:
545     kpColor backgroundColor (bool ofSelection = false) const;
546     void addImageOrSelectionCommand (kpCommand *cmd,
547                                      bool addSelCreateCmdIfSelAvail = true,
548                                      bool addSelContentCmdIfSelAvail = true);
549 
550 public slots:
551     void slotCrop ();
552 
553 private slots:
554     void slotResizeScale ();
555     void slotAutoCrop ();
556     void slotFlip ();
557     void slotMirror ();
558 
559     void slotRotate ();
560     void slotRotate270 ();
561     void slotRotate90 ();
562 
563     void slotSkew ();
564     void slotConvertToBlackAndWhite ();
565     void slotConvertToGrayscale ();
566     void slotInvertColors ();
567     void slotClear ();
568     void slotMakeConfidential();
569     void slotMoreEffects ();
570 
571 
572 //
573 // Colors Menu
574 //
575 
576 private:
577     void setupColorsMenuActions ();
578     void createColorBox ();
579     void enableColorsMenuDocumentActions (bool enable);
580 private slots:
581     void slotUpdateColorsDeleteRowActionEnabled ();
582 
583 private:
584     void deselectActionColorsKDE ();
585 
586     bool queryCloseColors ();
587 
588 private:
589     void openDefaultColors ();
590 private slots:
591     void slotColorsDefault ();
592 
593 private:
594     bool openKDEColors (const QString &name);
595 private slots:
596     void slotColorsKDE ();
597 
598 private:
599     bool openColors (const QUrl &url);
600 private slots:
601     void slotColorsOpen ();
602 
603     void slotColorsReload ();
604 
605     bool slotColorsSave ();
606     bool slotColorsSaveAs ();
607 
608     void slotColorsAppendRow ();
609     void slotColorsDeleteRow ();
610 
611 
612 //
613 // Settings Menu
614 //
615 
616 private:
617     void setupSettingsMenuActions ();
618     void enableSettingsMenuDocumentActions (bool enable = true);
619 
620 private slots:
621     void slotFullScreen ();
622 
623     void slotEnableSettingsShowPath ();
624     void slotShowPathToggled ();
625     void slotDrawAntiAliasedToggled(bool on);
626 
627     void slotKeyBindings ();
628 
629 //
630 // Status Bar
631 //
632 
633 private:
634     enum
635     {
636         StatusBarItemShapePoints,
637         StatusBarItemShapeSize,
638         StatusBarItemDocSize,
639         StatusBarItemDocDepth,
640         StatusBarItemZoom
641     };
642 
643     void addPermanentStatusBarItem (int id, int maxTextLen);
644     void createStatusBar ();
645 
646     void setStatusBarDocDepth (int depth = 0);
647 
648 private slots:
649     void setStatusBarMessage (const QString &message = QString());
650     void setStatusBarShapePoints (const QPoint &startPoint = KP_INVALID_POINT,
651                                   const QPoint &endPoint = KP_INVALID_POINT);
652     void setStatusBarShapeSize (const QSize &size = KP_INVALID_SIZE);
653     void setStatusBarDocSize (const QSize &size = KP_INVALID_SIZE);
654     void setStatusBarZoom (int zoom = 0);
655 
656     void recalculateStatusBarMessage ();
657     void recalculateStatusBarShape ();
658 
659     void recalculateStatusBar ();
660 
661 
662 //
663 // Text ToolBar
664 //
665 
666 private:
667     void setupTextToolBarActions ();
668     void readAndApplyTextSettings ();
669 
670 public:
671     void enableTextToolBarActions (bool enable = true);
672 
673 private slots:
674     void slotTextFontFamilyChanged ();
675     void slotTextFontSizeChanged ();
676     void slotTextBoldChanged ();
677     void slotTextItalicChanged ();
678     void slotTextUnderlineChanged ();
679     void slotTextStrikeThruChanged ();
680 
681 public:
682     KToolBar *textToolBar ();
683     bool isTextStyleBackgroundOpaque () const;
684     kpTextStyle textStyle () const;
685     void setTextStyle (const kpTextStyle &textStyle_);
686     int settingTextStyle () const;
687 
688 private:
689     struct kpMainWindowPrivate *d;
690 };
691 
692 #endif  // KP_MAIN_WINDOW_H
693