kpMainWindow.cpp 32.2 KB
Newer Older
1

2
/*
3
   Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
4
   All rights reserved.
5

6 7 8
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:
9

10 11 12 13 14
   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
15

16 17 18 19 20 21
   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 23
   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 25
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 27
*/

Clarence Dang's avatar
Clarence Dang committed
28

29 30
#include <kpMainWindow.h>
#include <kpMainWindowPrivate.h>
Clarence Dang's avatar
Clarence Dang committed
31

32
#include <qevent.h>
Christoph Feck's avatar
Christoph Feck committed
33
#include <qmenu.h>
Clarence Dang's avatar
Clarence Dang committed
34
#include <qtimer.h>
35 36

#include <kconfig.h>
37
#include <kconfiggroup.h>
38
#include <kdebug.h>
39
#include <kglobal.h>
40
#include <klocale.h>
Laurent Montel's avatar
Laurent Montel committed
41
#include <krecentfilesaction.h>
42 43 44

#include <kpAbstractImageSelection.h>
#include <kpCommandEnvironment.h>
45
#include <kpColorCells.h>
46 47 48 49
#include <kpColorToolBar.h>
#include <kpCommandHistory.h>
#include <kpDefs.h>
#include <kpDocument.h>
50
#include <kpDocumentEnvironment.h>
51 52 53 54 55 56 57 58 59
#include <kpSelectionDrag.h>
#include <kpThumbnail.h>
#include <kpTool.h>
#include <kpToolToolBar.h>
#include <kpViewManager.h>
#include <kpViewScrollableContainer.h>
#include <kpWidgetMapper.h>
#include <kpZoomedThumbnailView.h>
#include <kpZoomedView.h>
60

Clarence Dang's avatar
Clarence Dang committed
61 62 63 64
#if DEBUG_KP_MAIN_WINDOW
    #include <qdatetime.h>
#endif

Clarence Dang's avatar
 
Clarence Dang committed
65

66 67
//---------------------------------------------------------------------

Clarence Dang's avatar
Clarence Dang committed
68
kpMainWindow::kpMainWindow ()
69
    : KXmlGuiWindow (0/*parent*/)
Clarence Dang's avatar
Clarence Dang committed
70
{
Clarence Dang's avatar
Clarence Dang committed
71
    init ();
Christoph Feck's avatar
Christoph Feck committed
72
    open (QUrl (), true/*create an empty doc*/);
Clarence Dang's avatar
 
Clarence Dang committed
73

74
    d->isFullyConstructed = true;
Clarence Dang's avatar
Clarence Dang committed
75
}
76

77 78
//---------------------------------------------------------------------

Christoph Feck's avatar
Christoph Feck committed
79
kpMainWindow::kpMainWindow (const QUrl &url)
80
    : KXmlGuiWindow (0/*parent*/)
Clarence Dang's avatar
Clarence Dang committed
81
{
Clarence Dang's avatar
Clarence Dang committed
82
    init ();
Clarence Dang's avatar
 
Clarence Dang committed
83
    open (url, true/*create an empty doc with the same url if url !exist*/);
Clarence Dang's avatar
Clarence Dang committed
84

85
    d->isFullyConstructed = true;
Clarence Dang's avatar
Clarence Dang committed
86
}
87

88 89
//---------------------------------------------------------------------

Clarence Dang's avatar
Clarence Dang committed
90
kpMainWindow::kpMainWindow (kpDocument *newDoc)
91
    : KXmlGuiWindow (0/*parent*/)
Clarence Dang's avatar
Clarence Dang committed
92
{
Clarence Dang's avatar
Clarence Dang committed
93
    init ();
Clarence Dang's avatar
Clarence Dang committed
94
    setDocument (newDoc);
Clarence Dang's avatar
 
Clarence Dang committed
95

96
    d->isFullyConstructed = true;
Clarence Dang's avatar
Clarence Dang committed
97 98
}

99 100
//---------------------------------------------------------------------

Clarence Dang's avatar
Clarence Dang committed
101

102
// TODO: Move into appropriate kpMainWindow_*.cpp or another class
Clarence Dang's avatar
Clarence Dang committed
103 104 105 106 107

// private
void kpMainWindow::readGeneralSettings ()
{
#if DEBUG_KP_MAIN_WINDOW
108
    kDebug () << "\tkpMainWindow(" << objectName () << ")::readGeneralSettings()";
Clarence Dang's avatar
Clarence Dang committed
109 110
#endif

111
    KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral);
Clarence Dang's avatar
Clarence Dang committed
112

