File indexing completed on 2024-04-28 04:20:20

0001 /*
0002    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
0003    All rights reserved.
0004 
0005    Redistribution and use in source and binary forms, with or without
0006    modification, are permitted provided that the following conditions
0007    are met:
0008 
0009    1. Redistributions of source code must retain the above copyright
0010       notice, this list of conditions and the following disclaimer.
0011    2. Redistributions in binary form must reproduce the above copyright
0012       notice, this list of conditions and the following disclaimer in the
0013       documentation and/or other materials provided with the distribution.
0014 
0015    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0016    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0017    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0018    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0019    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0020    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0021    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0022    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0023    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0024    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0025 */
0026 
0027 
0028 #include "kpMainWindow.h"
0029 #include "kpMainWindowPrivate.h"
0030 
0031 #include "widgets/kpColorCells.h"
0032 #include "lgpl/generic/kpColorCollection.h"
0033 #include "lgpl/generic/kpUrlFormatter.h"
0034 #include "widgets/toolbars/kpColorToolBar.h"
0035 
0036 #include <KActionCollection>
0037 #include <KMessageBox>
0038 #include <KSelectAction>
0039 #include <KStandardGuiItem>
0040 #include "kpLogCategories.h"
0041 
0042 #include <QFileDialog>
0043 #include <QAction>
0044 #include <kwidgetsaddons_version.h>
0045 
0046 //---------------------------------------------------------------------
0047 
0048 static QStringList KDEColorCollectionNames ()
0049 {
0050     return kpColorCollection::installedCollections ();
0051 }
0052 
0053 //---------------------------------------------------------------------
0054 
0055 // private
0056 void kpMainWindow::setupColorsMenuActions ()
0057 {
0058     KActionCollection *ac = actionCollection ();
0059 
0060 
0061     d->actionColorsDefault = ac->addAction (QStringLiteral("colors_default"));
0062     d->actionColorsDefault->setText (i18n ("Use KolourPaint Defaults"));
0063     connect (d->actionColorsDefault, &QAction::triggered,
0064              this, &kpMainWindow::slotColorsDefault);
0065 
0066     d->actionColorsKDE = ac->add <KSelectAction> (QStringLiteral("colors_kde"));
0067     d->actionColorsKDE->setText (i18nc ("@item:inmenu colors", "Use KDE's"));
0068     // TODO: Will this slot be called spuriously if there are no colors
0069     //       installed?
0070 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0071     connect (d->actionColorsKDE,
0072              static_cast<void (KSelectAction::*)(QAction*)>(&KSelectAction::triggered),
0073              this, &kpMainWindow::slotColorsKDE);
0074 #else
0075     connect (d->actionColorsKDE,
0076              &KSelectAction::actionTriggered,
0077              this, &kpMainWindow::slotColorsKDE);
0078 #endif
0079 
0080     for (const auto &colName : ::KDEColorCollectionNames ()) {
0081         d->actionColorsKDE->addAction (colName);
0082     }
0083 
0084     d->actionColorsOpen = ac->addAction (QStringLiteral("colors_open"));
0085     d->actionColorsOpen->setText (i18nc ("@item:inmenu colors", "&Open..."));
0086     connect (d->actionColorsOpen, &QAction::triggered, this, &kpMainWindow::slotColorsOpen);
0087 
0088     d->actionColorsReload = ac->addAction (QStringLiteral("colors_reload"));
0089     d->actionColorsReload->setText (i18nc ("@item:inmenu colors", "Reloa&d"));
0090     connect (d->actionColorsReload, &QAction::triggered,
0091              this, &kpMainWindow::slotColorsReload);
0092 
0093     d->actionColorsSave = ac->addAction (QStringLiteral("colors_save"));
0094     d->actionColorsSave->setText (i18nc ("@item:inmenu colors", "&Save"));
0095     connect (d->actionColorsSave, &QAction::triggered,
0096              this, &kpMainWindow::slotColorsSave);
0097 
0098     d->actionColorsSaveAs = ac->addAction (QStringLiteral("colors_save_as"));
0099     d->actionColorsSaveAs->setText (i18nc ("@item:inmenu colors", "Save &As..."));
0100     connect (d->actionColorsSaveAs, &QAction::triggered,
0101              this, &kpMainWindow::slotColorsSaveAs);
0102 
0103     d->actionColorsAppendRow = ac->addAction (QStringLiteral("colors_append_row"));
0104     d->actionColorsAppendRow->setText (i18nc ("@item:inmenu colors", "Add Row"));
0105     connect (d->actionColorsAppendRow, &QAction::triggered,
0106              this, &kpMainWindow::slotColorsAppendRow);
0107 
0108     d->actionColorsDeleteRow = ac->addAction (QStringLiteral("colors_delete_row"));
0109     d->actionColorsDeleteRow->setText (i18nc ("@item:inmenu colors", "Delete Last Row"));
0110     connect (d->actionColorsDeleteRow, &QAction::triggered,
0111              this, &kpMainWindow::slotColorsDeleteRow);
0112 
0113 
0114     enableColorsMenuDocumentActions (false);
0115 }
0116 
0117 //---------------------------------------------------------------------
0118 
0119 // private
0120 void kpMainWindow::createColorBox ()
0121 {
0122     d->colorToolBar = new kpColorToolBar (i18n ("Color Box"), this);
0123 
0124     // (needed for QMainWindow::saveState())
0125     d->colorToolBar->setObjectName ( QStringLiteral("Color Box" ));
0126 
0127     connect (colorCells (), &kpColorCells::rowCountChanged,
0128              this, &kpMainWindow::slotUpdateColorsDeleteRowActionEnabled);
0129 }
0130 
0131 //---------------------------------------------------------------------
0132 
0133 // private
0134 void kpMainWindow::enableColorsMenuDocumentActions (bool enable)
0135 {
0136     d->actionColorsDefault->setEnabled (enable);
0137     d->actionColorsKDE->setEnabled (enable);
0138     d->actionColorsOpen->setEnabled (enable);
0139     d->actionColorsReload->setEnabled (enable);
0140 
0141     d->actionColorsSave->setEnabled (enable);
0142     d->actionColorsSaveAs->setEnabled (enable);
0143 
0144     d->actionColorsAppendRow->setEnabled (enable);
0145 
0146     d->colorMenuDocumentActionsEnabled = enable;
0147 
0148     slotUpdateColorsDeleteRowActionEnabled ();
0149 }
0150 
0151 //---------------------------------------------------------------------
0152 
0153 // private slot
0154 void kpMainWindow::slotUpdateColorsDeleteRowActionEnabled ()
0155 {
0156     // Currently, this is always enabled since kpColorCells guarantees that
0157     // there will be at least one row of cells (which might all be of the
0158     // invalid color).
0159     //
0160     // But this method is left here for future extensibility.
0161     d->actionColorsDeleteRow->setEnabled (
0162         d->colorMenuDocumentActionsEnabled && (colorCells ()->rowCount () > 0));
0163 }
0164 
0165 //---------------------------------------------------------------------
0166 
0167 
0168 // Used in 2 situations:
0169 //
0170 // 1. User opens a color without using the "Use KDE's" submenu.
0171 // 2. User attempts to open a color using the "Use KDE's" submenu but the
0172 //    opening fails.
0173 //
0174 // TODO: Maybe we could put the 3 actions (for different ways of opening
0175 //       colors) in an exclusive group -- this might eliminate the need for
0176 //       this hack.
0177 //
0178 // private
0179 void kpMainWindow::deselectActionColorsKDE ()
0180 {
0181     d->actionColorsKDE->setCurrentItem (-1);
0182 }
0183 
0184 //---------------------------------------------------------------------
0185 
0186 
0187 // private
0188 bool kpMainWindow::queryCloseColors ()
0189 {
0190 #if DEBUG_KP_MAIN_WINDOW
0191     qCDebug(kpLogMainWindow) << "kpMainWindow::queryCloseColors() colorCells.modified="
0192               << colorCells ()->isModified ();
0193 #endif
0194 
0195     toolEndShape ();
0196 
0197     if (!colorCells ()->isModified ()) {
0198         return true;  // ok to close
0199     }
0200 
0201     int result = KMessageBox::Cancel;
0202 
0203 
0204     if (!colorCells ()->url ().isEmpty ())
0205     {
0206 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0207         result = KMessageBox::warningTwoActionsCancel(this,
0208 #else
0209         result = KMessageBox::warningYesNoCancel (this,
0210 #endif
0211             i18n ("The color palette \"%1\" has been modified.\n"
0212                   "Do you want to save it?",
0213                   kpUrlFormatter::PrettyFilename (colorCells ()->url ())),
0214             QString ()/*caption*/,
0215             KStandardGuiItem::save (), KStandardGuiItem::discard ());
0216     }
0217     else
0218     {
0219         const QString name = colorCells ()->colorCollection ()->name ();
0220         if (!name.isEmpty ())
0221         {
0222 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0223             result = KMessageBox::warningTwoActionsCancel(this,
0224 #else
0225             result = KMessageBox::warningYesNoCancel (this,
0226 #endif
0227                 i18n ("The KDE color palette \"%1\" has been modified.\n"
0228                       "Do you want to save it to a file?",
0229                       name),
0230                 QString ()/*caption*/,
0231                 KStandardGuiItem::save (), KStandardGuiItem::discard ());
0232         }
0233         else
0234         {
0235 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0236             result = KMessageBox::warningTwoActionsCancel(this,
0237 #else
0238             result = KMessageBox::warningYesNoCancel (this,
0239 #endif
0240                 i18n ("The default color palette has been modified.\n"
0241                       "Do you want to save it to a file?"),
0242                 QString ()/*caption*/,
0243                 KStandardGuiItem::save (), KStandardGuiItem::discard ());
0244         }
0245     }
0246 
0247     switch (result)
0248     {
0249 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0250     case KMessageBox::ButtonCode::PrimaryAction:
0251 #else
0252     case KMessageBox::Yes:
0253 #endif
0254         return slotColorsSave ();  // close only if save succeeds
0255 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0256     case KMessageBox::ButtonCode::SecondaryAction:
0257 #else
0258     case KMessageBox::No:
0259 #endif
0260         return true;  // close without saving
0261     default:
0262         return false;  // don't close current doc
0263     }
0264 }
0265 
0266 //---------------------------------------------------------------------
0267 
0268 
0269 // private
0270 void kpMainWindow::openDefaultColors ()
0271 {
0272     colorCells ()->setColorCollection (
0273         kpColorCells::DefaultColorCollection ());
0274 }
0275 
0276 //---------------------------------------------------------------------
0277 
0278 // private slot
0279 void kpMainWindow::slotColorsDefault ()
0280 {
0281     // Call just in case.
0282     toolEndShape ();
0283 
0284     if (!queryCloseColors ()) {
0285         return;
0286     }
0287 
0288     openDefaultColors ();
0289 
0290     deselectActionColorsKDE ();
0291 }
0292 
0293 //---------------------------------------------------------------------
0294 
0295 // private
0296 bool kpMainWindow::openKDEColors (const QString &name)
0297 {
0298 #if DEBUG_KP_MAIN_WINDOW
0299     qCDebug(kpLogMainWindow) << "kpMainWindow::openKDEColors(" << name << ")";
0300 #endif
0301 
0302     kpColorCollection colorCol;
0303     if (colorCol.openKDE (name, this))
0304     {
0305     #if DEBUG_KP_MAIN_WINDOW
0306         qCDebug(kpLogMainWindow) << "opened";
0307     #endif
0308         colorCells ()->setColorCollection (colorCol);
0309         return true;
0310     }
0311     else
0312     {
0313     #if DEBUG_KP_MAIN_WINDOW
0314         qCDebug(kpLogMainWindow) << "failed to open";
0315     #endif
0316         return false;
0317     }
0318 }
0319 
0320 //---------------------------------------------------------------------
0321 
0322 // private slot
0323 void kpMainWindow::slotColorsKDE ()
0324 {
0325     // Call in case an error dialog appears.
0326     toolEndShape ();
0327 
0328     const int curItem = d->actionColorsKDE->currentItem ();
0329 
0330     if (!queryCloseColors ())
0331     {
0332         deselectActionColorsKDE ();
0333         return;
0334     }
0335 
0336     // queryCloseColors() calls slotColorSave(), which can call
0337     // slotColorSaveAs(), which can call deselectActionColorsKDE().
0338     d->actionColorsKDE->setCurrentItem (curItem);
0339 
0340     const QStringList colNames = ::KDEColorCollectionNames ();
0341     const int selected = d->actionColorsKDE->currentItem ();
0342     Q_ASSERT (selected >= 0 && selected < colNames.size ());
0343 
0344     if (!openKDEColors (colNames [selected])) {
0345         deselectActionColorsKDE ();
0346     }
0347 }
0348 
0349 //---------------------------------------------------------------------
0350 
0351 // private
0352 bool kpMainWindow::openColors (const QUrl &url)
0353 {
0354     return colorCells ()->openColorCollection (url);
0355 }
0356 
0357 //---------------------------------------------------------------------
0358 
0359 // private slot
0360 void kpMainWindow::slotColorsOpen ()
0361 {
0362     // Call due to dialog.
0363     toolEndShape ();
0364 
0365     QFileDialog fd(this);
0366     fd.setDirectoryUrl(colorCells ()->url());
0367     fd.setWindowTitle(i18nc ("@title:window", "Open Color Palette"));
0368 
0369     if (fd.exec ())
0370     {
0371         if (!queryCloseColors ()) {
0372             return;
0373         }
0374 
0375         QList<QUrl> selected = fd.selectedUrls();
0376         if ( selected.count() && openColors(selected[0]) ) {
0377           deselectActionColorsKDE();
0378         }
0379     }
0380 }
0381 
0382 //---------------------------------------------------------------------
0383 
0384 // private slot
0385 void kpMainWindow::slotColorsReload ()
0386 {
0387     toolEndShape ();
0388 
0389     if (colorCells ()->isModified ())
0390     {
0391         int result = KMessageBox::Cancel;
0392 
0393         if (!colorCells ()->url ().isEmpty ())
0394         {
0395             result = KMessageBox::warningContinueCancel (this,
0396                 i18n ("The color palette \"%1\" has been modified.\n"
0397                       "Reloading will lose all changes since you last saved it.\n"
0398                       "Are you sure?",
0399                       kpUrlFormatter::PrettyFilename (colorCells ()->url ())),
0400                 QString ()/*caption*/,
0401                 KGuiItem(i18n ("&Reload")));
0402         }
0403         else
0404         {
0405             const QString name = colorCells ()->colorCollection ()->name ();
0406             if (!name.isEmpty ())
0407             {
0408                 result = KMessageBox::warningContinueCancel (this,
0409                     i18n ("The KDE color palette \"%1\" has been modified.\n"
0410                           "Reloading will lose all changes.\n"
0411                           "Are you sure?",
0412                           colorCells ()->colorCollection ()->name ()),
0413                     QString ()/*caption*/,
0414                     KGuiItem (i18n ("&Reload")));
0415             }
0416             else
0417             {
0418                 result = KMessageBox::warningContinueCancel (this,
0419                     i18n ("The default color palette has been modified.\n"
0420                           "Reloading will lose all changes.\n"
0421                           "Are you sure?"),
0422                     QString ()/*caption*/,
0423                     KGuiItem (i18n ("&Reload")));
0424             }
0425         }
0426 
0427     #if DEBUG_KP_MAIN_WINDOW
0428         qCDebug(kpLogMainWindow) << "result=" << result
0429                   << "vs KMessageBox::Continue" << KMessageBox::Continue;
0430     #endif
0431         if (result != KMessageBox::Continue) {
0432             return;
0433         }
0434     }
0435 
0436 
0437     if (!colorCells ()->url ().isEmpty ())
0438     {
0439         openColors (colorCells ()->url ());
0440     }
0441     else
0442     {
0443         const QString name = colorCells ()->colorCollection ()->name ();
0444         if (!name.isEmpty ()) {
0445             openKDEColors (name);
0446         }
0447         else {
0448             openDefaultColors ();
0449         }
0450     }
0451 }
0452 
0453 //---------------------------------------------------------------------
0454 
0455 
0456 // private slot
0457 bool kpMainWindow::slotColorsSave ()
0458 {
0459     // Call due to dialog.
0460     toolEndShape ();
0461 
0462     if (colorCells ()->url ().isEmpty ())
0463     {
0464         return slotColorsSaveAs ();
0465     }
0466 
0467     return colorCells ()->saveColorCollection ();
0468 }
0469 
0470 //---------------------------------------------------------------------
0471 
0472 // private slot
0473 bool kpMainWindow::slotColorsSaveAs ()
0474 {
0475     // Call due to dialog.
0476     toolEndShape ();
0477 
0478     QFileDialog fd(this);
0479     fd.setDirectoryUrl(colorCells ()->url());
0480     fd.setWindowTitle(i18n("Save Color Palette As"));
0481     fd.setAcceptMode(QFileDialog::AcceptSave);
0482     // Note that QFileDialog takes care of asking the user to confirm overwriting.
0483 
0484     if (fd.exec ())
0485     {
0486         QList<QUrl> selected = fd.selectedUrls();
0487         if ( !selected.count() || !colorCells ()->saveColorCollectionAs(selected[0]) ) {
0488           return false;
0489         }
0490 
0491         // We're definitely using our own color collection now.
0492         deselectActionColorsKDE ();
0493 
0494         return true;
0495     }
0496 
0497     return false;
0498 }
0499 
0500 //---------------------------------------------------------------------
0501 
0502 // private slot
0503 void kpMainWindow::slotColorsAppendRow ()
0504 {
0505     // Call just in case.
0506     toolEndShape ();
0507 
0508     kpColorCells *colorCells = d->colorToolBar->colorCells ();
0509     colorCells->appendRow ();
0510 }
0511 
0512 //---------------------------------------------------------------------
0513 
0514 // private slot
0515 void kpMainWindow::slotColorsDeleteRow ()
0516 {
0517     // Call just in case.
0518     toolEndShape ();
0519 
0520     kpColorCells *colorCells = d->colorToolBar->colorCells ();
0521     colorCells->deleteLastRow ();
0522 }