3 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
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.
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.
29 #include <kpMainWindow.h>
30 #include <kpMainWindowPrivate.h>
36 #include <kapplication.h>
38 #include <kconfiggroup.h>
44 #include <kmessagebox.h>
45 #include <krecentfilesaction.h>
47 #include <kpAbstractImageSelection.h>
48 #include <kpCommandEnvironment.h>
49 #include <kpColorCells.h>
50 #include <kpColorToolBar.h>
51 #include <kpCommandHistory.h>
53 #include <kpDocument.h>
54 #include <kpDocumentEnvironment.h>
55 #include <kpSelectionDrag.h>
56 #include <kpThumbnail.h>
58 #include <kpToolToolBar.h>
59 #include <kpViewManager.h>
60 #include <kpViewScrollableContainer.h>
61 #include <kpWidgetMapper.h>
62 #include <kpZoomedThumbnailView.h>
63 #include <kpZoomedView.h>
65 #if DEBUG_KP_MAIN_WINDOW
66 #include <qdatetime.h>
70 kpMainWindow::kpMainWindow ()
71 : KXmlGuiWindow (0/*parent*/)
74 open (KUrl (), true/*create an empty doc*/);
76 d
->isFullyConstructed
= true;
79 kpMainWindow::kpMainWindow (const KUrl
&url
)
80 : KXmlGuiWindow (0/*parent*/)
83 open (url
, true/*create an empty doc with the same url if url !exist*/);
85 d
->isFullyConstructed
= true;
88 kpMainWindow::kpMainWindow (kpDocument
*newDoc
)
89 : KXmlGuiWindow (0/*parent*/)
94 d
->isFullyConstructed
= true;
98 // TODO: Move into appropriate kpMainWindow_*.cpp or another class
101 void kpMainWindow::readGeneralSettings ()
103 #if DEBUG_KP_MAIN_WINDOW
104 kDebug () << "\tkpMainWindow(" << objectName () << ")::readGeneralSettings()";
107 KConfigGroup
cfg (KGlobal::config (), kpSettingsGroupGeneral
);
109 d
->configFirstTime
= cfg
.readEntry (kpSettingFirstTime
, true);
110 d
->configShowGrid
= cfg
.readEntry (kpSettingShowGrid
, false);
111 d
->configShowPath
= cfg
.readEntry (kpSettingShowPath
, false);
112 d
->moreEffectsDialogLastEffect
= cfg
.readEntry (kpSettingMoreEffectsLastEffect
, 0);
113 d
->resizeScaleDialogLastKeepAspect
= cfg
.readEntry (kpSettingResizeScaleLastKeepAspect
, false);
115 if (cfg
.hasKey (kpSettingOpenImagesInSameWindow
))
117 d
->configOpenImagesInSameWindow
= cfg
.readEntry (kpSettingOpenImagesInSameWindow
, false);
121 d
->configOpenImagesInSameWindow
= false;
122 #if DEBUG_KP_MAIN_WINDOW
123 kDebug () << "\tconfigOpenImagesInSameWindow: first time"
124 << " - writing default: " << d
->configOpenImagesInSameWindow
127 // TODO: More hidden options have to write themselves out on startup,
128 // not on use, to be discoverable (e.g. printing centered on page).
129 cfg
.writeEntry (kpSettingOpenImagesInSameWindow
,
130 d
->configOpenImagesInSameWindow
);
134 d
->configPrintImageCenteredOnPage
= cfg
.readEntry (kpSettingPrintImageCenteredOnPage
, true);
137 #if DEBUG_KP_MAIN_WINDOW
138 kDebug () << "\t\tGeneral Settings: firstTime=" << d
->configFirstTime
139 << " showGrid=" << d
->configShowGrid
140 << " showPath=" << d
->configShowPath
141 << " moreEffectsDialogLastEffect=" << d
->moreEffectsDialogLastEffect
142 << " resizeScaleDialogLastKeepAspect=" << d
->resizeScaleDialogLastKeepAspect
143 << " openImagesInSameWindow=" << d
->configOpenImagesInSameWindow
144 << " printImageCenteredOnPage=" << d
->configPrintImageCenteredOnPage
;
149 void kpMainWindow::readThumbnailSettings ()
151 #if DEBUG_KP_MAIN_WINDOW
152 kDebug () << "\tkpMainWindow(" << objectName () << ")::readThumbnailSettings()";
155 KConfigGroup
cfg (KGlobal::config (), kpSettingsGroupThumbnail
);
157 d
->configThumbnailShown
= cfg
.readEntry (kpSettingThumbnailShown
, false);
158 d
->configThumbnailGeometry
= cfg
.readEntry (kpSettingThumbnailGeometry
, QRect ());
159 d
->configZoomedThumbnail
= cfg
.readEntry (kpSettingThumbnailZoomed
, true);
160 d
->configThumbnailShowRectangle
= cfg
.readEntry (kpSettingThumbnailShowRectangle
, true);
162 #if DEBUG_KP_MAIN_WINDOW
163 kDebug () << "\t\tThumbnail Settings: shown=" << d
->configThumbnailShown
164 << " geometry=" << d
->configThumbnailGeometry
165 << " zoomed=" << d
->configZoomedThumbnail
166 << " showRectangle=" << d
->configThumbnailShowRectangle
171 // private [override KXmlGuiWindow]
172 void kpMainWindow::createGUI ()
174 KXmlGuiWindow::createGUI ();
176 // HACK: Until we have a proper kpToolToolBar where tool actions are
177 // plugged into it properly, Qt4 will not recognise our actions'
180 // In kolourpaintui.rc, we get around this by plugging them into
181 // a fake menu. Here, we hide that fake menu.
182 const QList
<KMenu
*> menuToHide
= findChildren
<KMenu
*>("toolToolBarHiddenMenu");
183 // should only contain one but...
184 foreach (KMenu
*menu
, menuToHide
)
186 menu
->menuAction()->setVisible(false);
191 void kpMainWindow::init ()
193 #if DEBUG_KP_MAIN_WINDOW
194 kDebug () << "kpMainWindow(" << objectName () << ")::init()";
195 QTime totalTime
; totalTime
.start ();
196 QTime time
; time
.start ();
199 d
= new kpMainWindowPrivate
;
202 // Set fields that must be set early on.
204 // For all other fields that don't need to be set as urgently, please
205 // set them in their respective kpMainWindow_*.cpp.
208 d
->isFullyConstructed
= false;
213 d
->thumbnailView
= 0;
218 d
->commandHistory
= 0;
219 d
->statusBarCreated
= false;
220 d
->settingImageSelectionTransparency
= 0;
221 d
->settingTextStyle
= 0;
223 d
->docResizeToBeCompleted
= false;
225 d
->documentEnvironment
= 0;
226 d
->commandEnvironment
= 0;
227 d
->toolSelectionEnvironment
= 0;
228 d
->toolsActionGroup
= 0;
229 d
->transformDialogEnvironment
= 0;
233 // set mainwindow properties
236 setMinimumSize (320, 260);
237 setAcceptDrops (true);
238 #if DEBUG_KP_MAIN_WINDOW
239 kDebug () << "\tTIME: little init = " << time
.restart () << "msec";
247 // KConfig::readEntry() does not actually reread from disk, hence doesn't
248 // realize what other processes have done e.g. Settings / Show Path
249 KGlobal::config ()->reparseConfiguration ();
250 #if DEBUG_KP_MAIN_WINDOW
251 kDebug () << "\tTIME: reparseConfig = " << time
.restart () << "msec";
254 readGeneralSettings ();
255 #if DEBUG_KP_MAIN_WINDOW
256 kDebug () << "\tTIME: readGeneralSettings = " << time
.restart () << "msec";
259 readThumbnailSettings ();
260 #if DEBUG_KP_MAIN_WINDOW
261 kDebug () << "\tTIME: readThumbnailSettings = " << time
.restart () << "msec";
270 #if DEBUG_KP_MAIN_WINDOW
271 kDebug () << "\tTIME: setupActions = " << time
.restart () << "msec";
275 #if DEBUG_KP_MAIN_WINDOW
276 kDebug () << "\tTIME: createStatusBar = " << time
.restart () << "msec";
280 #if DEBUG_KP_MAIN_WINDOW
281 kDebug () << "\tTIME: createGUI = " << time
.restart () << "msec";
290 #if DEBUG_KP_MAIN_WINDOW
291 kDebug () << "\tTIME: createColorBox = " << time
.restart () << "msec";
295 #if DEBUG_KP_MAIN_WINDOW
296 kDebug () << "\tTIME: createToolBox = " << time
.restart () << "msec";
300 // Let the Tool Box take all the vertical space, since it can be quite
301 // tall with all its tool option widgets. This also avoids occasional
302 // bugs like the Tool Box overlapping the Color Tool Bar.
303 setCorner (Qt::BottomLeftCorner
, Qt::LeftDockWidgetArea
);
306 // HACK: We couldn't get toolbar orientations and undocking to work
307 // properly so we fix their positions for the time being.
309 // Must be called before setAutoSaveSettings() or there are
310 // massive redraw errors (don't know why).
311 addDockWidget (Qt::LeftDockWidgetArea
, d
->toolToolBar
, Qt::Vertical
);
312 d
->toolToolBar
->setFeatures (QDockWidget::NoDockWidgetFeatures
);
314 addDockWidget (Qt::BottomDockWidgetArea
, d
->colorToolBar
, Qt::Horizontal
);
315 d
->colorToolBar
->setFeatures (QDockWidget::NoDockWidgetFeatures
);
318 d
->scrollView
= new kpViewScrollableContainer (this);
319 d
->scrollView
->setObjectName ("scrollView");
320 connect (d
->scrollView
, SIGNAL (beganDocResize ()),
321 this, SLOT (slotBeganDocResize ()));
322 connect (d
->scrollView
, SIGNAL (continuedDocResize (const QSize
&)),
323 this, SLOT (slotContinuedDocResize (const QSize
&)));
324 connect (d
->scrollView
, SIGNAL (cancelledDocResize ()),
325 this, SLOT (slotCancelledDocResize ()));
326 connect (d
->scrollView
, SIGNAL (endedDocResize (const QSize
&)),
327 this, SLOT (slotEndedDocResize (const QSize
&)));
329 connect (d
->scrollView
, SIGNAL (statusMessageChanged (const QString
&)),
330 this, SLOT (slotDocResizeMessageChanged (const QString
&)));
332 connect (d
->scrollView
, SIGNAL (contentsMoving (int, int)),
333 this, SLOT (slotScrollViewAboutToScroll ()));
334 setCentralWidget (d
->scrollView
);
335 d
->scrollView
->show ();
336 #if DEBUG_KP_MAIN_WINDOW
337 kDebug () << "\tTIME: d->scrollView = " << time
.restart () << "msec";
342 // set initial pos/size of GUI
345 setAutoSaveSettings ();
347 // Put our non-XMLGUI toolbars in a sane place, the first time around
348 // (have to do this _after_ setAutoSaveSettings as that applies default
349 // (i.e. random) settings to the toolbars)
350 if (d
->configFirstTime
)
352 #if DEBUG_KP_MAIN_WINDOW
353 kDebug () << "\tfirstTime: positioning toolbars";
356 // Not needed due to above toolbar HACK.
358 addToolBar (Qt::LeftToolBarArea
, d
->toolToolBar
);
359 addToolBar (Qt::BottomToolBarArea
, d
->colorToolBar
);
362 KConfigGroup
cfg (KGlobal::config (), kpSettingsGroupGeneral
);
364 cfg
.writeEntry (kpSettingFirstTime
, d
->configFirstTime
= false);
369 #if DEBUG_KP_MAIN_WINDOW
370 kDebug () << "\tall done in " << totalTime
.elapsed () << "msec";
375 // private virtual [base KMainWindow]
376 void kpMainWindow::readProperties (const KConfigGroup
&configGroup
)
378 #if DEBUG_KP_MAIN_WINDOW
379 kDebug () << "kpMainWindow<" << this << ">::readProperties()";
382 // No document at all?
383 if (!configGroup
.hasKey (kpSessionSettingDocumentUrl
))
385 #if DEBUG_KP_MAIN_WINDOW
386 kDebug () << "\tno url - no document";
393 const KUrl url
= configGroup
.readEntry (kpSessionSettingDocumentUrl
,
395 #if DEBUG_KP_MAIN_WINDOW
396 kDebug () << "\turl=" << url
;
399 const QSize notFromURLDocSize
=
400 configGroup
.readEntry (kpSessionSettingNotFromUrlDocumentSize
,
404 if (notFromURLDocSize
.isEmpty ())
406 // If this fails, the empty document that kpMainWindow::kpMainWindow()
407 // created is left untouched.
408 openInternal (url
, defaultDocSize (),
409 false/*show error message if url !exist*/);
414 #if DEBUG_KP_MAIN_WINDOW
415 kDebug () << "\tnot from url; doc size=" << notFromURLDocSize
;
417 // Either we have an empty URL or we have a "kolourpaint doesnotexist.png"
418 // URL. Regarding the latter case, if a file now actually exists at that
419 // URL, we do open it - ignoring notFromURLDocSize - to avoid putting
420 // the user in a situation where he might accidentally overwrite an
422 openInternal (url
, notFromURLDocSize
,
423 true/*create an empty doc with the same url if url !exist*/);
429 // private virtual [base KMainWindow]
430 // WARNING: KMainWindow API Doc says "No user interaction is allowed
431 // in this function!"
432 void kpMainWindow::saveProperties (KConfigGroup
&configGroup
)
434 #if DEBUG_KP_MAIN_WINDOW
435 kDebug () << "kpMainWindow<" << this << ">::saveProperties()";
438 // No document at all?
441 #if DEBUG_KP_MAIN_WINDOW
442 kDebug () << "\tno url - no document";
448 // Save URL in all cases:
450 // a) d->document->isFromURL()
451 // b) !d->document->isFromURL() [save size in this case]
453 // ii) URL (from "kolourpaint doesnotexist.png")
455 const KUrl url
= d
->document
->url ();
456 #if DEBUG_KP_MAIN_WINDOW
457 kDebug () << "\turl=" << url
;
459 configGroup
.writeEntry (kpSessionSettingDocumentUrl
, url
.url ());
461 // Not from URL e.g. "kolourpaint doesnotexist.png"?
463 // Note that "kolourpaint doesexist.png" is considered to be from
464 // a URL even if it was deleted in the background (hence the
465 // "false" arg to isFromURL()). This is because the user expects
466 // it to be from a URL, so when we session restore, we pop up a
467 // "cannot find file" dialog, instead of silently creating a new,
469 if (!d
->document
->isFromURL (false/*don't bother checking exists*/))
471 // If we don't have a URL either:
473 // a) it was not modified - so we can use either width() or
474 // constructorWidth() (they'll be equal).
475 // b) the changes were discarded so we use the initial width,
476 // constructorWidth().
478 // Similarly for height() and constructorHeight().
479 const QSize
docSize (d
->document
->constructorWidth (),
480 d
->document
->constructorHeight ());
481 #if DEBUG_KP_MAIN_WINDOW
482 kDebug () << "\tnot from url; doc size=" << docSize
;
484 configGroup
.writeEntry (kpSessionSettingNotFromUrlDocumentSize
, docSize
);
488 // Local session save i.e. queryClose() was not called beforehand
489 // (see QApplication::saveState())?
491 if (d
->document
->isModified ())
493 // TODO: Implement by saving the current image to a persistent file.
494 // We do this instead of saving/mutating the backing image file
495 // as no one expects a file save on a session save without a
496 // "do you want to save" dialog first.
498 // I don't think any KDE application implements local session saving.
500 // --- The below code does not compile but shows you want to do ---
502 // Create unique name for the document in this main window.
503 const KUrl tempURL
= homeDir
+
504 "kolourpaint session " + sessionID
+
505 mainWindowPtrToString
+ ".png";
506 // TODO: Use lossless PNG saving options.
507 kpDocumentSaveOptions pngSaveOptions
;
509 if (kpDocument::savePixmapToFile (d
->document
->pixmapWithSelection (),
511 pngSaveOptions
, *d
->document
->metaInfo (),
512 false/*no overwrite prompt*/,
513 false/*no lossy prompt*/,
516 // readProperties() will still open kpSessionSettingDocumentUrl
517 // (as that's the expected URL) and will then add commands to:
519 // 1. Resize the document to the size of image at
520 // kpSessionSettingDocumentUnsavedContentsUrl, if the sizes
522 // 2. Paste the kpSessionSettingDocumentUnsavedContentsUrl image
523 // (setting the main window's selection mode to opaque beforehand).
525 // It will then delete the file at
526 // kpSessionSettingDocumentUnsavedContentsUrl.
527 configGroup
.writeEntry (kpSessionSettingDocumentUnsavedContentsUrl
,
532 // Not much we can do - we aren't allowed to throw up a dialog.
540 kpMainWindow::~kpMainWindow ()
542 d
->isFullyConstructed
= false;
544 // Get the kpTool to finish up. This makes sure that the kpTool destructor
545 // will not need to access any other class (that might be deleted before
546 // the destructor is called by the QObject child-deletion mechanism).
548 tool ()->endInternal ();
550 // Delete document & views.
551 // Note: This will disconnects signals from the current kpTool, so kpTool
552 // must not be destructed yet.
555 delete d
->commandHistory
; d
->commandHistory
= 0;
556 delete d
->scrollView
; d
->scrollView
= 0;
563 kpDocument
*kpMainWindow::document () const
569 kpDocumentEnvironment
*kpMainWindow::documentEnvironment ()
571 if (!d
->documentEnvironment
)
572 d
->documentEnvironment
= new kpDocumentEnvironment (this);
574 return d
->documentEnvironment
;
578 kpViewManager
*kpMainWindow::viewManager () const
580 return d
->viewManager
;
584 kpColorToolBar
*kpMainWindow::colorToolBar () const
586 return d
->colorToolBar
;
590 kpColorCells
*kpMainWindow::colorCells () const
592 return d
->colorToolBar
? d
->colorToolBar
->colorCells () : 0;
596 kpToolToolBar
*kpMainWindow::toolToolBar () const
598 return d
->toolToolBar
;
602 kpCommandHistory
*kpMainWindow::commandHistory () const
604 return d
->commandHistory
;
607 kpCommandEnvironment
*kpMainWindow::commandEnvironment ()
609 if (!d
->commandEnvironment
)
610 d
->commandEnvironment
= new kpCommandEnvironment (this);
612 return d
->commandEnvironment
;
617 void kpMainWindow::setupActions ()
619 setupFileMenuActions ();
620 setupEditMenuActions ();
621 setupViewMenuActions ();
622 setupImageMenuActions ();
623 setupColorsMenuActions ();
624 setupSettingsMenuActions ();
625 setupHelpMenuActions ();
627 setupTextToolBarActions ();
632 void kpMainWindow::enableDocumentActions (bool enable
)
634 enableFileMenuDocumentActions (enable
);
635 enableEditMenuDocumentActions (enable
);
636 enableViewMenuDocumentActions (enable
);
637 enableImageMenuDocumentActions (enable
);
638 enableColorsMenuDocumentActions (enable
);
639 enableSettingsMenuDocumentActions (enable
);
640 enableHelpMenuDocumentActions (enable
);
645 void kpMainWindow::setDocument (kpDocument
*newDoc
)
647 #if DEBUG_KP_MAIN_WINDOW
648 kDebug () << "kpMainWindow::setDocument (" << newDoc
<< ")";
651 // is it a close operation?
654 #if DEBUG_KP_MAIN_WINDOW
655 kDebug () << "\tdisabling actions";
658 // sync with the bit marked "sync" below
660 // TODO: Never disable the Color Box because the user should be
661 // able to manipulate the colors, even without a currently
664 // We just have to make sure that signals from the Color
665 // Box aren't fired and received unexpectedly when there's
667 Q_ASSERT (d
->colorToolBar
);
668 d
->colorToolBar
->setEnabled (false);
670 enableTextToolBarActions (false);
673 // Always disable the tools.
674 // If we decide to open a new document/mainView we want
675 // kpTool::begin() to be called again e.g. in case it sets the cursor.
676 // kpViewManager won't do this because we nuke it to avoid stale state.
677 enableToolsDocumentActions (false);
681 enableDocumentActions (false);
684 #if DEBUG_KP_MAIN_WINDOW
685 kDebug () << "\tdestroying views";
688 delete d
->mainView
; d
->mainView
= 0;
689 slotDestroyThumbnail ();
691 #if DEBUG_KP_MAIN_WINDOW
692 kDebug () << "\tdestroying viewManager";
695 // viewManager will die and so will the selection
696 d
->actionCopy
->setEnabled (false);
697 d
->actionCut
->setEnabled (false);
698 d
->actionDelete
->setEnabled (false);
699 d
->actionDeselect
->setEnabled (false);
700 d
->actionCopyToFile
->setEnabled (false);
702 delete d
->viewManager
; d
->viewManager
= 0;
704 #if DEBUG_KP_MAIN_WINDOW
705 kDebug () << "\tdestroying document";
706 kDebug () << "\t\td->document=" << d
->document
;
708 // destroy current document
710 d
->document
= newDoc
;
713 if (!d
->lastCopyToURL
.isEmpty ())
714 d
->lastCopyToURL
.setFileName (QString());
715 d
->copyToFirstTime
= true;
717 if (!d
->lastExportURL
.isEmpty ())
718 d
->lastExportURL
.setFileName (QString());
719 d
->exportFirstTime
= true;
722 // not a close operation?
725 #if DEBUG_KP_MAIN_WINDOW
726 kDebug () << "\treparenting doc that may have been created into a"
727 << " different mainWindiow" << endl
;
729 d
->document
->setEnviron (documentEnvironment ());
731 #if DEBUG_KP_MAIN_WINDOW
732 kDebug () <<"\tcreating viewManager";
734 d
->viewManager
= new kpViewManager (this);
736 #if DEBUG_KP_MAIN_WINDOW
737 kDebug () << "\tcreating views";
739 d
->mainView
= new kpZoomedView (d
->document
, d
->toolToolBar
, d
->viewManager
,
742 d
->scrollView
->viewport ());
743 d
->mainView
->setObjectName ("mainView");
745 d
->scrollView
->addChild (d
->mainView
);
746 d
->viewManager
->registerView (d
->mainView
);
747 d
->mainView
->show ();
749 #if DEBUG_KP_MAIN_WINDOW
750 kDebug () << "\thooking up document signals";
753 // Copy/Cut/Deselect/Delete
754 connect (d
->document
, SIGNAL (selectionEnabled (bool)),
755 d
->actionCut
, SLOT (setEnabled (bool)));
756 connect (d
->document
, SIGNAL (selectionEnabled (bool)),
757 d
->actionCopy
, SLOT (setEnabled (bool)));
758 connect (d
->document
, SIGNAL (selectionEnabled (bool)),
759 d
->actionDelete
, SLOT (setEnabled (bool)));
760 connect (d
->document
, SIGNAL (selectionEnabled (bool)),
761 d
->actionDeselect
, SLOT (setEnabled (bool)));
762 connect (d
->document
, SIGNAL (selectionEnabled (bool)),
763 d
->actionCopyToFile
, SLOT (setEnabled (bool)));
765 // this code won't actually enable any actions at this stage
766 // (fresh document) but better safe than sorry
767 d
->actionCopy
->setEnabled (d
->document
->selection ());
768 d
->actionCut
->setEnabled (d
->document
->selection ());
769 d
->actionDeselect
->setEnabled (d
->document
->selection ());
770 d
->actionDelete
->setEnabled (d
->document
->selection ());
771 d
->actionCopyToFile
->setEnabled (d
->document
->selection ());
773 connect (d
->document
, SIGNAL (selectionEnabled (bool)),
774 this, SLOT (slotImageMenuUpdateDueToSelection ()));
775 connect (d
->document
, SIGNAL (selectionIsTextChanged (bool)),
776 this, SLOT (slotImageMenuUpdateDueToSelection ()));
779 connect (d
->document
, SIGNAL (documentOpened ()),
780 this, SLOT (recalculateStatusBar ()));
782 connect (d
->document
, SIGNAL (sizeChanged (const QSize
&)),
783 this, SLOT (setStatusBarDocSize (const QSize
&)));
785 // Caption (url, modified)
786 connect (d
->document
, SIGNAL (documentModified ()),
787 this, SLOT (slotUpdateCaption ()));
788 connect (d
->document
, SIGNAL (documentOpened ()),
789 this, SLOT (slotUpdateCaption ()));
790 connect (d
->document
, SIGNAL (documentSaved ()),
791 this, SLOT (slotUpdateCaption ()));
793 // File/Reload action only available with non-empty URL
794 connect (d
->document
, SIGNAL (documentSaved ()),
795 this, SLOT (slotEnableReload ()));
797 connect (d
->document
, SIGNAL (documentSaved ()),
798 this, SLOT (slotEnableSettingsShowPath ()));
801 Q_ASSERT (d
->commandHistory
);
802 connect (d
->commandHistory
, SIGNAL (documentRestored ()),
803 this, SLOT (slotDocumentRestored ())); // caption "!modified"
804 connect (d
->document
, SIGNAL (documentSaved ()),
805 d
->commandHistory
, SLOT (documentSaved ()));
807 // Sync document -> views
808 connect (d
->document
, SIGNAL (contentsChanged (const QRect
&)),
809 d
->viewManager
, SLOT (updateViews (const QRect
&)));
810 connect (d
->document
, SIGNAL (sizeChanged (int, int)),
811 d
->viewManager
, SLOT (adjustViewsToEnvironment ()));
813 #if DEBUG_KP_MAIN_WINDOW
814 kDebug () << "\tenabling actions";
817 // sync with the bit marked "sync" above
819 Q_ASSERT (d
->colorToolBar
);
820 d
->colorToolBar
->setEnabled (true);
823 // Hide the text toolbar - it will be shown by kpToolText::begin()
824 enableTextToolBarActions (false);
826 enableToolsDocumentActions (true);
828 enableDocumentActions (true);
830 // TODO: The thumbnail auto zoom doesn't work because it thinks its
831 // width == 1 when !this->isShown(). So for consistency,
832 // never create the thumbnail.
834 if (d
->configThumbnailShown
)
838 #if DEBUG_KP_MAIN_WINDOW
839 kDebug () << "\tcreating thumbnail immediately";
841 slotCreateThumbnail ();
843 // this' geometry is weird ATM
846 #if DEBUG_KP_MAIN_WINDOW
847 kDebug () << "\tcreating thumbnail LATER";
849 QTimer::singleShot (0, this, SLOT (slotCreateThumbnail ()));
855 #if DEBUG_KP_MAIN_WINDOW
856 kDebug () << "\tupdating mainWindow elements";
859 slotImageMenuUpdateDueToSelection ();
860 recalculateStatusBar ();
861 slotUpdateCaption (); // Untitled to start with
863 slotEnableSettingsShowPath ();
865 if (d
->commandHistory
)
866 d
->commandHistory
->clear ();
868 #if DEBUG_KP_MAIN_WINDOW
869 kDebug () << "\tdocument and views ready to go!";
874 // private virtual [base QWidget]
875 void kpMainWindow::dragEnterEvent (QDragEnterEvent
*e
)
877 // It's faster to test for QMimeData::hasText() first due to the
878 // lazy evaluation of the '||' operator.
879 e
->setAccepted (e
->mimeData ()->hasText () ||
880 KUrl::List::canDecode (e
->mimeData ()) ||
881 kpSelectionDrag::canDecode (e
->mimeData ()));
884 // private virtual [base QWidget]
885 void kpMainWindow::dropEvent (QDropEvent
*e
)
887 #if DEBUG_KP_MAIN_WINDOW
888 kDebug () << "kpMainWindow::dropEvent" << e
->pos ();
893 kpAbstractImageSelection
*sel
= kpSelectionDrag::decode (e
->mimeData (),
894 pasteWarnAboutLossInfo ());
897 // TODO: How do you actually drop a selection or ordinary images on
898 // the clipboard)? Will this code path _ever_ execute?
899 sel
->setTransparency (imageSelectionTransparency ());
900 // TODO: drop at point like with QTextDrag below?
904 else if (!(urls
= KUrl::List::fromMimeData (e
->mimeData ())).isEmpty ())
906 // LOTODO: kpSetOverrideCursorSaver cursorSaver (Qt::waitCursor);
908 // However, you would need to prefix all possible error/warning
909 // dialogs that might be called, with Qt::arrowCursor e.g. in
910 // kpDocument, kpPixmapFX::convertToPixmapAsLosslessAsPossible()
911 // and probably a lot more places.
912 foreach (const KUrl
&u
, urls
)
915 else if (e
->mimeData ()->hasText ())
917 const QString text
= e
->mimeData ()->text ();
919 QPoint selTopLeft
= KP_INVALID_POINT
;
920 const QPoint globalPos
= QWidget::mapToGlobal (e
->pos ());
921 #if DEBUG_KP_MAIN_WINDOW
922 kDebug () << "\tpos toGlobal=" << globalPos
;
929 view
= d
->viewManager
->viewUnderCursor ();
930 #if DEBUG_KP_MAIN_WINDOW
931 kDebug () << "\t\tviewUnderCursor=" << view
;
935 // HACK: see kpViewManager::setViewUnderCursor() to see why
937 #if DEBUG_KP_MAIN_WINDOW
938 kDebug () << "\t\tattempting to discover view";
940 if (d
->mainView
&& d
->scrollView
)
942 kDebug () << "\t\t\tmainView->globalRect="
943 << kpWidgetMapper::toGlobal (d
->mainView
, d
->mainView
->rect ())
944 << " scrollView->globalRect="
945 << kpWidgetMapper::toGlobal (d
->scrollView
,
947 d
->scrollView
->visibleWidth (),
948 d
->scrollView
->visibleHeight ()))
952 if (d
->thumbnailView
&&
953 kpWidgetMapper::toGlobal (d
->thumbnailView
, d
->thumbnailView
->rect ())
954 .contains (globalPos
))
956 // TODO: Code will never get executed.
957 // Thumbnail doesn't accept drops.
958 view
= d
->thumbnailView
;
960 else if (d
->mainView
&&
961 kpWidgetMapper::toGlobal (d
->mainView
, d
->mainView
->rect ())
962 .contains (globalPos
) &&
964 kpWidgetMapper::toGlobal (d
->scrollView
,
966 d
->scrollView
->visibleWidth (),
967 d
->scrollView
->visibleHeight ()))
968 .contains (globalPos
))
977 const QPoint viewPos
= view
->mapFromGlobal (globalPos
);
978 const QPoint docPoint
= view
->transformViewToDoc (viewPos
);
980 // viewUnderCursor() is hacky and can return a view when we aren't
981 // over one thanks to drags.
982 if (d
->document
&& d
->document
->rect ().contains (docPoint
))
984 selTopLeft
= docPoint
;
986 // TODO: In terms of doc pixels, would be inconsistent behaviour
987 // based on zoomLevel of view.
988 // selTopLeft -= QPoint (-view->selectionResizeHandleAtomicSize (),
989 // -view->selectionResizeHandleAtomicSize ());
993 pasteText (text
, true/*force new text selection*/, selTopLeft
);
999 void kpMainWindow::slotScrollViewAboutToScroll ()
1001 #if DEBUG_KP_MAIN_WINDOW && 1
1002 kDebug () << "kpMainWindow::slotScrollViewAboutToScroll() tool="
1003 << tool () << "viewManager=" << viewManager ();
1006 kDebug () << "\tfastUpdates=" << viewManager ()->fastUpdates ()
1007 << " queueUpdates=" << viewManager ()->queueUpdates ();
1011 // We're getting a late signal from the scrollview (thanks to
1012 // a timer inside the Q3ScrollView). By now, setDocument() has
1013 // already killed the document(), tool() and viewManager().
1017 QTimer::singleShot (0, this, SLOT (slotScrollViewAfterScroll ()));
1021 void kpMainWindow::slotScrollViewAfterScroll ()
1023 #if DEBUG_KP_MAIN_WINDOW && 1
1024 kDebug () << "kpMainWindow::slotScrollViewAfterScroll() tool="
1028 // OPT: Why can't this be moved into kpViewScrollableContainer::slotDragScroll(),
1029 // grouping all drag-scroll-related repaints, which would potentially avoid
1030 // double repainting?
1033 #if DEBUG_KP_MAIN_WINDOW && 1
1034 kDebug () << "calling somethingBelowTheCursorChanged()";
1036 tool ()->somethingBelowTheCursorChanged ();
1039 #if DEBUG_KP_MAIN_WINDOW && 1
1040 kDebug () << "DONE";
1045 // private virtual [base QWidget]
1046 void kpMainWindow::moveEvent (QMoveEvent
* /*e*/)
1050 // Disabled because it lags too far behind the mainWindow
1051 // d->thumbnail->move (d->thumbnail->pos () + (e->pos () - e->oldPos ()));
1053 notifyThumbnailGeometryChanged ();
1059 void kpMainWindow::slotUpdateCaption ()
1063 setCaption (d
->configShowPath
? d
->document
->prettyUrl ()
1064 : d
->document
->prettyFilename (),
1065 d
->document
->isModified ());
1069 setCaption (QString::null
, false); //krazy:exclude=nullstrassign for old broken gcc
1074 void kpMainWindow::slotDocumentRestored ()
1077 d
->document
->setModified (false);
1078 slotUpdateCaption ();
1082 #include <kpMainWindow.moc>