113 114 115 116
    d->configFirstTime = cfg.readEntry (kpSettingFirstTime, true);
    d->configShowGrid = cfg.readEntry (kpSettingShowGrid, false);
    d->configShowPath = cfg.readEntry (kpSettingShowPath, false);
    d->moreEffectsDialogLastEffect = cfg.readEntry (kpSettingMoreEffectsLastEffect, 0);
117

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
    if (cfg.hasKey (kpSettingOpenImagesInSameWindow))
    {
        d->configOpenImagesInSameWindow = cfg.readEntry (kpSettingOpenImagesInSameWindow, false);
    }
    else
    {
        d->configOpenImagesInSameWindow = false;
#if DEBUG_KP_MAIN_WINDOW
        kDebug () << "\tconfigOpenImagesInSameWindow: first time"
                  << " - writing default: " << d->configOpenImagesInSameWindow
                  << endl;
#endif
        // TODO: More hidden options have to write themselves out on startup,
        //       not on use, to be discoverable (e.g. printing centered on page).
        cfg.writeEntry (kpSettingOpenImagesInSameWindow,
                        d->configOpenImagesInSameWindow);
        cfg.sync ();
    }

137 138
    d->configPrintImageCenteredOnPage = cfg.readEntry (kpSettingPrintImageCenteredOnPage, true);

Clarence Dang's avatar
Clarence Dang committed
139 140

#if DEBUG_KP_MAIN_WINDOW
141 142 143 144
    kDebug () << "\t\tGeneral Settings: firstTime=" << d->configFirstTime
               << " showGrid=" << d->configShowGrid
               << " showPath=" << d->configShowPath
               << " moreEffectsDialogLastEffect=" << d->moreEffectsDialogLastEffect
145
               << " openImagesInSameWindow=" << d->configOpenImagesInSameWindow
146
               << " printImageCenteredOnPage=" << d->configPrintImageCenteredOnPage;
Clarence Dang's avatar
Clarence Dang committed
147 148 149
#endif
}

150 151
//---------------------------------------------------------------------

Clarence Dang's avatar
Clarence Dang committed
152 153 154 155
// private
void kpMainWindow::readThumbnailSettings ()
{
#if DEBUG_KP_MAIN_WINDOW
156
    kDebug () << "\tkpMainWindow(" << objectName () << ")::readThumbnailSettings()";
Clarence Dang's avatar
Clarence Dang committed
157 158
#endif

159
    KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupThumbnail);
Clarence Dang's avatar
Clarence Dang committed
160

161 162 163 164
    d->configThumbnailShown = cfg.readEntry (kpSettingThumbnailShown, false);
    d->configThumbnailGeometry = cfg.readEntry (kpSettingThumbnailGeometry, QRect ());
    d->configZoomedThumbnail = cfg.readEntry (kpSettingThumbnailZoomed, true);
    d->configThumbnailShowRectangle = cfg.readEntry (kpSettingThumbnailShowRectangle, true);
Clarence Dang's avatar
Clarence Dang committed
165 166

#if DEBUG_KP_MAIN_WINDOW
167 168 169 170
    kDebug () << "\t\tThumbnail Settings: shown=" << d->configThumbnailShown
               << " geometry=" << d->configThumbnailGeometry
               << " zoomed=" << d->configZoomedThumbnail
               << " showRectangle=" << d->configThumbnailShowRectangle
Clarence Dang's avatar
Clarence Dang committed
171 172
               << endl;
#endif
Clarence Dang's avatar
Clarence Dang committed
173
}
174

175 176
//---------------------------------------------------------------------

177
void kpMainWindow::finalizeGUI(KXMLGUIClient *client)
178
{
179 180
  if ( client == this )
  {
Christoph Feck's avatar
Christoph Feck committed
181
    const QList<QMenu *> menuToHide = findChildren<QMenu *>("toolToolBarHiddenMenu");
182
    // should only contain one but...
Christoph Feck's avatar
Christoph Feck committed
183
    foreach (QMenu *menu, menuToHide)
184
    {
185
        menu->menuAction()->setVisible(false);
186
    }
187
  }
188 189
}

190 191
//---------------------------------------------------------------------

