1 /*
2 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14
15 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27
28 #include "kpMainWindow.h"
29 #include "kpMainWindowPrivate.h"
30
31 #include "widgets/kpColorCells.h"
32 #include "lgpl/generic/kpColorCollection.h"
33 #include "lgpl/generic/kpUrlFormatter.h"
34 #include "widgets/toolbars/kpColorToolBar.h"
35
36 #include <KActionCollection>
37 #include <KMessageBox>
38 #include <KSelectAction>
39 #include <KStandardGuiItem>
40 #include "kpLogCategories.h"
41
42 #include <QFileDialog>
43 #include <QAction>
44
45 //---------------------------------------------------------------------
46
KDEColorCollectionNames()47 static QStringList KDEColorCollectionNames ()
48 {
49 return kpColorCollection::installedCollections ();
50 }
51
52 //---------------------------------------------------------------------
53
54 // private
setupColorsMenuActions()55 void kpMainWindow::setupColorsMenuActions ()
56 {
57 KActionCollection *ac = actionCollection ();
58
59
60 d->actionColorsDefault = ac->addAction (QStringLiteral("colors_default"));
61 d->actionColorsDefault->setText (i18n ("Use KolourPaint Defaults"));
62 connect (d->actionColorsDefault, &QAction::triggered,
63 this, &kpMainWindow::slotColorsDefault);
64
65 d->actionColorsKDE = ac->add <KSelectAction> (QStringLiteral("colors_kde"));
66 d->actionColorsKDE->setText (i18nc ("@item:inmenu colors", "Use KDE's"));
67 // TODO: Will this slot be called spuriously if there are no colors
68 // installed?
69 connect (d->actionColorsKDE,
70 static_cast<void (KSelectAction::*)(QAction*)>(&KSelectAction::triggered),
71 this, &kpMainWindow::slotColorsKDE);
72
73 for (const auto &colName : ::KDEColorCollectionNames ()) {
74 d->actionColorsKDE->addAction (colName);
75 }
76
77 d->actionColorsOpen = ac->addAction (QStringLiteral("colors_open"));
78 d->actionColorsOpen->setText (i18nc ("@item:inmenu colors", "&Open..."));
79 connect (d->actionColorsOpen, &QAction::triggered, this, &kpMainWindow::slotColorsOpen);
80
81 d->actionColorsReload = ac->addAction (QStringLiteral("colors_reload"));
82 d->actionColorsReload->setText (i18nc ("@item:inmenu colors", "Reloa&d"));
83 connect (d->actionColorsReload, &QAction::triggered,
84 this, &kpMainWindow::slotColorsReload);
85
86 d->actionColorsSave = ac->addAction (QStringLiteral("colors_save"));
87 d->actionColorsSave->setText (i18nc ("@item:inmenu colors", "&Save"));
88 connect (d->actionColorsSave, &QAction::triggered,
89 this, &kpMainWindow::slotColorsSave);
90
91 d->actionColorsSaveAs = ac->addAction (QStringLiteral("colors_save_as"));
92 d->actionColorsSaveAs->setText (i18nc ("@item:inmenu colors", "Save &As..."));
93 connect (d->actionColorsSaveAs, &QAction::triggered,
94 this, &kpMainWindow::slotColorsSaveAs);
95
96 d->actionColorsAppendRow = ac->addAction (QStringLiteral("colors_append_row"));
97 d->actionColorsAppendRow->setText (i18nc ("@item:inmenu colors", "Add Row"));
98 connect (d->actionColorsAppendRow, &QAction::triggered,
99 this, &kpMainWindow::slotColorsAppendRow);
100
101 d->actionColorsDeleteRow = ac->addAction (QStringLiteral("colors_delete_row"));
102 d->actionColorsDeleteRow->setText (i18nc ("@item:inmenu colors", "Delete Last Row"));
103 connect (d->actionColorsDeleteRow, &QAction::triggered,
104 this, &kpMainWindow::slotColorsDeleteRow);
105
106
107 enableColorsMenuDocumentActions (false);
108 }
109
110 //---------------------------------------------------------------------
111
112 // private
createColorBox()113 void kpMainWindow::createColorBox ()
114 {
115 d->colorToolBar = new kpColorToolBar (i18n ("Color Box"), this);
116
117 // (needed for QMainWindow::saveState())
118 d->colorToolBar->setObjectName ( QStringLiteral("Color Box" ));
119
120 connect (colorCells (), &kpColorCells::rowCountChanged,
121 this, &kpMainWindow::slotUpdateColorsDeleteRowActionEnabled);
122 }
123
124 //---------------------------------------------------------------------
125
126 // private
enableColorsMenuDocumentActions(bool enable)127 void kpMainWindow::enableColorsMenuDocumentActions (bool enable)
128 {
129 d->actionColorsDefault->setEnabled (enable);
130 d->actionColorsKDE->setEnabled (enable);
131 d->actionColorsOpen->setEnabled (enable);
132 d->actionColorsReload->setEnabled (enable);
133
134 d->actionColorsSave->setEnabled (enable);
135 d->actionColorsSaveAs->setEnabled (enable);
136
137 d->actionColorsAppendRow->setEnabled (enable);
138
139 d->colorMenuDocumentActionsEnabled = enable;
140
141 slotUpdateColorsDeleteRowActionEnabled ();
142 }
143
144 //---------------------------------------------------------------------
145
146 // private slot
slotUpdateColorsDeleteRowActionEnabled()147 void kpMainWindow::slotUpdateColorsDeleteRowActionEnabled ()
148 {
149 // Currently, this is always enabled since kpColorCells guarantees that
150 // there will be at least one row of cells (which might all be of the
151 // invalid color).
152 //
153 // But this method is left here for future extensibility.
154 d->actionColorsDeleteRow->setEnabled (
155 d->colorMenuDocumentActionsEnabled && (colorCells ()->rowCount () > 0));
156 }
157
158 //---------------------------------------------------------------------
159
160
161 // Used in 2 situations:
162 //
163 // 1. User opens a color without using the "Use KDE's" submenu.
164 // 2. User attempts to open a color using the "Use KDE's" submenu but the
165 // opening fails.
166 //
167 // TODO: Maybe we could put the 3 actions (for different ways of opening
168 // colors) in an exclusive group -- this might eliminate the need for
169 // this hack.
170 //
171 // private
deselectActionColorsKDE()172 void kpMainWindow::deselectActionColorsKDE ()
173 {
174 d->actionColorsKDE->setCurrentItem (-1);
175 }
176
177 //---------------------------------------------------------------------
178
179
180 // private
queryCloseColors()181 bool kpMainWindow::queryCloseColors ()
182 {
183 #if DEBUG_KP_MAIN_WINDOW
184 qCDebug(kpLogMainWindow) << "kpMainWindow::queryCloseColors() colorCells.modified="
185 << colorCells ()->isModified ();
186 #endif
187
188 toolEndShape ();
189
190 if (!colorCells ()->isModified ()) {
191 return true; // ok to close
192 }
193
194 int result = KMessageBox::Cancel;
195
196
197 if (!colorCells ()->url ().isEmpty ())
198 {
199 result = KMessageBox::warningYesNoCancel (this,
200 i18n ("The color palette \"%1\" has been modified.\n"
201 "Do you want to save it?",
202 kpUrlFormatter::PrettyFilename (colorCells ()->url ())),
203 QString ()/*caption*/,
204 KStandardGuiItem::save (), KStandardGuiItem::discard ());
205 }
206 else
207 {
208 const QString name = colorCells ()->colorCollection ()->name ();
209 if (!name.isEmpty ())
210 {
211 result = KMessageBox::warningYesNoCancel (this,
212 i18n ("The KDE color palette \"%1\" has been modified.\n"
213 "Do you want to save it to a file?",
214 name),
215 QString ()/*caption*/,
216 KStandardGuiItem::save (), KStandardGuiItem::discard ());
217 }
218 else
219 {
220 result = KMessageBox::warningYesNoCancel (this,
221 i18n ("The default color palette has been modified.\n"
222 "Do you want to save it to a file?"),
223 QString ()/*caption*/,
224 KStandardGuiItem::save (), KStandardGuiItem::discard ());
225 }
226 }
227
228 switch (result)
229 {
230 case KMessageBox::Yes:
231 return slotColorsSave (); // close only if save succeeds
232 case KMessageBox::No:
233 return true; // close without saving
234 default:
235 return false; // don't close current doc
236 }
237 }
238
239 //---------------------------------------------------------------------
240
241
242 // private
openDefaultColors()243 void kpMainWindow::openDefaultColors ()
244 {
245 colorCells ()->setColorCollection (
246 kpColorCells::DefaultColorCollection ());
247 }
248
249 //---------------------------------------------------------------------
250
251 // private slot
slotColorsDefault()252 void kpMainWindow::slotColorsDefault ()
253 {
254 // Call just in case.
255 toolEndShape ();
256
257 if (!queryCloseColors ()) {
258 return;
259 }
260
261 openDefaultColors ();
262
263 deselectActionColorsKDE ();
264 }
265
266 //---------------------------------------------------------------------
267
268 // private
openKDEColors(const QString & name)269 bool kpMainWindow::openKDEColors (const QString &name)
270 {
271 #if DEBUG_KP_MAIN_WINDOW
272 qCDebug(kpLogMainWindow) << "kpMainWindow::openKDEColors(" << name << ")";
273 #endif
274
275 kpColorCollection colorCol;
276 if (colorCol.openKDE (name, this))
277 {
278 #if DEBUG_KP_MAIN_WINDOW
279 qCDebug(kpLogMainWindow) << "opened";
280 #endif
281 colorCells ()->setColorCollection (colorCol);
282 return true;
283 }
284 else
285 {
286 #if DEBUG_KP_MAIN_WINDOW
287 qCDebug(kpLogMainWindow) << "failed to open";
288 #endif
289 return false;
290 }
291 }
292
293 //---------------------------------------------------------------------
294
295 // private slot
slotColorsKDE()296 void kpMainWindow::slotColorsKDE ()
297 {
298 // Call in case an error dialog appears.
299 toolEndShape ();
300
301 const int curItem = d->actionColorsKDE->currentItem ();
302
303 if (!queryCloseColors ())
304 {
305 deselectActionColorsKDE ();
306 return;
307 }
308
309 // queryCloseColors() calls slotColorSave(), which can call
310 // slotColorSaveAs(), which can call deselectActionColorsKDE().
311 d->actionColorsKDE->setCurrentItem (curItem);
312
313 const QStringList colNames = ::KDEColorCollectionNames ();
314 const int selected = d->actionColorsKDE->currentItem ();
315 Q_ASSERT (selected >= 0 && selected < colNames.size ());
316
317 if (!openKDEColors (colNames [selected])) {
318 deselectActionColorsKDE ();
319 }
320 }
321
322 //---------------------------------------------------------------------
323
324 // private
openColors(const QUrl & url)325 bool kpMainWindow::openColors (const QUrl &url)
326 {
327 return colorCells ()->openColorCollection (url);
328 }
329
330 //---------------------------------------------------------------------
331
332 // private slot
slotColorsOpen()333 void kpMainWindow::slotColorsOpen ()
334 {
335 // Call due to dialog.
336 toolEndShape ();
337
338 QFileDialog fd(this);
339 fd.setDirectoryUrl(colorCells ()->url());
340 fd.setWindowTitle(i18nc ("@title:window", "Open Color Palette"));
341
342 if (fd.exec ())
343 {
344 if (!queryCloseColors ()) {
345 return;
346 }
347
348 QList<QUrl> selected = fd.selectedUrls();
349 if ( selected.count() && openColors(selected[0]) ) {
350 deselectActionColorsKDE();
351 }
352 }
353 }
354
355 //---------------------------------------------------------------------
356
357 // private slot
slotColorsReload()358 void kpMainWindow::slotColorsReload ()
359 {
360 toolEndShape ();
361
362 if (colorCells ()->isModified ())
363 {
364 int result = KMessageBox::Cancel;
365
366 if (!colorCells ()->url ().isEmpty ())
367 {
368 result = KMessageBox::warningContinueCancel (this,
369 i18n ("The color palette \"%1\" has been modified.\n"
370 "Reloading will lose all changes since you last saved it.\n"
371 "Are you sure?",
372 kpUrlFormatter::PrettyFilename (colorCells ()->url ())),
373 QString ()/*caption*/,
374 KGuiItem(i18n ("&Reload")));
375 }
376 else
377 {
378 const QString name = colorCells ()->colorCollection ()->name ();
379 if (!name.isEmpty ())
380 {
381 result = KMessageBox::warningContinueCancel (this,
382 i18n ("The KDE color palette \"%1\" has been modified.\n"
383 "Reloading will lose all changes.\n"
384 "Are you sure?",
385 colorCells ()->colorCollection ()->name ()),
386 QString ()/*caption*/,
387 KGuiItem (i18n ("&Reload")));
388 }
389 else
390 {
391 result = KMessageBox::warningContinueCancel (this,
392 i18n ("The default color palette has been modified.\n"
393 "Reloading will lose all changes.\n"
394 "Are you sure?"),
395 QString ()/*caption*/,
396 KGuiItem (i18n ("&Reload")));
397 }
398 }
399
400 #if DEBUG_KP_MAIN_WINDOW
401 qCDebug(kpLogMainWindow) << "result=" << result
402 << "vs KMessageBox::Continue" << KMessageBox::Continue;
403 #endif
404 if (result != KMessageBox::Continue) {
405 return;
406 }
407 }
408
409
410 if (!colorCells ()->url ().isEmpty ())
411 {
412 openColors (colorCells ()->url ());
413 }
414 else
415 {
416 const QString name = colorCells ()->colorCollection ()->name ();
417 if (!name.isEmpty ()) {
418 openKDEColors (name);
419 }
420 else {
421 openDefaultColors ();
422 }
423 }
424 }
425
426 //---------------------------------------------------------------------
427
428
429 // private slot
slotColorsSave()430 bool kpMainWindow::slotColorsSave ()
431 {
432 // Call due to dialog.
433 toolEndShape ();
434
435 if (colorCells ()->url ().isEmpty ())
436 {
437 return slotColorsSaveAs ();
438 }
439
440 return colorCells ()->saveColorCollection ();
441 }
442
443 //---------------------------------------------------------------------
444
445 // private slot
slotColorsSaveAs()446 bool kpMainWindow::slotColorsSaveAs ()
447 {
448 // Call due to dialog.
449 toolEndShape ();
450
451 QFileDialog fd(this);
452 fd.setDirectoryUrl(colorCells ()->url());
453 fd.setWindowTitle(i18n("Save Color Palette As"));
454 fd.setAcceptMode(QFileDialog::AcceptSave);
455 // Note that QFileDialog takes care of asking the user to confirm overwriting.
456
457 if (fd.exec ())
458 {
459 QList<QUrl> selected = fd.selectedUrls();
460 if ( !selected.count() || !colorCells ()->saveColorCollectionAs(selected[0]) ) {
461 return false;
462 }
463
464 // We're definitely using our own color collection now.
465 deselectActionColorsKDE ();
466
467 return true;
468 }
469
470 return false;
471 }
472
473 //---------------------------------------------------------------------
474
475 // private slot
slotColorsAppendRow()476 void kpMainWindow::slotColorsAppendRow ()
477 {
478 // Call just in case.
479 toolEndShape ();
480
481 kpColorCells *colorCells = d->colorToolBar->colorCells ();
482 colorCells->appendRow ();
483 }
484
485 //---------------------------------------------------------------------
486
487 // private slot
slotColorsDeleteRow()488 void kpMainWindow::slotColorsDeleteRow ()
489 {
490 // Call just in case.
491 toolEndShape ();
492
493 kpColorCells *colorCells = d->colorToolBar->colorCells ();
494 colorCells->deleteLastRow ();
495 }
496