1 //=============================================================================
2 //
3 // File : CustomizeToolBarsDialog.cpp
4 // Creation date : Wed 01 Dec 2004 14:42:20 by Szymon Stefanek
5 //
6 // This file is part of the KVIrc IRC client distribution
7 // Copyright (C) 2004-2010 Szymon Stefanek <pragma at kvirc dot net>
8 //
9 // This program is FREE software. You can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the HOPE that it will be USEFUL,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 // See the GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program. If not, write to the Free Software Foundation,
21 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=============================================================================
24
25 #include "CustomizeToolBarsDialog.h"
26
27 #include "KviApplication.h"
28 #include "KviActionDrawer.h"
29 #include "KviLocale.h"
30 #include "KviMainWindow.h"
31 #include "KviIconManager.h"
32 #include "KviActionManager.h"
33 #include "KviCustomToolBar.h"
34 #include "KviCustomToolBarManager.h"
35 #include "KviCustomToolBarDescriptor.h"
36 #include "KviImageDialog.h"
37 #include "KviFileUtils.h"
38 #include "KviFileDialog.h"
39 #include "KviInternalCommand.h"
40 #include "KviKvsUserAction.h"
41 #include "KviTalToolTip.h"
42 #include "kvi_fileextensions.h"
43
44 #include <QPushButton>
45 #include <QLayout>
46 #include <QApplication>
47 #include <QLineEdit>
48 #include <QLabel>
49 #include <QMessageBox>
50 #include <QFrame>
51 #include <QDir>
52 #include <QTimer>
53 #include <QEvent>
54 #include <QSplitter>
55 #include <QDropEvent>
56 #include <QDesktopWidget>
57 #include <QMimeData>
58
59 CustomizeToolBarsDialog * CustomizeToolBarsDialog::m_pInstance = nullptr;
60 extern QRect g_rectToolBarEditorDialogGeometry;
61
TrashcanLabel(QWidget * p)62 TrashcanLabel::TrashcanLabel(QWidget * p)
63 : QLabel(p)
64 {
65 setPixmap(*(g_pIconManager->getBigIcon("kvi_bigicon_trashcan.png")));
66 KviTalToolTip::add(this, __tr2qs_ctx("Drop here the icons from the toolbars to remove them", "editor"));
67 setFrameStyle(QFrame::Sunken | QFrame::WinPanel);
68 setAcceptDrops(true);
69 setAlignment(Qt::AlignCenter);
70 setMinimumSize(40, 40);
71 m_uFlashCount = 0;
72 m_pFlashTimer = nullptr;
73 m_clrOriginal = palette().color(backgroundRole());
74 setAutoFillBackground(true); //needed for flashing
75 connect(KviActionManager::instance(), SIGNAL(removeActionsHintRequest()), this, SLOT(flash()));
76 }
77
~TrashcanLabel()78 TrashcanLabel::~TrashcanLabel()
79 {
80 if(m_pFlashTimer)
81 {
82 m_pFlashTimer->stop();
83 delete m_pFlashTimer;
84 }
85 }
86
flash()87 void TrashcanLabel::flash()
88 {
89 m_uFlashCount = 0;
90 if(m_pFlashTimer)
91 return;
92 m_pFlashTimer = new QTimer();
93 connect(m_pFlashTimer, SIGNAL(timeout()), this, SLOT(heartbeat()));
94 m_pFlashTimer->start(200);
95 }
96
heartbeat()97 void TrashcanLabel::heartbeat()
98 {
99 m_uFlashCount++;
100 if(m_uFlashCount % 2)
101 {
102 QPalette p = palette();
103 p.setColor(backgroundRole(), QColor(0, 0, 0));
104 setPalette(p);
105 }
106 else
107 {
108 QPalette p = palette();
109 p.setColor(backgroundRole(), m_clrOriginal);
110 setPalette(p);
111 }
112 update();
113 if(m_uFlashCount == 8)
114 {
115 m_pFlashTimer->stop();
116 delete m_pFlashTimer;
117 m_pFlashTimer = nullptr;
118 }
119 }
120
dropEvent(QDropEvent * e)121 void TrashcanLabel::dropEvent(QDropEvent * e)
122 {
123 if(e->mimeData()->hasText())
124 e->acceptProposedAction();
125 }
126
dragEnterEvent(QDragEnterEvent * e)127 void TrashcanLabel::dragEnterEvent(QDragEnterEvent * e)
128 {
129 if(e->mimeData()->hasText())
130 e->acceptProposedAction();
131 }
132
CustomToolBarPropertiesDialog(QWidget * p,const QString & szText,const QString & szId,const QString & szLabel,const QString & szIconId)133 CustomToolBarPropertiesDialog::CustomToolBarPropertiesDialog(QWidget * p, const QString & szText, const QString & szId, const QString & szLabel, const QString & szIconId)
134 : QDialog(p)
135 {
136 m_szId = szId;
137 m_szOriginalId = szId;
138 m_szLabel = szLabel;
139
140 setWindowTitle(__tr2qs_ctx("Toolbar Properties - KVIrc", "editor"));
141 setWindowIcon(QIcon(*(g_pIconManager->getSmallIcon(KviIconManager::ToolBarEditor))));
142 setModal(true);
143
144 QGridLayout * g = new QGridLayout(this);
145
146 QLabel * l = new QLabel(szText, this);
147 g->addWidget(l, 0, 0, 1, 6);
148
149 l = new QLabel(__tr2qs_ctx("Label", "editor") + ":", this);
150 g->addWidget(l, 1, 0);
151
152 m_pLabelEdit = new QLineEdit(this);
153 g->addWidget(m_pLabelEdit, 1, 1, 1, 5);
154 m_pLabelEdit->setText(szLabel);
155 connect(m_pLabelEdit, SIGNAL(textChanged(const QString &)), this, SLOT(labelTextChanged(const QString &)));
156
157 l = new QLabel(__tr2qs_ctx("Icon", "editor") + ":", this);
158 g->addWidget(l, 2, 0);
159
160 m_pIconEdit = new QLineEdit(this);
161 m_pIconEdit->setReadOnly(true);
162 g->addWidget(m_pIconEdit, 2, 1, 1, 4);
163
164 m_pIconButton = new QPushButton(this);
165 g->addWidget(m_pIconButton, 2, 5, 1, 1);
166 connect(m_pIconButton, SIGNAL(clicked()), this, SLOT(iconButtonClicked()));
167
168 iconSelected(szIconId);
169
170 m_pAdvanced = new QWidget(this);
171 QGridLayout * ag = new QGridLayout(m_pAdvanced);
172
173 l = new QLabel(__tr2qs_ctx("ID", "editor") + ":", m_pAdvanced);
174 l->setMinimumWidth(100);
175 ag->addWidget(l, 0, 0);
176
177 m_pIdEdit = new QLineEdit(m_pAdvanced);
178 ag->addWidget(m_pIdEdit, 0, 1);
179 ag->setRowStretch(0, 1);
180
181 m_pIdEdit->setText(szId);
182
183 g->addWidget(m_pAdvanced, 3, 0, 1, 6);
184 m_pAdvanced->hide();
185
186 m_pLabelEdit->setFocus();
187
188 QPushButton * pb = new QPushButton(__tr2qs_ctx("OK", "editor"), this);
189 connect(pb, SIGNAL(clicked()), this, SLOT(okClicked()));
190 pb->setMinimumWidth(80);
191 g->addWidget(pb, 4, 4, 1, 2);
192
193 pb = new QPushButton(__tr2qs_ctx("Cancel", "editor"), this);
194 connect(pb, SIGNAL(clicked()), this, SLOT(reject()));
195 pb->setMinimumWidth(80);
196 g->addWidget(pb, 4, 3);
197
198 m_pAdvancedButton = new QPushButton(__tr2qs_ctx("Advanced...", "editor"), this);
199 connect(m_pAdvancedButton, SIGNAL(clicked()), this, SLOT(advancedClicked()));
200 m_pAdvancedButton->setMinimumWidth(110);
201 g->addWidget(m_pAdvancedButton, 4, 0, 1, 2);
202
203 g->setRowStretch(0, 1);
204 g->setColumnStretch(2, 1);
205 }
206
207 CustomToolBarPropertiesDialog::~CustomToolBarPropertiesDialog()
208 = default;
209
iconSelected(const QString & szIconId)210 void CustomToolBarPropertiesDialog::iconSelected(const QString & szIconId)
211 {
212 QPixmap * pix = g_pIconManager->getImage(szIconId);
213
214 if(pix)
215 {
216 m_pIconButton->setIcon(QIcon(*pix));
217 m_szIconId = szIconId;
218 m_pIconEdit->setText(szIconId);
219 }
220 else
221 {
222 m_pIconButton->setText(__tr2qs("&Browse..."));
223 m_szIconId = "";
224 m_pIconEdit->setText("");
225 }
226 }
227
iconButtonClicked()228 void CustomToolBarPropertiesDialog::iconButtonClicked()
229 {
230 KviImageDialog * dlg = new KviImageDialog(this, __tr2qs_ctx("Choose a Toolbar Icon - KVIrc", "editor"));
231 if(dlg->exec() != QDialog::Accepted)
232 {
233 delete dlg;
234 return;
235 }
236 QString s = dlg->selectedImage();
237 delete dlg;
238 iconSelected(s);
239 }
240
labelTextChanged(const QString & s)241 void CustomToolBarPropertiesDialog::labelTextChanged(const QString & s)
242 {
243 if(m_szOriginalId.isEmpty())
244 {
245 QString szId = KviCustomToolBarManager::instance()->idForNewToolBar(s);
246 m_pIdEdit->setText(szId);
247 }
248 }
249
okClicked()250 void CustomToolBarPropertiesDialog::okClicked()
251 {
252 if(m_szLabel.isEmpty())
253 {
254 QMessageBox::information(this, __tr2qs_ctx("Invalid Toolbar Label - KVIrc", "editor"), __tr2qs_ctx("The toolbar label can't be empty!", "editor"), __tr2qs_ctx("OK", "editor"));
255 return;
256 }
257
258 if(m_szId.isEmpty())
259 {
260 m_szId = KviCustomToolBarManager::instance()->idForNewToolBar(m_szLabel);
261 }
262
263 if(KviCustomToolBarManager::instance()->find(m_szId))
264 {
265 if(m_szId != m_szOriginalId)
266 {
267 if(QMessageBox::information(this, __tr2qs_ctx("Duplicate Toolbar ID - KVIrc", "editor"),
268 __tr2qs_ctx("The specified toolbar ID already exists.<br>"
269 "Would you like KVIrc to assign it automatically (so it doesn't "
270 "collide with any other toolbar) or you prefer to do it manually?", "editor"),
271 __tr2qs_ctx("Manually", "editor"), __tr2qs_ctx("Automatically", "editor")) == 0)
272 return;
273 m_szId = KviCustomToolBarManager::instance()->idForNewToolBar(m_szLabel);
274 }
275 }
276
277 m_szId = m_pIdEdit->text();
278 m_szLabel = m_pLabelEdit->text();
279 accept();
280 }
281
advancedClicked()282 void CustomToolBarPropertiesDialog::advancedClicked()
283 {
284 if(m_pAdvanced->isVisible())
285 {
286 m_pAdvanced->hide();
287 m_pAdvancedButton->setText(__tr2qs_ctx("Advanced...", "editor"));
288 }
289 else
290 {
291 m_pAdvanced->show();
292 m_pAdvancedButton->setText(__tr2qs_ctx("Hide Advanced", "editor"));
293 }
294 }
295
CustomizeToolBarsDialog(QWidget * p)296 CustomizeToolBarsDialog::CustomizeToolBarsDialog(QWidget * p)
297 : QWidget(p)
298 {
299 setObjectName("Toolbar_editor");
300 setWindowTitle(__tr2qs_ctx("Customize Toolbars - KVIrc", "editor"));
301 setWindowIcon(*(g_pIconManager->getSmallIcon(KviIconManager::ToolBarEditor)));
302
303 m_pInstance = this;
304
305 QGridLayout * g = new QGridLayout(this);
306 m_pDrawer = new KviActionDrawer(this);
307 g->addWidget(m_pDrawer, 0, 0, 7, 1);
308
309 QPushButton * b = new QPushButton(__tr2qs_ctx("New Toolbar", "editor"), this);
310 connect(b, SIGNAL(clicked()), this, SLOT(newToolBar()));
311 g->addWidget(b, 0, 1);
312
313 m_pDeleteToolBarButton = new QPushButton(__tr2qs_ctx("Delete Toolbar", "editor"), this);
314 connect(m_pDeleteToolBarButton, SIGNAL(clicked()), this, SLOT(deleteToolBar()));
315 g->addWidget(m_pDeleteToolBarButton, 1, 1);
316
317 m_pRenameToolBarButton = new QPushButton(__tr2qs_ctx("Edit Toolbar", "editor"), this);
318 connect(m_pRenameToolBarButton, SIGNAL(clicked()), this, SLOT(renameToolBar()));
319 g->addWidget(m_pRenameToolBarButton, 2, 1);
320
321 QFrame * f = new QFrame(this);
322 f->setFrameStyle(QFrame::HLine | QFrame::Sunken);
323 g->addWidget(f, 3, 1);
324
325 m_pExportToolBarButton = new QPushButton(__tr2qs_ctx("Export Toolbar", "editor"), this);
326 connect(m_pExportToolBarButton, SIGNAL(clicked()), this, SLOT(exportToolBar()));
327 g->addWidget(m_pExportToolBarButton, 4, 1);
328
329 m_pImportToolBarButton = new QPushButton(__tr2qs_ctx("Import Toolbar", "editor"), this);
330 connect(m_pImportToolBarButton, SIGNAL(clicked()), this, SLOT(importToolBar()));
331 g->addWidget(m_pImportToolBarButton, 5, 1);
332
333 TrashcanLabel * t = new TrashcanLabel(this);
334 g->addWidget(t, 7, 1);
335
336 b = new QPushButton(__tr2qs_ctx("Close","editor"),this);
337 connect(b,SIGNAL(clicked()), this, SLOT(closeClicked()));
338 g->addWidget(b, 8, 1);
339
340 g->setRowStretch(6, 1);
341 g->setColumnStretch(0, 1);
342
343 m_pDrawer->fill();
344
345 connect(KviActionManager::instance(), SIGNAL(currentToolBarChanged()), this, SLOT(currentToolBarChanged()));
346 KviActionManager::instance()->customizeToolBarsDialogCreated();
347
348 currentToolBarChanged();
349
350 if(g_rectToolBarEditorDialogGeometry.y() < 5)
351 {
352 g_rectToolBarEditorDialogGeometry.setY(5);
353 }
354
355 resize(g_rectToolBarEditorDialogGeometry.width(),
356 g_rectToolBarEditorDialogGeometry.height());
357 move(g_rectToolBarEditorDialogGeometry.x(),
358 g_rectToolBarEditorDialogGeometry.y());
359
360 new QShortcut(Qt::Key_Escape, this, SLOT(closeClicked()));
361 }
362
~CustomizeToolBarsDialog()363 CustomizeToolBarsDialog::~CustomizeToolBarsDialog()
364 {
365 g_rectToolBarEditorDialogGeometry = QRect(pos().x(), pos().y(), size().width(), size().height());
366
367 KviActionManager::instance()->customizeToolBarsDialogDestroyed();
368 m_pInstance = nullptr;
369 }
370
currentToolBarChanged()371 void CustomizeToolBarsDialog::currentToolBarChanged()
372 {
373 m_pDeleteToolBarButton->setEnabled(KviActionManager::instance()->currentToolBar());
374 m_pRenameToolBarButton->setEnabled(KviActionManager::instance()->currentToolBar());
375 }
376
showEvent(QShowEvent * e)377 void CustomizeToolBarsDialog::showEvent(QShowEvent * e)
378 {
379 QRect rect = g_pApp->desktop()->screenGeometry(g_pMainWindow);
380 move(rect.x() + ((rect.width() - width()) / 2), rect.y() + ((rect.height() - height()) / 2));
381
382 QWidget::showEvent(e);
383 }
384
deleteToolBar()385 void CustomizeToolBarsDialog::deleteToolBar()
386 {
387 KviCustomToolBar * t = KviActionManager::currentToolBar();
388 if(!t)
389 return;
390 if(QMessageBox::question(this,
391 __tr2qs_ctx("Confirm Toolbar Deletion - KVIrc", "editor"),
392 __tr2qs_ctx("Do you really want to delete toolbar \"%1\"?", "editor").arg(t->windowTitle()),
393 QMessageBox::Yes | QMessageBox::No,
394 QMessageBox::No)
395 != QMessageBox::Yes)
396 return;
397 KviCustomToolBarManager::instance()->destroyDescriptor(t->descriptor()->id());
398 }
399
exportToolBar()400 void CustomizeToolBarsDialog::exportToolBar()
401 {
402 KviCustomToolBar * t = KviActionManager::currentToolBar();
403 if(!t)
404 return;
405
406 QString szName = QDir::homePath();
407 if(!szName.endsWith(QString(KVI_PATH_SEPARATOR)))
408 szName += KVI_PATH_SEPARATOR;
409 szName += t->descriptor()->id();
410 szName += ".kvs";
411
412 QString szFile;
413
414 if(!KviFileDialog::askForSaveFileName(szFile, __tr2qs_ctx("Enter a Filename - KVIrc", "editor"), szName, KVI_FILTER_SCRIPT, true, true, true, this))
415 return;
416
417 QString szCode;
418
419 int ret = QMessageBox::question(this,
420 __tr2qs_ctx("Confirm Toolbar Export - KVIrc", "editor"),
421 __tr2qs_ctx("Do you want the associated actions to be exported with the toolbar?", "editor"),
422 __tr2qs_ctx("Yes", "editor"),
423 __tr2qs_ctx("No", "editor"),
424 __tr2qs_ctx("Cancel", "editor"));
425
426 if(ret == 2)
427 return;
428
429 bool bExportActions = ret == 0;
430
431 if(bExportActions)
432 {
433 KviPointerList<QString> * a = t->descriptor()->actions();
434 if(a)
435 {
436 for(QString * s = a->first(); s; s = a->next())
437 {
438 KviAction * act = KviActionManager::instance()->getAction(*s);
439 if(act)
440 {
441 if(act->isKviUserActionNeverOverrideThis())
442 {
443 ((KviKvsUserAction *)act)->exportToKvs(szCode);
444 szCode += "\n\n";
445 }
446 }
447 }
448 }
449 }
450
451 szCode += "toolbar.create ";
452 szCode += t->descriptor()->id();
453 szCode += " ";
454 szCode += t->descriptor()->labelCode();
455 szCode += " ";
456 szCode += t->descriptor()->iconId();
457 szCode += "\n";
458
459 KviPointerList<QString> * aa = t->descriptor()->actions();
460 if(aa)
461 {
462 for(QString * ss = aa->first(); ss; ss = aa->next())
463 {
464 szCode += "toolbar.additem ";
465 szCode += t->descriptor()->id();
466 szCode += " ";
467 szCode += *ss;
468 szCode += "\n";
469 }
470 }
471
472 szCode += "toolbar.show ";
473 szCode += t->descriptor()->id();
474 szCode += "\n";
475
476 if(!KviFileUtils::writeFile(szFile, szCode))
477 {
478 QMessageBox::warning(this, __tr2qs_ctx("Write to Toolbar File Failed - KVIrc", "editor"), __tr2qs_ctx("Unable to write to the toolbar file.", "editor"), __tr2qs_ctx("OK", "editor"));
479 }
480 }
481
importToolBar()482 void CustomizeToolBarsDialog::importToolBar()
483 {
484 g_pMainWindow->executeInternalCommand(KVI_INTERNALCOMMAND_EXECUTE_SCRIPT_FROM_DISK);
485 }
486
renameToolBar()487 void CustomizeToolBarsDialog::renameToolBar()
488 {
489 KviCustomToolBar * t = KviActionManager::currentToolBar();
490 if(!t)
491 return;
492
493 CustomToolBarPropertiesDialog * dlg = new CustomToolBarPropertiesDialog(this,
494 __tr2qs_ctx("Please specify the properties for the toolbar \"%1\"", "editor").arg(t->windowTitle()),
495 t->descriptor()->id(),
496 t->descriptor()->labelCode(),
497 t->descriptor()->iconId());
498
499 dlg->show();
500 if(dlg->exec() != QDialog::Accepted)
501 {
502 delete dlg;
503 return;
504 }
505
506 QString id = dlg->id();
507 QString label = dlg->label();
508 QString icon = dlg->iconId();
509 delete dlg;
510
511 if((id == t->descriptor()->id()) && (label == t->descriptor()->labelCode()) && (icon == t->descriptor()->iconId()))
512 return;
513
514 KviCustomToolBarManager::instance()->renameDescriptor(t->descriptor()->id(), id, label);
515 t->descriptor()->setIconId(icon);
516 }
517
newToolBar()518 void CustomizeToolBarsDialog::newToolBar()
519 {
520 CustomToolBarPropertiesDialog * dlg = new CustomToolBarPropertiesDialog(this,
521 __tr2qs_ctx("Please specify the properties for the new toolbar", "editor"),
522 KviCustomToolBarManager::instance()->idForNewToolBar(__tr2qs_ctx("My Toolbar", "editor")),
523 __tr2qs_ctx("My Toolbar", "editor"));
524
525 dlg->show();
526 if(dlg->exec() != QDialog::Accepted)
527 {
528 delete dlg;
529 return;
530 }
531
532 QString id = dlg->id();
533 QString label = dlg->label();
534 QString icon = dlg->iconId();
535 delete dlg;
536
537 KviCustomToolBarDescriptor * d = KviCustomToolBarManager::instance()->create(id, label);
538 d->setIconId(icon);
539 KviCustomToolBar * t = d->createToolBar();
540 KviActionManager::instance()->setCurrentToolBar(t);
541 }
542
closeClicked()543 void CustomizeToolBarsDialog::closeClicked()
544 {
545 delete this;
546 }
547
cleanup()548 void CustomizeToolBarsDialog::cleanup()
549 {
550 if(!m_pInstance)
551 return;
552 delete m_pInstance;
553 m_pInstance = nullptr;
554 }
555
display(bool bTopLevel)556 void CustomizeToolBarsDialog::display(bool bTopLevel)
557 {
558 if(m_pInstance)
559 {
560 if(bTopLevel)
561 {
562 if(m_pInstance->parent())
563 {
564 m_pInstance->setParent(nullptr);
565 }
566 }
567 else
568 {
569 if(m_pInstance->parent() != g_pMainWindow->splitter())
570 {
571 m_pInstance->setParent(g_pMainWindow->splitter());
572 }
573 }
574 }
575 else
576 {
577 if(bTopLevel)
578 {
579 m_pInstance = new CustomizeToolBarsDialog(nullptr);
580 }
581 else
582 {
583 m_pInstance = new CustomizeToolBarsDialog(g_pMainWindow->splitter());
584 }
585 }
586 m_pInstance->show();
587 m_pInstance->raise();
588 m_pInstance->setFocus();
589 }
590
closeEvent(QCloseEvent * e)591 void CustomizeToolBarsDialog::closeEvent(QCloseEvent * e)
592 {
593 e->ignore();
594 delete this;
595 }
596
reject()597 void CustomizeToolBarsDialog::reject()
598 {
599 cleanup();
600 }
601