Clarence Dang's avatar
Clarence Dang committed
192
// private
Clarence Dang's avatar
Clarence Dang committed
193
void kpMainWindow::init ()
194
{
Clarence Dang's avatar
Clarence Dang committed
195
#if DEBUG_KP_MAIN_WINDOW
196
    kDebug () << "kpMainWindow(" << objectName () << ")::init()";
Clarence Dang's avatar
Clarence Dang committed
197 198 199
    QTime totalTime; totalTime.start ();
#endif

Clarence Dang's avatar
Clarence Dang committed
200 201
    d = new kpMainWindowPrivate;

Clarence Dang's avatar
Clarence Dang committed
202 203 204 205 206
    //
    // set mainwindow properties
    //

    setMinimumSize (320, 260);
207
    setAcceptDrops (true);
Clarence Dang's avatar
 
Clarence Dang committed
208

Clarence Dang's avatar
Clarence Dang committed
209
    //
Clarence Dang's avatar
Clarence Dang committed
210
    // read config
Clarence Dang's avatar
Clarence Dang committed
211 212
    //

Clarence Dang's avatar
Clarence Dang committed
213
    // KConfig::readEntry() does not actually reread from disk, hence doesn't
Thorsten Roeder's avatar
Thorsten Roeder committed
214
    // realize what other processes have done e.g. Settings / Show Path
215
    KSharedConfig::openConfig ()->reparseConfiguration ();
Clarence Dang's avatar
Clarence Dang committed
216 217 218

    readGeneralSettings ();
    readThumbnailSettings ();
Clarence Dang's avatar
 
Clarence Dang committed
219

Clarence Dang's avatar
Clarence Dang committed
220 221 222
    //
    // create GUI
    //
223
    setupActions ();
224
    createStatusBar ();
225
    createGUI ();
Clarence Dang's avatar
 
Clarence Dang committed
226

227
    createColorBox ();
228
    createToolBox ();
Clarence Dang's avatar
 
Clarence Dang committed
229

230 231 232 233

    // Let the Tool Box take all the vertical space, since it can be quite
    // tall with all its tool option widgets.  This also avoids occasional
    // bugs like the Tool Box overlapping the Color Tool Bar.
234 235
    setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
    setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
236

237 238
    // no tabbed docks; does not make sense with only 2 dock widgets
    setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks);
239

240
    addDockWidget(Qt::BottomDockWidgetArea, d->colorToolBar, Qt::Horizontal);
241

242
    d->scrollView = new kpViewScrollableContainer (this);
Laurent Montel's avatar
Laurent Montel committed
243
    d->scrollView->setObjectName ( QLatin1String("scrollView" ));
244
    connect (d->scrollView, SIGNAL (beganDocResize ()),
245
             this, SLOT (slotBeganDocResize ()));
246
    connect (d->scrollView, SIGNAL (continuedDocResize (const QSize &)),
247
             this, SLOT (slotContinuedDocResize (const QSize &)));
248
    connect (d->scrollView, SIGNAL (cancelledDocResize ()),
249
             this, SLOT (slotCancelledDocResize ()));
250
    connect (d->scrollView, SIGNAL (endedDocResize (const QSize &)),
251 252
             this, SLOT (slotEndedDocResize (const QSize &)));

253
    connect (d->scrollView, SIGNAL (statusMessageChanged (const QString &)),
254 255
             this, SLOT (slotDocResizeMessageChanged (const QString &)));

256 257
    connect (d->scrollView, SIGNAL(contentsMoved()),
             this, SLOT(slotScrollViewAfterScroll()));
258

259
    setCentralWidget (d->scrollView);
Clarence Dang's avatar
 
Clarence Dang committed
260

Clarence Dang's avatar
Clarence Dang committed
261 262 263
    //
    // set initial pos/size of GUI
    //
264

265
    setAutoSaveSettings ();
Clarence Dang's avatar
 
Clarence Dang committed
266

267 268 269
    // our non-XMLGUI tools-toolbar will get initially the toolButtonStyle as
    // all other toolbars, but we want to show only icons for the tools by default
    // (have to do this _after_ setAutoSaveSettings as that applies the default settings)
270
    if (d->configFirstTime)
271
    {
272
      d->toolToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
Clarence Dang's avatar
Clarence Dang committed
273

274
      KConfigGroup cfg(KSharedConfig::openConfig(), kpSettingsGroupGeneral);
Clarence Dang's avatar
Clarence Dang committed
275

276 277
      cfg.writeEntry(kpSettingFirstTime, d->configFirstTime = false);
      cfg.sync();
278
    }
Clarence Dang's avatar
Clarence Dang committed
279

280

Clarence Dang's avatar
Clarence Dang committed
281
#if DEBUG_KP_MAIN_WINDOW
282
    kDebug () << "\tall done in " << totalTime.elapsed () << "msec";
Clarence Dang's avatar
Clarence Dang committed
283
#endif
284 285
}

286
//---------------------------------------------------------------------
287 288 289 290 291

// private virtual [base KMainWindow]
void kpMainWindow::readProperties (const KConfigGroup &configGroup)
{
#if DEBUG_KP_MAIN_WINDOW
292
    kDebug () << "kpMainWindow<" << this << ">::readProperties()";
293 294 295 296 297 298
#endif

    // No document at all?
    if (!configGroup.hasKey (kpSessionSettingDocumentUrl))
    {
    #if DEBUG_KP_MAIN_WINDOW
299
        kDebug () << "\tno url - no document";
300 301 302 303 304 305
    #endif
        setDocument (0);
    }
    // Have a document.
    else
    {
Christoph Feck's avatar
Christoph Feck committed
306
        const QUrl url = configGroup.readEntry (kpSessionSettingDocumentUrl,
307 308
                                                QString ());
    #if DEBUG_KP_MAIN_WINDOW
309
        kDebug () << "\turl=" << url;
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    #endif

        const QSize notFromURLDocSize =
            configGroup.readEntry (kpSessionSettingNotFromUrlDocumentSize,
                                   QSize ());

        // Is from URL?
        if (notFromURLDocSize.isEmpty ())
        {
            // If this fails, the empty document that kpMainWindow::kpMainWindow()
            // created is left untouched.
            openInternal (url, defaultDocSize (),
                false/*show error message if url !exist*/);
        }
        // Not from URL?
        else
        {
        #if DEBUG_KP_MAIN_WINDOW
328
            kDebug () << "\tnot from url; doc size=" << notFromURLDocSize;
329 330 331 332 333 334 335 336 337 338 339 340 341
        #endif
            // Either we have an empty URL or we have a "kolourpaint doesnotexist.png"
            // URL.  Regarding the latter case, if a file now actually exists at that
            // URL, we do open it - ignoring notFromURLDocSize - to avoid putting
            // the user in a situation where he might accidentally overwrite an
            // existing file.
            openInternal (url, notFromURLDocSize,
                true/*create an empty doc with the same url if url !exist*/);
        }
    }

}

342 343
//---------------------------------------------------------------------

344 345 346 347 348 349
// private virtual [base KMainWindow]
// WARNING: KMainWindow API Doc says "No user interaction is allowed
//          in this function!"
void kpMainWindow::saveProperties (KConfigGroup &configGroup)
{
#if DEBUG_KP_MAIN_WINDOW
350
    kDebug () << "kpMainWindow<" << this << ">::saveProperties()";
351 352 353
#endif

    // No document at all?
354
    if (!d->document)
355 356
    {
    #if DEBUG_KP_MAIN_WINDOW
357
        kDebug () << "\tno url - no document";
358 359 360 361 362 363 364
    #endif
    }
    // Have a document.
    else
    {
        // Save URL in all cases:
        //
365 366
        //    a) d->document->isFromURL()
        //    b) !d->document->isFromURL() [save size in this case]
367 368 369
        //       i) No URL
        //       ii) URL (from "kolourpaint doesnotexist.png")

Christoph Feck's avatar
Christoph Feck committed
370
        const QUrl url = d->document->url ();
371
    #if DEBUG_KP_MAIN_WINDOW
372
        kDebug () << "\turl=" << url;
373 374 375 376 377 378 379 380 381 382 383
    #endif
        configGroup.writeEntry (kpSessionSettingDocumentUrl, url.url ());

        // Not from URL e.g. "kolourpaint doesnotexist.png"?
        //
        // Note that "kolourpaint doesexist.png" is considered to be from
        // a URL even if it was deleted in the background (hence the
        // "false" arg to isFromURL()).  This is because the user expects
        // it to be from a URL, so when we session restore, we pop up a
        // "cannot find file" dialog, instead of silently creating a new,
        // blank document.
384
        if (!d->document->isFromURL (false/*don't bother checking exists*/))
385 386 387 388 389 390 391 392 393
        {
            // If we don't have a URL either:
            //
            // a) it was not modified - so we can use either width() or
            //    constructorWidth() (they'll be equal).
            // b) the changes were discarded so we use the initial width,
            //    constructorWidth().
            //
            // Similarly for height() and constructorHeight().
394 395
            const QSize docSize (d->document->constructorWidth (),
                                 d->document->constructorHeight ());
396
        #if DEBUG_KP_MAIN_WINDOW
397
            kDebug () << "\tnot from url; doc size=" << docSize;
398 399 400 401 402 403 404 405
        #endif
            configGroup.writeEntry (kpSessionSettingNotFromUrlDocumentSize, docSize);
        }


        // Local session save i.e. queryClose() was not called beforehand
        // (see QApplication::saveState())?
    #if 0
406
        if (d->document->isModified ())
407 408 409 410 411 412 413 414 415 416 417
        {
            // TODO: Implement by saving the current image to a persistent file.
            //       We do this instead of saving/mutating the backing image file
            //       as no one expects a file save on a session save without a
            //       "do you want to save" dialog first.
            //
            //       I don't think any KDE application implements local session saving.
            //
            //       --- The below code does not compile but shows you want to do ---

            // Create unique name for the document in this main window.
Christoph Feck's avatar
Christoph Feck committed
418
            const QUrl tempURL = homeDir +
419 420 421 422 423
                "kolourpaint session " + sessionID +
                mainWindowPtrToString + ".png";
            // TODO: Use lossless PNG saving options.
            kpDocumentSaveOptions pngSaveOptions;

424
            if (kpDocument::savePixmapToFile (d->document->pixmapWithSelection (),
425
                    tempURL,
426
                    pngSaveOptions, *d->document->metaInfo (),
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
                    false/*no overwrite prompt*/,
                    false/*no lossy prompt*/,
                    this))
            {
                // readProperties() will still open kpSessionSettingDocumentUrl
                // (as that's the expected URL) and will then add commands to:
                //
                // 1. Resize the document to the size of image at
                //    kpSessionSettingDocumentUnsavedContentsUrl, if the sizes
                //    differ.
                // 2. Paste the kpSessionSettingDocumentUnsavedContentsUrl image
                //    (setting the main window's selection mode to opaque beforehand).
                //
                // It will then delete the file at
                // kpSessionSettingDocumentUnsavedContentsUrl.
                configGroup.writeEntry (kpSessionSettingDocumentUnsavedContentsUrl,
                    tempURL.url ());
            }
            else
            {
                // Not much we can do - we aren't allowed to throw up a dialog.
            }
        }
    #endif
    }
}

454 455
//---------------------------------------------------------------------

456

457 458
kpMainWindow::~kpMainWindow ()
{
459
    d->isFullyConstructed = false;
460

461 462 463 464 465 466 467 468 469
    // Get the kpTool to finish up.  This makes sure that the kpTool destructor
    // will not need to access any other class (that might be deleted before
    // the destructor is called by the QObject child-deletion mechanism).
    if (tool ())
        tool ()->endInternal ();

    // Delete document & views.
    // Note: This will disconnects signals from the current kpTool, so kpTool
    //       must not be destructed yet.
Clarence Dang's avatar
Clarence Dang committed
470
    setDocument (0);
471

472 473
    delete d->commandHistory; d->commandHistory = 0;
    delete d->scrollView; d->scrollView = 0;
Clarence Dang's avatar
Clarence Dang committed
474 475

    delete d; d = 0;
476 477
}

478 479
//---------------------------------------------------------------------

480 481 482

// public
kpDocument *kpMainWindow::document () const
483
{
484
    return d->document;
485 486
}

487 488
//---------------------------------------------------------------------

489 490 491 492 493 494 495 496 497
// public
kpDocumentEnvironment *kpMainWindow::documentEnvironment ()
{
    if (!d->documentEnvironment)
        d->documentEnvironment = new kpDocumentEnvironment (this);

    return d->documentEnvironment;
}

498 499
//---------------------------------------------------------------------

500 501
// public
kpViewManager *kpMainWindow::viewManager () const
502
{
503
    return d->viewManager;
504 505
}

506 507
//---------------------------------------------------------------------

508 509
// public
kpColorToolBar *kpMainWindow::colorToolBar () const
510
{
511
    return d->colorToolBar;
512 513
}

514 515
//---------------------------------------------------------------------

516 517 518
// public
kpColorCells *kpMainWindow::colorCells () const
{
519
    return d->colorToolBar ? d->colorToolBar->colorCells () : 0;
520 521
}

522 523
//---------------------------------------------------------------------

524 525
// public
kpToolToolBar *kpMainWindow::toolToolBar () const
526
{
527
    return d->toolToolBar;
528 529
}

530 531
//---------------------------------------------------------------------

532
// public
Clarence Dang's avatar
Clarence Dang committed
533
kpCommandHistory *kpMainWindow::commandHistory () const
534
{
535
    return d->commandHistory;
536 537
}

538 539
//---------------------------------------------------------------------

540 541 542 543 544 545 546 547
kpCommandEnvironment *kpMainWindow::commandEnvironment ()
{
    if (!d->commandEnvironment)
        d->commandEnvironment = new kpCommandEnvironment (this);

    return d->commandEnvironment;
}

548
//---------------------------------------------------------------------
549

550 551
// private
void kpMainWindow::setupActions ()
552
{
553 554 555 556
    setupFileMenuActions ();
    setupEditMenuActions ();
    setupViewMenuActions ();
    setupImageMenuActions ();
557
    setupColorsMenuActions ();
558
    setupSettingsMenuActions ();
559

Clarence Dang's avatar
Clarence Dang committed
560
    setupTextToolBarActions ();
561
    setupToolActions ();
562 563
}

564 565
//---------------------------------------------------------------------

Clarence Dang's avatar
Clarence Dang committed
566 567 568 569 570 571 572
// private
void kpMainWindow::enableDocumentActions (bool enable)
{
    enableFileMenuDocumentActions (enable);
    enableEditMenuDocumentActions (enable);
    enableViewMenuDocumentActions (enable);
    enableImageMenuDocumentActions (enable);
573
    enableColorsMenuDocumentActions (enable);
Clarence Dang's avatar
Clarence Dang committed
574 575 576
    enableSettingsMenuDocumentActions (enable);
}

577
//---------------------------------------------------------------------
578

579
// private
Clarence Dang's avatar
Clarence Dang committed
580
void kpMainWindow::setDocument (kpDocument *newDoc)
581
{
582
    //kDebug () << newDoc;
583

Clarence Dang's avatar
Clarence Dang committed
584 585 586
    // is it a close operation?
    if (!newDoc)
    {
587
    #if DEBUG_KP_MAIN_WINDOW
588
        kDebug () << "\tdisabling actions";
Clarence Dang's avatar
Clarence Dang committed
589
    #endif
Clarence Dang's avatar
 
Clarence Dang committed
590

Clarence Dang's avatar
Clarence Dang committed
591
        // sync with the bit marked "sync" below
Clarence Dang's avatar
 
Clarence Dang committed
592

593 594 595 596 597 598 599
        // TODO: Never disable the Color Box because the user should be
        //       able to manipulate the colors, even without a currently
        //       open document.
        //
        //       We just have to make sure that signals from the Color
        //       Box aren't fired and received unexpectedly when there's
        //       no document.
600 601
        Q_ASSERT (d->colorToolBar);
        d->colorToolBar->setEnabled (false);
Clarence Dang's avatar
Clarence Dang committed
602

Clarence Dang's avatar
Clarence Dang committed
603 604 605 606 607 608 609 610
        enableTextToolBarActions (false);
    }

    // Always disable the tools.
    // If we decide to open a new document/mainView we want
    // kpTool::begin() to be called again e.g. in case it sets the cursor.
    // kpViewManager won't do this because we nuke it to avoid stale state.
    enableToolsDocumentActions (false);
Clarence Dang's avatar
 
Clarence Dang committed
611

Clarence Dang's avatar
Clarence Dang committed
612 613
    if (!newDoc)
    {
Clarence Dang's avatar
Clarence Dang committed
614 615
        enableDocumentActions (false);
    }
Clarence Dang's avatar
 
Clarence Dang committed
616

617
    delete d->mainView; d->mainView = 0;
618
    slotDestroyThumbnail ();
619

Clarence Dang's avatar
Clarence Dang committed
620
    // viewManager will die and so will the selection
621 622 623 624 625
    d->actionCopy->setEnabled (false);
    d->actionCut->setEnabled (false);
    d->actionDelete->setEnabled (false);
    d->actionDeselect->setEnabled (false);
    d->actionCopyToFile->setEnabled (false);
Clarence Dang's avatar
Clarence Dang committed
626

627
    delete d->viewManager; d->viewManager = 0;
Clarence Dang's avatar
 
Clarence Dang committed
628

629
#if DEBUG_KP_MAIN_WINDOW
630 631
    kDebug () << "\tdestroying document";
    kDebug () << "\t\td->document=" << d->document;
Clarence Dang's avatar
Clarence Dang committed
632 633
#endif
    // destroy current document
634 635
    delete d->document;
    d->document = newDoc;
Clarence Dang's avatar
 
Clarence Dang committed
636

Clarence Dang's avatar
Clarence Dang committed
637

638
    if (!d->lastCopyToURL.isEmpty ())
Christoph Feck's avatar
Christoph Feck committed
639 640 641 642 643 644
    {
        // remove file name from path
        QString path = d->lastCopyToURL.path ();
        path = path.left (path.lastIndexOf (QLatin1Char ('/')) + 1);
        d->lastCopyToURL.setPath (path);
    }
645
    d->copyToFirstTime = true;
646

647
    if (!d->lastExportURL.isEmpty ())
Christoph Feck's avatar
Christoph Feck committed
648 649 650 651 652
    {
        QString path = d->lastExportURL.path ();
        path = path.left (path.lastIndexOf (QLatin1Char ('/')) + 1);
        d->lastExportURL.setPath (path);
    }
653
    d->exportFirstTime = true;
654 655


Clarence Dang's avatar
Clarence Dang committed
656
    // not a close operation?
657
    if (d->document)
658
    {
659 660 661 662
    #if DEBUG_KP_MAIN_WINDOW
        kDebug () << "\treparenting doc that may have been created into a"
                  << " different mainWindiow" << endl;
    #endif
663
        d->document->setEnviron (documentEnvironment ());
Clarence Dang's avatar
 
Clarence Dang committed
664

665
        d->viewManager = new kpViewManager (this);
Clarence Dang's avatar
Clarence Dang committed
666

667
        d->mainView = new kpZoomedView (d->document, d->toolToolBar, d->viewManager,
668
                                       0/*buddyView*/,
669 670
                                       d->scrollView,
                                       d->scrollView->viewport ());
Laurent Montel's avatar
Laurent Montel committed
671
        d->mainView->setObjectName ( QLatin1String("mainView" ));
Clarence Dang's avatar
Clarence Dang committed
672

673
        d->viewManager->registerView (d->mainView);
674
        d->scrollView->setView (d->mainView);
675
        d->mainView->show ();
Clarence Dang's avatar
 
Clarence Dang committed
676

677
    #if DEBUG_KP_MAIN_WINDOW
678
        kDebug () << "\thooking up document signals";
Clarence Dang's avatar
Clarence Dang committed
679
    #endif
Clarence Dang's avatar
 
Clarence Dang committed
680

681
        // Copy/Cut/Deselect/Delete
682 683 684 685 686 687 688 689 690 691
        connect (d->document, SIGNAL (selectionEnabled (bool)),
                 d->actionCut, SLOT (setEnabled (bool)));
        connect (d->document, SIGNAL (selectionEnabled (bool)),
                 d->actionCopy, SLOT (setEnabled (bool)));
        connect (d->document, SIGNAL (selectionEnabled (bool)),
                 d->actionDelete, SLOT (setEnabled (bool)));
        connect (d->document, SIGNAL (selectionEnabled (bool)),
                 d->actionDeselect, SLOT (setEnabled (bool)));
        connect (d->document, SIGNAL (selectionEnabled (bool)),
                 d->actionCopyToFile, SLOT (setEnabled (bool)));
692 693 694

        // this code won't actually enable any actions at this stage
        // (fresh document) but better safe than sorry
695 696 697 698 699
        d->actionCopy->setEnabled (d->document->selection ());
        d->actionCut->setEnabled (d->document->selection ());
        d->actionDeselect->setEnabled (d->document->selection ());
        d->actionDelete->setEnabled (d->document->selection ());
        d->actionCopyToFile->setEnabled (d->document->selection ());
700

701
        connect (d->document, SIGNAL (selectionEnabled (bool)),
702
                 this, SLOT (slotImageMenuUpdateDueToSelection ()));
703
        connect (d->document, SIGNAL (selectionIsTextChanged (bool)),
704
                 this, SLOT (slotImageMenuUpdateDueToSelection ()));
705 706

        // Status bar
707
        connect (d->document, SIGNAL (documentOpened ()),
708
                 this, SLOT (recalculateStatusBar ()));
709

710
        connect (d->document, SIGNAL (sizeChanged (const QSize &)),
711
                 this, SLOT (setStatusBarDocSize (const QSize &)));
Clarence Dang's avatar
Clarence Dang committed
712

713
        // Caption (url, modified)
714
        connect (d->document, SIGNAL (documentModified ()),
Clarence Dang's avatar
Clarence Dang committed
715
                 this, SLOT (slotUpdateCaption ()));
716
        connect (d->document, SIGNAL (documentOpened ()),
Clarence Dang's avatar
Clarence Dang committed
717
                 this, SLOT (slotUpdateCaption ()));
718
        connect (d->document, SIGNAL (documentSaved ()),
Clarence Dang's avatar
Clarence Dang committed
719 720
                 this, SLOT (slotUpdateCaption ()));

721
        // File/Reload action only available with non-empty URL
722
        connect (d->document, SIGNAL (documentSaved ()),
723
                 this, SLOT (slotEnableReload ()));
724

725
        connect (d->document, SIGNAL (documentSaved ()),
726
                 this, SLOT (slotEnableSettingsShowPath ()));
727

728
        // Command history
729 730
        Q_ASSERT (d->commandHistory);
        connect (d->commandHistory, SIGNAL (documentRestored ()),
731
                 this, SLOT (slotDocumentRestored ()));  // caption "!modified"
732 733
        connect (d->document, SIGNAL (documentSaved ()),
                 d->commandHistory, SLOT (documentSaved ()));
734

735
        // Sync document -> views
736 737 738 739
        connect (d->document, SIGNAL (contentsChanged (const QRect &)),
                 d->viewManager, SLOT (updateViews (const QRect &)));
        connect (d->document, SIGNAL (sizeChanged (int, int)),
                 d->viewManager, SLOT (adjustViewsToEnvironment ()));
Clarence Dang's avatar
 
Clarence Dang committed
740

741
    #if DEBUG_KP_MAIN_WINDOW
742
        kDebug () << "\tenabling actions";
Clarence Dang's avatar
Clarence Dang committed
743
    #endif
Clarence Dang's avatar
 
Clarence Dang committed
744

Clarence Dang's avatar
Clarence Dang committed
745
        // sync with the bit marked "sync" above
Clarence Dang's avatar
 
Clarence Dang committed
746

747 748
        Q_ASSERT (d->colorToolBar);
        d->colorToolBar->setEnabled (true);
Clarence Dang's avatar
 
Clarence Dang committed
749

Clarence Dang's avatar
Clarence Dang committed
750 751 752 753

        // Hide the text toolbar - it will be shown by kpToolText::begin()
        enableTextToolBarActions (false);

Clarence Dang's avatar
Clarence Dang committed
754
        enableToolsDocumentActions (true);
Clarence Dang's avatar
 
Clarence Dang committed
755

Clarence Dang's avatar
Clarence Dang committed
756
        enableDocumentActions (true);
Clarence Dang's avatar
Clarence Dang committed
757 758 759 760 761

    // TODO: The thumbnail auto zoom doesn't work because it thinks its
    //       width == 1 when !this->isShown().  So for consistency,
    //       never create the thumbnail.
    #if 0
762
        if (d->configThumbnailShown)
Clarence Dang's avatar
Clarence Dang committed
763 764 765 766
        {
            if (isShown ())
            {
            #if DEBUG_KP_MAIN_WINDOW
767
                kDebug () << "\tcreating thumbnail immediately";
Clarence Dang's avatar
Clarence Dang committed
768 769 770 771 772 773 774
            #endif
                slotCreateThumbnail ();
            }
            // this' geometry is weird ATM
            else
            {
            #if DEBUG_KP_MAIN_WINDOW
775
                kDebug () << "\tcreating thumbnail LATER";
Clarence Dang's avatar
Clarence Dang committed
776 777 778 779 780
            #endif
                QTimer::singleShot (0, this, SLOT (slotCreateThumbnail ()));
            }
        }
    #endif
781
    }
Clarence Dang's avatar
Clarence Dang committed
782

783
#if DEBUG_KP_MAIN_WINDOW
784
    kDebug () << "\tupdating mainWindow elements";
Clarence Dang's avatar
Clarence Dang committed
785 786
#endif

787
    slotImageMenuUpdateDueToSelection ();
788
    recalculateStatusBar ();
Clarence Dang's avatar
Clarence Dang committed
789
    slotUpdateCaption ();  // Untitled to start with
790 791
    slotEnableReload ();
    slotEnableSettingsShowPath ();
Clarence Dang's avatar
 
Clarence Dang committed
792

793 794
    if (d->commandHistory)
        d->commandHistory->clear ();
Clarence Dang's avatar
Clarence Dang committed
795

796
#if DEBUG_KP_MAIN_WINDOW
797
    kDebug () << "\tdocument and views ready to go!";
Clarence Dang's avatar
 
Clarence Dang committed
798
#endif
799 800
}

801
//---------------------------------------------------------------------
802 803 804 805

// private virtual [base QWidget]
void kpMainWindow::dragEnterEvent (QDragEnterEvent *e)
{
806 807 808
    // It's faster to test for QMimeData::hasText() first due to the
    // lazy evaluation of the '||' operator.
    e->setAccepted (e->mimeData ()->hasText () ||
809
                    e->mimeData ()->hasUrls () ||
810
                    kpSelectionDrag::canDecode (e->mimeData ()));
811 812
}

813 814
//---------------------------------------------------------------------

815 816
// private virtual [base QWidget]
void kpMainWindow::dropEvent (QDropEvent *e)
817
{
818
#if DEBUG_KP_MAIN_WINDOW
819
    kDebug () << "kpMainWindow::dropEvent" << e->pos ();
820 821
#endif

Christoph Feck's avatar
Christoph Feck committed
822
    QList<QUrl> urls;
Clarence Dang's avatar
 
Clarence Dang committed
823

824
    kpAbstractImageSelection *sel = kpSelectionDrag::decode (e->mimeData ());
825
    if (sel)