1 //=============================================================================
2 //
3 // File : PopupEditorWindow.cpp
4 // Creation date : Mon Dec 23 2002 20:28:18 by Szymon Stefanek
5 //
6 // This file is part of the KVIrc IRC client distribution
7 // Copyright (C) 2002-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 "PopupEditorWindow.h"
26
27 #include "KviIconManager.h"
28 #include "KviOptions.h"
29 #include "KviLocale.h"
30 #include "KviImageDialog.h"
31 #include "KviConfigurationFile.h"
32 #include "KviFileDialog.h"
33 #include "KviFileUtils.h"
34 #include "KviScriptEditor.h"
35 #include "kvi_debug.h"
36 #include "KviApplication.h"
37 #include "KviKvsPopupManager.h"
38 #include "KviKvsPopupMenu.h"
39 #include "KviKvsVariantList.h"
40 #include "KviPointerHashTable.h"
41 #include "KviTalVBox.h"
42 #include "kvi_fileextensions.h"
43
44 #include <QMessageBox>
45 #include <QDir>
46 #include <QHeaderView>
47 #include <QSplitter>
48 #include <QLayout>
49 #include <QLabel>
50 #include <QToolTip>
51 #include <QPushButton>
52 #include <QAbstractItemView>
53
54 extern PopupEditorWindow * g_pPopupEditorWindow;
55
56 //KviPopupEntryItem
PopupTreeWidgetItem(QTreeWidget * pTreeWidget,PopupTreeWidgetItem * after,Type t)57 PopupTreeWidgetItem::PopupTreeWidgetItem(QTreeWidget * pTreeWidget, PopupTreeWidgetItem * after, Type t)
58 : QTreeWidgetItem(pTreeWidget, after), m_type(t)
59 {
60 init();
61 }
62
PopupTreeWidgetItem(PopupTreeWidgetItem * parent,PopupTreeWidgetItem * after,Type t)63 PopupTreeWidgetItem::PopupTreeWidgetItem(PopupTreeWidgetItem * parent, PopupTreeWidgetItem * after, Type t)
64 : QTreeWidgetItem(parent, after), m_type(t)
65 {
66 init();
67 }
68
init()69 void PopupTreeWidgetItem::init()
70 {
71 switch(m_type)
72 {
73 case Item:
74 setText(1, __tr2qs_ctx("Item", "editor"));
75 break;
76 case Menu:
77 setText(1, __tr2qs_ctx("Submenu", "editor"));
78 break;
79 case ExtMenu:
80 setText(1, __tr2qs_ctx("External Menu", "editor"));
81 break;
82 case Separator:
83 setText(0, "-----------------------");
84 setText(1, __tr2qs_ctx("Separator", "editor"));
85 break;
86 case Label:
87 setText(1, __tr2qs_ctx("Label", "editor"));
88 break;
89 case Epilogue:
90 setText(0, __tr2qs_ctx("### Epilogue ###", "editor"));
91 setText(1, __tr2qs_ctx("Epilogue", "editor"));
92 break;
93 case Prologue:
94 setText(0, __tr2qs_ctx("### Prologue ###", "editor"));
95 setText(1, __tr2qs_ctx("Prologue", "editor"));
96 break;
97 default:
98 break;
99 }
100 }
101
setItemText(const QString & szText)102 void PopupTreeWidgetItem::setItemText(const QString & szText)
103 {
104 switch(m_type)
105 {
106 case Item:
107 case Menu:
108 case Label:
109 case ExtMenu:
110 m_szText = szText;
111 setText(0, szText);
112 break;
113 default:
114 break;
115 }
116 }
117
setCondition(const QString & szCondition)118 void PopupTreeWidgetItem::setCondition(const QString & szCondition)
119 {
120 switch(m_type)
121 {
122 case Item:
123 case Menu:
124 case Label:
125 case ExtMenu:
126 case Separator:
127 m_szCondition = szCondition;
128 break;
129 default:
130 break;
131 }
132 }
133
setCode(const QString & szCode)134 void PopupTreeWidgetItem::setCode(const QString & szCode)
135 {
136 switch(m_type)
137 {
138 case Item:
139 case Epilogue:
140 case Prologue:
141 case ExtMenu:
142 m_szCode = szCode;
143 break;
144 default:
145 break;
146 }
147 }
148
setId(const QString & szId)149 void PopupTreeWidgetItem::setId(const QString & szId)
150 {
151 m_szId = szId;
152 }
153
setIcon(const QString & szIcon)154 void PopupTreeWidgetItem::setIcon(const QString & szIcon)
155 {
156 switch(m_type)
157 {
158 case Item:
159 case Menu:
160 case Label:
161 case ExtMenu:
162 m_szIcon = szIcon;
163 {
164 QPixmap * pix = g_pIconManager->getImage(szIcon);
165 if(pix)
166 QTreeWidgetItem::setIcon(0, QIcon(*pix));
167 else
168 QTreeWidgetItem::setIcon(0, QIcon());
169 }
170 break;
171 default:
172 break;
173 }
174 }
175
SinglePopupEditor(QWidget * par)176 SinglePopupEditor::SinglePopupEditor(QWidget * par)
177 : QWidget(par)
178 {
179 m_pLastSelectedItem = nullptr;
180 m_pContextPopup = new QMenu(this);
181 m_pClipboard = nullptr;
182 m_pTestPopup = nullptr;
183
184 QGridLayout * g = new QGridLayout(this);
185 g->setMargin(0);
186 g->setSpacing(2);
187
188 m_pNameEditor = new QLineEdit(this);
189 m_pNameEditor->setToolTip(__tr2qs_ctx("Popup name", "editor"));
190
191 g->addWidget(m_pNameEditor, 0, 0, 1, 2);
192
193 m_pMenuButton = new QPushButton(__tr2qs_ctx("Test", "editor"), this);
194 g->addWidget(m_pMenuButton, 0, 2);
195 connect(m_pMenuButton, SIGNAL(clicked()), this, SLOT(testPopup()));
196 QSplitter * spl = new QSplitter(Qt::Vertical, this);
197 spl->setObjectName("popupeditor_vertical_splitter");
198 spl->setChildrenCollapsible(false);
199
200 m_pTreeWidget = new QTreeWidget(spl);
201 m_pTreeWidget->setColumnCount(2);
202 QStringList labels;
203 labels << __tr2qs_ctx("Item", "editor") << __tr2qs_ctx("Type", "editor");
204 m_pTreeWidget->setHeaderLabels(labels);
205 m_pTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
206 m_pTreeWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
207 m_pTreeWidget->setAllColumnsShowFocus(true);
208 m_pTreeWidget->setRootIsDecorated(true);
209 m_pTreeWidget->header()->setSortIndicatorShown(false);
210 m_pTreeWidget->setSortingEnabled(false);
211 m_pTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
212
213 connect(m_pTreeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged()));
214 connect(m_pTreeWidget, SIGNAL(customContextMenuRequested(const QPoint &)),
215 this, SLOT(customContextMenuRequested(const QPoint &)));
216
217 m_pEditor = KviScriptEditor::createInstance(spl);
218
219 g->addWidget(spl, 1, 0, 1, 3);
220
221 QLabel * l = new QLabel(__tr2qs_ctx("Text:", "editor"), this);
222 g->addWidget(l, 2, 0);
223
224 m_pTextEditor = new QLineEdit(this);
225 m_pTextEditor->setToolTip(
226 __tr2qs_ctx("<b>Visible text</b><br>May contain identifiers that will be evaluated at popup call time.<br>For labels, this text can contain also limited HTML tags.", "editor"));
227 g->addWidget(m_pTextEditor, 2, 1, 1, 2);
228
229 l = new QLabel(__tr2qs_ctx("Condition:", "editor"), this);
230 l->setMargin(2);
231 g->addWidget(l, 3, 0);
232
233 m_pConditionEditor = new QLineEdit(this);
234 m_pConditionEditor->setToolTip(
235 __tr2qs_ctx("<b>Boolean condition</b><br>Will be evaluated at popup call time in order to decide if this entry has to be shown.<br>An empty condition evaluates to true.", "editor"));
236 g->addWidget(m_pConditionEditor, 3, 1, 1, 2);
237
238 l = new QLabel(__tr2qs_ctx("Icon:", "editor"), this);
239 l->setMargin(2);
240 g->addWidget(l, 4, 0);
241
242 m_pIconEditor = new QLineEdit(this);
243 m_pIconEditor->setToolTip(
244 __tr2qs_ctx("<b>Icon identifier</b><br>May be an internal icon ID, an absolute path or a relative path.<br>Portable scripts should never use absolute paths.", "editor"));
245 g->addWidget(m_pIconEditor, 4, 1, 1, 2);
246
247 l = new QLabel(__tr2qs_ctx("External menu:", "editor"), this);
248 l->setMargin(2);
249 g->addWidget(l, 5, 0);
250
251 m_pExtNameEditor = new QLineEdit(this);
252 m_pExtNameEditor->setToolTip(
253 __tr2qs_ctx("<b>External menu name</b><br>This allows one to nest externally defined popup menus. The popup menu with the specified name will be looked up at menu setup time.", "editor"));
254 g->addWidget(m_pExtNameEditor, 5, 1, 1, 2);
255
256 l = new QLabel(__tr2qs_ctx("Item ID:", "editor"), this);
257 l->setMargin(2);
258 g->addWidget(l, 6, 0);
259
260 m_pIdEditor = new QLineEdit(this);
261 m_pIdEditor->setToolTip(
262 __tr2qs_ctx("<b>Item ID</b><br>This will allow you to use delpopupitem later.", "editor"));
263 g->addWidget(m_pIdEditor, 6, 1, 1, 2);
264 g->setColumnStretch(1, 1);
265 g->setRowStretch(1, 1);
266 }
267
~SinglePopupEditor()268 SinglePopupEditor::~SinglePopupEditor()
269 {
270 delete m_pClipboard;
271 delete m_pTestPopup;
272 KviScriptEditor::destroyInstance(m_pEditor);
273 }
274
testPopup()275 void SinglePopupEditor::testPopup()
276 {
277
278 if(m_pTestPopup)
279 delete m_pTestPopup;
280 m_pTestPopup = getMenu();
281 if(!m_pTestPopup)
282 return;
283 connect(m_pTestPopup, SIGNAL(testModeItemClicked(KviKvsPopupMenuItem *)), this, SLOT(testModeMenuItemClicked(KviKvsPopupMenuItem *)));
284 QPoint pnt = m_pMenuButton->mapToGlobal(QPoint(0, m_pMenuButton->height()));
285 KviKvsVariantList * parms = new KviKvsVariantList();
286 parms->append(new KviKvsVariant(QString("test1")));
287 parms->append(new KviKvsVariant(QString("test2")));
288 parms->append(new KviKvsVariant(QString("test3")));
289 parms->append(new KviKvsVariant(QString("test4")));
290 m_pTestPopup->doPopup(pnt, g_pActiveWindow, parms, true);
291 }
292
findMatchingItem(KviKvsPopupMenuItem * it,PopupTreeWidgetItem * item)293 PopupTreeWidgetItem * SinglePopupEditor::findMatchingItem(KviKvsPopupMenuItem * it, PopupTreeWidgetItem * item)
294 {
295
296 if(it->type() != KviKvsPopupMenuItem::Item)
297 goto not_this_one;
298 if(item->m_type != PopupTreeWidgetItem::Item)
299 goto not_this_one;
300 if(it->name() != item->m_szId)
301 goto not_this_one;
302 if(it->kvsText())
303 {
304 if(it->kvsText()->code() != item->m_szText)
305 goto not_this_one;
306 }
307 else
308 {
309 if(!item->m_szText.isEmpty())
310 goto not_this_one;
311 }
312 if(it->kvsCode())
313 {
314 if(it->kvsCode()->code() != item->m_szCode)
315 goto not_this_one;
316 }
317 else
318 {
319 if(!item->m_szCode.isEmpty())
320 goto not_this_one;
321 }
322 if(it->kvsIcon())
323 {
324 if(it->kvsIcon()->code() != item->m_szIcon)
325 goto not_this_one;
326 }
327 else
328 {
329 if(!item->m_szIcon.isEmpty())
330 goto not_this_one;
331 }
332 if(it->kvsCondition())
333 {
334 if(it->kvsCondition()->code() != item->m_szCondition)
335 goto not_this_one;
336 }
337 else
338 {
339 if(!item->m_szCondition.isEmpty())
340 goto not_this_one;
341 }
342
343 return item;
344
345 not_this_one:
346 int count = item->childCount();
347 for(int i = 0; i < count; i++)
348 {
349 PopupTreeWidgetItem * testItem = (PopupTreeWidgetItem *)item->child(i);
350 KVI_ASSERT(testItem);
351 PopupTreeWidgetItem * found = findMatchingItem(it, testItem);
352 if(found)
353 return found;
354 }
355
356 return nullptr;
357 }
358
testModeMenuItemClicked(KviKvsPopupMenuItem * it)359 void SinglePopupEditor::testModeMenuItemClicked(KviKvsPopupMenuItem * it)
360 {
361
362 saveLastSelectedItem(); // that's the first thingie
363 // find the matching item and set it as current
364 int count = m_pTreeWidget->topLevelItemCount();
365 for(int i = 0; i < count; i++)
366 {
367 PopupTreeWidgetItem * item = (PopupTreeWidgetItem *)m_pTreeWidget->topLevelItem(i);
368 PopupTreeWidgetItem * found = findMatchingItem(it, item);
369 if(found)
370 {
371 // set the item as current
372 m_pTreeWidget->scrollToItem(found);
373 m_pTreeWidget->setCurrentItem(found);
374 found->setSelected(true);
375 selectionChanged();
376 return;
377 }
378 }
379 }
380
customContextMenuRequested(const QPoint & pos)381 void SinglePopupEditor::customContextMenuRequested(const QPoint & pos)
382 {
383 QTreeWidgetItem * it = m_pTreeWidget->itemAt(pos);
384
385 m_pContextPopup->clear();
386
387 bool bIsMenu = false;
388
389 if(it)
390 {
391 bIsMenu = ((PopupTreeWidgetItem *)it)->m_type == PopupTreeWidgetItem::Menu;
392 }
393
394 m_pContextPopup->addAction(__tr2qs_ctx("New Separator Below", "editor"), this, SLOT(contextNewSeparatorBelow()));
395 m_pContextPopup->addAction(__tr2qs_ctx("New Separator Above", "editor"), this, SLOT(contextNewSeparatorAbove()))
396 ->setEnabled(it);
397 m_pContextPopup->addAction(__tr2qs_ctx("New Separator Inside", "editor"), this, SLOT(contextNewSeparatorInside()))
398 ->setEnabled(it && bIsMenu);
399
400 m_pContextPopup->addSeparator();
401
402 m_pContextPopup->addAction(__tr2qs_ctx("New Label Below", "editor"), this, SLOT(contextNewLabelBelow()));
403 m_pContextPopup->addAction(__tr2qs_ctx("New Label Above", "editor"), this, SLOT(contextNewLabelAbove()))
404 ->setEnabled(it);
405 m_pContextPopup->addAction(__tr2qs_ctx("New Label Inside", "editor"), this, SLOT(contextNewLabelInside()))
406 ->setEnabled(it && bIsMenu);
407
408 m_pContextPopup->addSeparator();
409
410 m_pContextPopup->addAction(__tr2qs_ctx("New Item Below", "editor"), this, SLOT(contextNewItemBelow()));
411 m_pContextPopup->addAction(__tr2qs_ctx("New Item Above", "editor"), this, SLOT(contextNewItemAbove()))
412 ->setEnabled(it);
413 m_pContextPopup->addAction(__tr2qs_ctx("New Item Inside", "editor"), this, SLOT(contextNewItemInside()))
414 ->setEnabled(it && bIsMenu);
415
416 m_pContextPopup->addSeparator();
417
418 m_pContextPopup->addAction(__tr2qs_ctx("New Menu Below", "editor"), this, SLOT(contextNewMenuBelow()));
419 m_pContextPopup->addAction(__tr2qs_ctx("New Menu Above", "editor"), this, SLOT(contextNewMenuAbove()))
420 ->setEnabled(it);
421 m_pContextPopup->addAction(__tr2qs_ctx("New Menu Inside", "editor"), this, SLOT(contextNewMenuInside()))
422 ->setEnabled(it && bIsMenu);
423
424 m_pContextPopup->addSeparator();
425
426 m_pContextPopup->addAction(__tr2qs_ctx("New External Menu Below", "editor"), this, SLOT(contextNewExtMenuBelow()));
427 m_pContextPopup->addAction(__tr2qs_ctx("New External Menu Above", "editor"), this, SLOT(contextNewExtMenuAbove()))
428 ->setEnabled(it);
429 m_pContextPopup->addAction(__tr2qs_ctx("New External Menu Inside", "editor"), this, SLOT(contextNewExtMenuInside()))
430 ->setEnabled(it && bIsMenu);
431
432 m_pContextPopup->addSeparator();
433
434 m_pContextPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Cut)),
435 __tr2qs_ctx("Cu&t", "editor"), this, SLOT(contextCut()))
436 ->setEnabled(it);
437 m_pContextPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Copy)),
438 __tr2qs_ctx("&Copy", "editor"), this, SLOT(contextCopy()))
439 ->setEnabled(it);
440 m_pContextPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Discard)),
441 __tr2qs_ctx("Re&move", "editor"), this, SLOT(contextRemove()))
442 ->setEnabled(it);
443 m_pContextPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Paste)),
444 __tr2qs_ctx("&Paste Below", "editor"), this, SLOT(contextPasteBelow()))
445 ->setEnabled(m_pClipboard);
446 m_pContextPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Paste)),
447 __tr2qs_ctx("Paste Above", "editor"), this, SLOT(contextPasteAbove()))
448 ->setEnabled(it && m_pClipboard);
449 m_pContextPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Paste)),
450 __tr2qs_ctx("Paste Inside", "editor"), this, SLOT(contextPasteInside()))
451 ->setEnabled(it && bIsMenu && m_pClipboard);
452
453 m_pContextPopup->addSeparator();
454 m_pContextPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Prologue)),
455 __tr2qs_ctx("New Menu Prologue", "editor"), this, SLOT(contextNewPrologue()));
456
457 m_pContextPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Epilogue)),
458 __tr2qs_ctx("New Menu Epilogue", "editor"), this, SLOT(contextNewEpilogue()));
459
460 m_pContextPopup->popup(QCursor::pos());
461 }
462
createNewItemAboveLastSelected(PopupTreeWidgetItem::Type t)463 void SinglePopupEditor::createNewItemAboveLastSelected(PopupTreeWidgetItem::Type t)
464 {
465 m_pTreeWidget->setCurrentItem(newItemAbove(m_pLastSelectedItem, t));
466 }
467
createNewItemBelowLastSelected(PopupTreeWidgetItem::Type t)468 void SinglePopupEditor::createNewItemBelowLastSelected(PopupTreeWidgetItem::Type t)
469 {
470 m_pTreeWidget->setCurrentItem(newItemBelow(m_pLastSelectedItem, t));
471 }
472
createNewItemInsideLastSelected(PopupTreeWidgetItem::Type t)473 void SinglePopupEditor::createNewItemInsideLastSelected(PopupTreeWidgetItem::Type t)
474 {
475 if(m_pLastSelectedItem)
476 m_pLastSelectedItem->setExpanded(true);
477 m_pTreeWidget->setCurrentItem(newItemInside(m_pLastSelectedItem, t));
478 }
479
contextNewSeparatorAbove()480 void SinglePopupEditor::contextNewSeparatorAbove()
481 {
482 createNewItemAboveLastSelected(PopupTreeWidgetItem::Separator);
483 }
484
contextNewSeparatorBelow()485 void SinglePopupEditor::contextNewSeparatorBelow()
486 {
487 createNewItemBelowLastSelected(PopupTreeWidgetItem::Separator);
488 }
489
contextNewSeparatorInside()490 void SinglePopupEditor::contextNewSeparatorInside()
491 {
492 createNewItemInsideLastSelected(PopupTreeWidgetItem::Separator);
493 }
494
contextNewItemBelow()495 void SinglePopupEditor::contextNewItemBelow()
496 {
497 createNewItemBelowLastSelected(PopupTreeWidgetItem::Item);
498 }
499
contextNewItemAbove()500 void SinglePopupEditor::contextNewItemAbove()
501 {
502 createNewItemAboveLastSelected(PopupTreeWidgetItem::Item);
503 }
504
contextNewItemInside()505 void SinglePopupEditor::contextNewItemInside()
506 {
507 createNewItemInsideLastSelected(PopupTreeWidgetItem::Item);
508 }
509
contextNewMenuBelow()510 void SinglePopupEditor::contextNewMenuBelow()
511 {
512 createNewItemBelowLastSelected(PopupTreeWidgetItem::Menu);
513 }
514
contextNewMenuAbove()515 void SinglePopupEditor::contextNewMenuAbove()
516 {
517 createNewItemAboveLastSelected(PopupTreeWidgetItem::Menu);
518 }
519
contextNewMenuInside()520 void SinglePopupEditor::contextNewMenuInside()
521 {
522 createNewItemInsideLastSelected(PopupTreeWidgetItem::Menu);
523 }
524
contextNewExtMenuBelow()525 void SinglePopupEditor::contextNewExtMenuBelow()
526 {
527 createNewItemBelowLastSelected(PopupTreeWidgetItem::ExtMenu);
528 }
529
contextNewExtMenuAbove()530 void SinglePopupEditor::contextNewExtMenuAbove()
531 {
532 createNewItemAboveLastSelected(PopupTreeWidgetItem::ExtMenu);
533 }
contextNewExtMenuInside()534 void SinglePopupEditor::contextNewExtMenuInside()
535 {
536 createNewItemInsideLastSelected(PopupTreeWidgetItem::ExtMenu);
537 }
538
contextNewLabelBelow()539 void SinglePopupEditor::contextNewLabelBelow()
540 {
541 createNewItemBelowLastSelected(PopupTreeWidgetItem::Label);
542 }
543
contextNewLabelAbove()544 void SinglePopupEditor::contextNewLabelAbove()
545 {
546 createNewItemAboveLastSelected(PopupTreeWidgetItem::Label);
547 }
548
contextNewLabelInside()549 void SinglePopupEditor::contextNewLabelInside()
550 {
551 createNewItemInsideLastSelected(PopupTreeWidgetItem::Label);
552 }
553
newItem(PopupTreeWidgetItem * par,PopupTreeWidgetItem * after,PopupTreeWidgetItem::Type t)554 PopupTreeWidgetItem * SinglePopupEditor::newItem(PopupTreeWidgetItem * par, PopupTreeWidgetItem * after, PopupTreeWidgetItem::Type t)
555 {
556 if(par)
557 return new PopupTreeWidgetItem(par, after, t);
558 return new PopupTreeWidgetItem(m_pTreeWidget, after, t);
559 }
560
newItemBelow(PopupTreeWidgetItem * it,PopupTreeWidgetItem::Type t)561 PopupTreeWidgetItem * SinglePopupEditor::newItemBelow(PopupTreeWidgetItem * it, PopupTreeWidgetItem::Type t)
562 {
563 if(!it)
564 return newItem(nullptr, nullptr, t);
565 return newItem((PopupTreeWidgetItem *)it->parent(), it, t);
566 }
567
newItemAbove(PopupTreeWidgetItem * it,PopupTreeWidgetItem::Type t)568 PopupTreeWidgetItem * SinglePopupEditor::newItemAbove(PopupTreeWidgetItem * it, PopupTreeWidgetItem::Type t)
569 {
570 if(!it)
571 return newItem(nullptr, nullptr, t);
572 return newItem((PopupTreeWidgetItem *)it->parent(), (PopupTreeWidgetItem *)m_pTreeWidget->itemAbove(it), t);
573 }
574
newItemInside(PopupTreeWidgetItem * it,PopupTreeWidgetItem::Type t)575 PopupTreeWidgetItem * SinglePopupEditor::newItemInside(PopupTreeWidgetItem * it, PopupTreeWidgetItem::Type t)
576 {
577 if(it && it->m_type != PopupTreeWidgetItem::Menu)
578 return newItemBelow(it, t);
579 return newItem(it, it, t);
580 }
581
contextNewPrologue()582 void SinglePopupEditor::contextNewPrologue()
583 {
584 PopupTreeWidgetItem * it = m_pLastSelectedItem ? (PopupTreeWidgetItem *)m_pLastSelectedItem->parent() : nullptr;
585 m_pTreeWidget->setCurrentItem(newItem(it, it, PopupTreeWidgetItem::Prologue));
586 }
587
contextNewEpilogue()588 void SinglePopupEditor::contextNewEpilogue()
589 {
590 PopupTreeWidgetItem * it = m_pLastSelectedItem ? (PopupTreeWidgetItem *)m_pLastSelectedItem->parent() : nullptr;
591 PopupTreeWidgetItem * after = it ? (PopupTreeWidgetItem *)it->child(0) : (PopupTreeWidgetItem *)m_pTreeWidget->topLevelItem(0);
592 if(after)
593 {
594 while(m_pTreeWidget->itemAbove(after))
595 {
596 if(after->parent() == m_pTreeWidget->itemAbove(after)->parent())
597 after = (PopupTreeWidgetItem *)m_pTreeWidget->itemAbove(after);
598 }
599 }
600 else
601 {
602 after = it;
603 }
604 m_pTreeWidget->setCurrentItem(newItem(it, after, PopupTreeWidgetItem::Epilogue));
605 }
606
contextCopy()607 void SinglePopupEditor::contextCopy()
608 {
609 if(!m_pLastSelectedItem)
610 return;
611 delete m_pClipboard;
612 m_pClipboard = new KviKvsPopupMenu("clipboard");
613 addItemToMenu(m_pClipboard, m_pLastSelectedItem);
614 }
615
contextCut()616 void SinglePopupEditor::contextCut()
617 {
618 if(!m_pLastSelectedItem)
619 return;
620
621 saveLastSelectedItem();
622 contextCopy();
623
624 auto * lastSelectedCache = m_pLastSelectedItem;
625
626 m_pTreeWidget->selectionModel()->clearSelection();
627 selectionChanged();
628 delete lastSelectedCache;
629 }
630
contextRemove()631 void SinglePopupEditor::contextRemove()
632 {
633 if(!m_pLastSelectedItem)
634 return;
635
636 auto * lastSelectedCache = m_pLastSelectedItem;
637
638 m_pTreeWidget->selectionModel()->clearSelection();
639 selectionChanged();
640 delete lastSelectedCache;
641 }
642
contextPasteBelow()643 void SinglePopupEditor::contextPasteBelow()
644 {
645 if(!m_pClipboard)
646 return;
647
648 PopupTreeWidgetItem * par = m_pLastSelectedItem ? (PopupTreeWidgetItem *)m_pLastSelectedItem->parent() : nullptr;
649 populateMenu(m_pClipboard, par, m_pLastSelectedItem);
650 }
651
contextPasteAbove()652 void SinglePopupEditor::contextPasteAbove()
653 {
654 if(!m_pClipboard)
655 return;
656
657 PopupTreeWidgetItem * par = m_pLastSelectedItem ? (PopupTreeWidgetItem *)m_pLastSelectedItem->parent() : nullptr;
658 PopupTreeWidgetItem * above = m_pLastSelectedItem ? (PopupTreeWidgetItem *)m_pTreeWidget->itemAbove(m_pLastSelectedItem) : nullptr;
659 populateMenu(m_pClipboard, par, above);
660 }
661
contextPasteInside()662 void SinglePopupEditor::contextPasteInside()
663 {
664 if(!m_pClipboard)
665 return;
666
667 if(m_pLastSelectedItem)
668 {
669 if(m_pLastSelectedItem->m_type != PopupTreeWidgetItem::Menu)
670 {
671 contextPasteBelow();
672 return;
673 }
674 m_pLastSelectedItem->setExpanded(true);
675 }
676 populateMenu(m_pClipboard, m_pLastSelectedItem, nullptr);
677 }
678
saveLastSelectedItem()679 void SinglePopupEditor::saveLastSelectedItem()
680 {
681 if(!m_pLastSelectedItem)
682 return;
683
684 QString tmp;
685
686 switch(m_pLastSelectedItem->m_type)
687 {
688 case PopupTreeWidgetItem::Prologue:
689 case PopupTreeWidgetItem::Epilogue:
690 case PopupTreeWidgetItem::Item:
691 {
692 QString tmpx;
693 m_pEditor->getText(tmpx);
694 m_pLastSelectedItem->setCode(tmpx);
695 }
696 break;
697 default:
698 break;
699 }
700
701 m_pLastSelectedItem->setId(m_pIdEditor->text());
702
703 switch(m_pLastSelectedItem->m_type)
704 {
705 case PopupTreeWidgetItem::Menu:
706 case PopupTreeWidgetItem::ExtMenu:
707 case PopupTreeWidgetItem::Item:
708 m_pLastSelectedItem->setIcon(m_pIconEditor->text());
709 break;
710 default:
711 break;
712 }
713
714 switch(m_pLastSelectedItem->m_type)
715 {
716 case PopupTreeWidgetItem::Menu:
717 case PopupTreeWidgetItem::Item:
718 case PopupTreeWidgetItem::Label:
719 case PopupTreeWidgetItem::ExtMenu:
720 m_pLastSelectedItem->setItemText(m_pTextEditor->text());
721 break;
722 default:
723 break;
724 }
725
726 switch(m_pLastSelectedItem->m_type)
727 {
728 case PopupTreeWidgetItem::Menu:
729 case PopupTreeWidgetItem::Item:
730 case PopupTreeWidgetItem::Label:
731 case PopupTreeWidgetItem::ExtMenu:
732 case PopupTreeWidgetItem::Separator:
733 m_pLastSelectedItem->setCondition(m_pConditionEditor->text());
734 break;
735 default:
736 break;
737 }
738
739 if(m_pLastSelectedItem->m_type == PopupTreeWidgetItem::ExtMenu)
740 {
741 m_pLastSelectedItem->setCode(m_pExtNameEditor->text());
742 }
743 }
744
addItemToMenu(KviKvsPopupMenu * p,PopupTreeWidgetItem * it)745 void SinglePopupEditor::addItemToMenu(KviKvsPopupMenu * p, PopupTreeWidgetItem * it)
746 {
747 it->m_szId = it->m_szId.trimmed();
748 switch(it->m_type)
749 {
750 case PopupTreeWidgetItem::Prologue:
751 it->m_szCode = it->m_szCode.trimmed();
752 p->addPrologue(it->m_szId, it->m_szCode);
753 break;
754 case PopupTreeWidgetItem::Epilogue:
755 it->m_szCode = it->m_szCode.trimmed();
756 p->addEpilogue(it->m_szId, it->m_szCode);
757 break;
758 case PopupTreeWidgetItem::Separator:
759 it->m_szCondition = it->m_szCondition.trimmed();
760 p->addSeparator(it->m_szId, it->m_szCondition);
761 break;
762 case PopupTreeWidgetItem::Label:
763 it->m_szText = it->m_szText.trimmed();
764 it->m_szCondition = it->m_szCondition.trimmed();
765 it->m_szIcon = it->m_szIcon.trimmed();
766 p->addLabel(it->m_szId, it->m_szText, it->m_szIcon, it->m_szCondition);
767 break;
768 case PopupTreeWidgetItem::Item:
769 it->m_szText = it->m_szText.trimmed();
770 it->m_szIcon = it->m_szIcon.trimmed();
771 it->m_szCondition = it->m_szCondition.trimmed();
772 it->m_szCode = it->m_szCode.trimmed();
773 p->addItem(it->m_szId, it->m_szCode, it->m_szText, it->m_szIcon, it->m_szCondition);
774 break;
775 case PopupTreeWidgetItem::ExtMenu:
776 it->m_szText = it->m_szText.trimmed();
777 it->m_szIcon = it->m_szIcon.trimmed();
778 it->m_szCondition = it->m_szCondition.trimmed();
779 it->m_szCode = it->m_szCode.trimmed(); // <-- this is the ext name in fact
780 p->addExtPopup(it->m_szId, it->m_szCode, it->m_szText, it->m_szIcon, it->m_szCondition);
781 break;
782 case PopupTreeWidgetItem::Menu:
783 {
784 it->m_szText = it->m_szText.trimmed();
785 it->m_szIcon = it->m_szIcon.trimmed();
786 it->m_szCondition = it->m_szCondition.trimmed();
787 KviKvsPopupMenu * menu = p->addPopup(it->m_szId, it->m_szText, it->m_szIcon, it->m_szCondition);
788 int count = it->childCount();
789 for(int i = 0; i < count; i++)
790 {
791 addItemToMenu(menu, (PopupTreeWidgetItem *)it->child(i));
792 }
793 }
794 break;
795 default:
796 break;
797 }
798 }
799
getMenu()800 KviKvsPopupMenu * SinglePopupEditor::getMenu()
801 {
802 saveLastSelectedItem();
803
804 QString tmp = m_pNameEditor->text().trimmed();
805
806 KviKvsPopupMenu * p = new KviKvsPopupMenu(tmp);
807
808 int count = m_pTreeWidget->topLevelItemCount();
809 for(int i = 0; i < count; i++)
810 {
811 addItemToMenu(p, (PopupTreeWidgetItem *)m_pTreeWidget->topLevelItem(i));
812 }
813 return p;
814 }
815
selectionChanged()816 void SinglePopupEditor::selectionChanged()
817 {
818 saveLastSelectedItem();
819
820 bool bEditorEnabled = false;
821 bool bIconEditorEnabled = false;
822 bool bConditionEditorEnabled = false;
823 bool bTextEditorEnabled = false;
824 bool bNameEditorEnabled = false;
825
826 QTreeWidgetItem * it;
827
828 if(m_pTreeWidget->selectedItems().empty())
829 {
830 it = nullptr;
831 }
832 else
833 {
834 it = (QTreeWidgetItem *)m_pTreeWidget->selectedItems().first();
835 }
836
837 if(it)
838 {
839 m_pIdEditor->setText(((PopupTreeWidgetItem *)it)->m_szId);
840
841 switch(((PopupTreeWidgetItem *)it)->m_type)
842 {
843 case PopupTreeWidgetItem::Prologue:
844 case PopupTreeWidgetItem::Epilogue:
845 case PopupTreeWidgetItem::Item:
846 m_pEditor->setText(((PopupTreeWidgetItem *)it)->m_szCode);
847 bEditorEnabled = true;
848 break;
849 default:
850 break;
851 }
852
853 switch(((PopupTreeWidgetItem *)it)->m_type)
854 {
855 case PopupTreeWidgetItem::Menu:
856 case PopupTreeWidgetItem::Item:
857 case PopupTreeWidgetItem::Label:
858 case PopupTreeWidgetItem::ExtMenu:
859 m_pIconEditor->setText(((PopupTreeWidgetItem *)it)->m_szIcon);
860 bIconEditorEnabled = true;
861 break;
862 default:
863 break;
864 }
865
866 switch(((PopupTreeWidgetItem *)it)->m_type)
867 {
868 case PopupTreeWidgetItem::Menu:
869 case PopupTreeWidgetItem::Item:
870 case PopupTreeWidgetItem::Label:
871 case PopupTreeWidgetItem::ExtMenu:
872 m_pTextEditor->setText(((PopupTreeWidgetItem *)it)->m_szText);
873 bTextEditorEnabled = true;
874 break;
875 default:
876 break;
877 }
878
879 switch(((PopupTreeWidgetItem *)it)->m_type)
880 {
881 case PopupTreeWidgetItem::Menu:
882 case PopupTreeWidgetItem::Item:
883 case PopupTreeWidgetItem::Label:
884 case PopupTreeWidgetItem::ExtMenu:
885 case PopupTreeWidgetItem::Separator:
886 m_pConditionEditor->setText(((PopupTreeWidgetItem *)it)->m_szCondition);
887 bConditionEditorEnabled = true;
888 break;
889 default:
890 break;
891 }
892
893 if(((PopupTreeWidgetItem *)it)->m_type == PopupTreeWidgetItem::ExtMenu)
894 {
895 m_pExtNameEditor->setText(((PopupTreeWidgetItem *)it)->m_szCode);
896 bNameEditorEnabled = true;
897 }
898 }
899
900 m_pLastSelectedItem = (PopupTreeWidgetItem *)it;
901
902 if(!bEditorEnabled)
903 m_pEditor->setText("");
904 m_pEditor->setEnabled(bEditorEnabled);
905 if(!bIconEditorEnabled)
906 m_pIconEditor->setText("");
907 m_pIconEditor->setEnabled(bIconEditorEnabled);
908 if(!bConditionEditorEnabled)
909 m_pConditionEditor->setText("");
910 m_pConditionEditor->setEnabled(bConditionEditorEnabled);
911 if(!bTextEditorEnabled)
912 m_pTextEditor->setText("");
913 m_pTextEditor->setEnabled(bTextEditorEnabled);
914 m_pExtNameEditor->setEnabled(bNameEditorEnabled);
915 if(!bNameEditorEnabled)
916 m_pExtNameEditor->setText("");
917 if(!it)
918 m_pIdEditor->setText("");
919 m_pIdEditor->setEnabled(it);
920 }
921
populateMenu(KviKvsPopupMenu * pop,PopupTreeWidgetItem * par,PopupTreeWidgetItem * theItem)922 void SinglePopupEditor::populateMenu(KviKvsPopupMenu * pop, PopupTreeWidgetItem * par, PopupTreeWidgetItem * theItem)
923 {
924 if(!pop)
925 return;
926
927 for(KviKvsScript * sp = pop->prologues()->first(); sp; sp = pop->prologues()->next())
928 {
929 if(par)
930 theItem = new PopupTreeWidgetItem(par, theItem, PopupTreeWidgetItem::Prologue);
931 else
932 theItem = new PopupTreeWidgetItem(m_pTreeWidget, theItem, PopupTreeWidgetItem::Prologue);
933 theItem->setCode(sp->code());
934 theItem->setId(sp->name());
935 }
936
937 for(KviKvsPopupMenuItem * item = pop->itemList()->first(); item; item = pop->itemList()->next())
938 {
939 switch(item->type())
940 {
941 case KviKvsPopupMenuItem::Item:
942 if(par)
943 theItem = new PopupTreeWidgetItem(par, theItem, PopupTreeWidgetItem::Item);
944 else
945 theItem = new PopupTreeWidgetItem(m_pTreeWidget, theItem, PopupTreeWidgetItem::Item);
946 theItem->setIcon(item->kvsIcon() ? item->kvsIcon()->code() : QString());
947 theItem->setItemText(item->kvsText() ? item->kvsText()->code() : QString());
948 theItem->setCondition(item->kvsCondition() ? item->kvsCondition()->code() : QString());
949 theItem->setCode(item->kvsCode() ? item->kvsCode()->code() : QString());
950 theItem->setId(item->name());
951 break;
952 case KviKvsPopupMenuItem::ExtMenu:
953 if(par)
954 theItem = new PopupTreeWidgetItem(par, theItem, PopupTreeWidgetItem::ExtMenu);
955 else
956 theItem = new PopupTreeWidgetItem(m_pTreeWidget, theItem, PopupTreeWidgetItem::ExtMenu);
957 theItem->setIcon(item->kvsIcon() ? item->kvsIcon()->code() : QString());
958 theItem->setItemText(item->kvsText() ? item->kvsText()->code() : QString());
959 theItem->setCondition(item->kvsCondition() ? item->kvsCondition()->code() : QString());
960 theItem->setCode(((KviKvsPopupMenuItemExtMenu *)item)->extName());
961 theItem->setId(item->name());
962 break;
963 case KviKvsPopupMenuItem::Label:
964 if(par)
965 theItem = new PopupTreeWidgetItem(par, theItem, PopupTreeWidgetItem::Label);
966 else
967 theItem = new PopupTreeWidgetItem(m_pTreeWidget, theItem, PopupTreeWidgetItem::Label);
968 theItem->setIcon(item->kvsIcon() ? item->kvsIcon()->code() : QString());
969 theItem->setItemText(item->kvsText() ? item->kvsText()->code() : QString());
970 theItem->setCondition(item->kvsCondition() ? item->kvsCondition()->code() : QString());
971 theItem->setId(item->name());
972 break;
973 case KviKvsPopupMenuItem::Separator:
974 if(par)
975 theItem = new PopupTreeWidgetItem(par, theItem, PopupTreeWidgetItem::Separator);
976 else
977 theItem = new PopupTreeWidgetItem(m_pTreeWidget, theItem, PopupTreeWidgetItem::Separator);
978 theItem->setCondition(item->kvsCondition() ? item->kvsCondition()->code() : QString());
979 theItem->setId(item->name());
980 break;
981 case KviKvsPopupMenuItem::Menu:
982 if(par)
983 theItem = new PopupTreeWidgetItem(par, theItem, PopupTreeWidgetItem::Menu);
984 else
985 theItem = new PopupTreeWidgetItem(m_pTreeWidget, theItem, PopupTreeWidgetItem::Menu);
986 theItem->setIcon(item->kvsIcon() ? item->kvsIcon()->code() : QString());
987 theItem->setItemText(item->kvsText() ? item->kvsText()->code() : QString());
988 theItem->setCondition(item->kvsCondition() ? item->kvsCondition()->code() : QString());
989 theItem->setId(item->name());
990 populateMenu(((KviKvsPopupMenuItemMenu *)item)->menu(), theItem, nullptr);
991 break;
992 default:
993 break;
994 }
995 }
996
997 for(KviKvsScript * se = pop->epilogues()->first(); se; se = pop->epilogues()->next())
998 {
999 if(par)
1000 theItem = new PopupTreeWidgetItem(par, theItem, PopupTreeWidgetItem::Epilogue);
1001 else
1002 theItem = new PopupTreeWidgetItem(m_pTreeWidget, theItem, PopupTreeWidgetItem::Epilogue);
1003 theItem->setCode(se->code());
1004 theItem->setId(se->name());
1005 }
1006
1007 m_pTreeWidget->resizeColumnToContents(0);
1008 }
1009
edit(MenuTreeWidgetItem * it)1010 void SinglePopupEditor::edit(MenuTreeWidgetItem * it)
1011 {
1012 saveLastSelectedItem();
1013
1014 m_pLastSelectedItem = nullptr;
1015
1016 m_pTreeWidget->clear();
1017
1018 selectionChanged();
1019
1020 if(it)
1021 {
1022 m_pNameEditor->setText(it->m_pPopup->popupName());
1023 populateMenu(it->m_pPopup, nullptr, nullptr);
1024 }
1025 else
1026 {
1027 m_pIconEditor->setText("");
1028 m_pIconEditor->setEnabled(false);
1029 m_pIdEditor->setText("");
1030 m_pIdEditor->setEnabled(false);
1031 m_pConditionEditor->setText("");
1032 m_pConditionEditor->setEnabled(false);
1033 m_pTextEditor->setText("");
1034 m_pTextEditor->setEnabled(false);
1035 m_pEditor->setText("");
1036 m_pEditor->setEnabled(false);
1037 m_pNameEditor->setText("");
1038 m_pExtNameEditor->setText("");
1039 m_pExtNameEditor->setEnabled(false);
1040 }
1041 m_pTreeWidget->setEnabled(it);
1042 m_pNameEditor->setEnabled(it);
1043 m_pMenuButton->setEnabled(it);
1044 }
1045
MenuTreeWidgetItem(QTreeWidget * par,KviKvsPopupMenu * popup)1046 MenuTreeWidgetItem::MenuTreeWidgetItem(QTreeWidget * par, KviKvsPopupMenu * popup)
1047 : QTreeWidgetItem(par)
1048 {
1049 setIcon(0, *(g_pIconManager->getSmallIcon(KviIconManager::Popup)));
1050 setText(0, popup->popupName());
1051 m_pPopup = popup;
1052 }
1053
~MenuTreeWidgetItem()1054 MenuTreeWidgetItem::~MenuTreeWidgetItem()
1055 {
1056 delete m_pPopup;
1057 }
1058
replacePopup(KviKvsPopupMenu * popup)1059 void MenuTreeWidgetItem::replacePopup(KviKvsPopupMenu * popup)
1060 {
1061 delete m_pPopup;
1062 m_pPopup = popup;
1063 }
1064
PopupEditorWidget(QWidget * par)1065 PopupEditorWidget::PopupEditorWidget(QWidget * par)
1066 : QWidget(par)
1067 {
1068 m_bSaving = false;
1069
1070 QGridLayout * l = new QGridLayout(this);
1071 QSplitter * spl = new QSplitter(Qt::Horizontal, this);
1072 spl->setObjectName("popupeditor_horizontal_splitter");
1073 spl->setChildrenCollapsible(false);
1074 l->addWidget(spl, 0, 0);
1075
1076 KviTalVBox * box = new KviTalVBox(spl);
1077
1078 m_pTreeWidget = new QTreeWidget(box);
1079 m_pTreeWidget->setHeaderLabel(__tr2qs_ctx("Popup", "editor"));
1080 m_pTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
1081 m_pTreeWidget->header()->setSortIndicatorShown(true);
1082
1083 QPushButton * pb = new QPushButton(__tr2qs_ctx("&Export All to...", "editor"), box);
1084 connect(pb, SIGNAL(clicked()), this, SLOT(exportAll()));
1085 QPushButton * gn = new QPushButton(__tr2qs_ctx("&Export Selected to...", "editor"), box);
1086 connect(gn, SIGNAL(clicked()), this, SLOT(exportSelected()));
1087
1088 m_pEditor = new SinglePopupEditor(spl);
1089
1090 m_bOneTimeSetupDone = false;
1091 m_pLastEditedItem = nullptr;
1092
1093 m_pContextPopup = new QMenu(this);
1094 m_pEmptyContextPopup = new QMenu(this);
1095
1096 spl->setStretchFactor(0, 20);
1097 spl->setStretchFactor(1, 80);
1098
1099 currentItemChanged(nullptr, nullptr);
1100 }
1101
oneTimeSetup()1102 void PopupEditorWidget::oneTimeSetup()
1103 {
1104 if(m_bOneTimeSetupDone)
1105 return;
1106 m_bOneTimeSetupDone = true;
1107
1108 const KviPointerHashTable<QString, KviKvsPopupMenu> * a = KviKvsPopupManager::instance()->popupDict();
1109 if(!a)
1110 return;
1111
1112 KviPointerHashTableIterator<QString, KviKvsPopupMenu> it(*a);
1113
1114 while(it.current())
1115 {
1116 KviKvsPopupMenu * popup = it.current();
1117 KviKvsPopupMenu * copy = new KviKvsPopupMenu(popup->popupName());
1118 copy->copyFrom(popup);
1119 new MenuTreeWidgetItem(m_pTreeWidget, copy);
1120 ++it;
1121 }
1122
1123 m_pTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
1124 connect(m_pTreeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
1125 connect(m_pTreeWidget, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(customContextMenuRequested(const QPoint &)));
1126 connect(KviKvsPopupManager::instance(), SIGNAL(popupRefresh(const QString &)), this, SLOT(popupRefresh(const QString &)));
1127 }
1128
popupRefresh(const QString & szName)1129 void PopupEditorWidget::popupRefresh(const QString & szName)
1130 {
1131 if(m_bSaving)
1132 return;
1133
1134 KviPointerHashTable<QString, KviKvsPopupMenu> * pTable = KviKvsPopupManager::instance()->popupDict();
1135 if(!pTable)
1136 return;
1137 KviKvsPopupMenu * pPopup = pTable->find(szName);
1138 if(!pPopup)
1139 return;
1140
1141 // if it already exists, replace its popup
1142 for(int i = 0; i < m_pTreeWidget->topLevelItemCount(); i++)
1143 {
1144 MenuTreeWidgetItem * ch = (MenuTreeWidgetItem *)m_pTreeWidget->topLevelItem(i);
1145
1146 if(KviQString::equalCI(szName, ch->m_pPopup->popupName()))
1147 {
1148 if(ch == m_pLastEditedItem)
1149 {
1150 if(
1151 QMessageBox::warning(nullptr, __tr2qs_ctx("Confirm Overwriting Current - KVIrc", "editor"),
1152 __tr2qs_ctx("An external script has changed the popup you are currently editing. Do you want to accept the external changes?", "editor"),
1153 QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape) != QMessageBox::Yes)
1154 return;
1155 }
1156 KviKvsPopupMenu * pCopy = new KviKvsPopupMenu(szName);
1157 pCopy->copyFrom(pPopup);
1158 ch->replacePopup(pCopy);
1159
1160 // refresh current item
1161 if(ch == m_pLastEditedItem)
1162 m_pEditor->edit(m_pLastEditedItem);
1163 return;
1164 }
1165 }
1166 // create it
1167 KviKvsPopupMenu * pCopy = new KviKvsPopupMenu(szName);
1168 pCopy->copyFrom(pPopup);
1169 new MenuTreeWidgetItem(m_pTreeWidget, pCopy);
1170 }
1171
customContextMenuRequested(const QPoint & pos)1172 void PopupEditorWidget::customContextMenuRequested(const QPoint & pos)
1173 {
1174 QTreeWidgetItem * it = m_pTreeWidget->itemAt(pos);
1175 KVI_ASSERT(m_bOneTimeSetupDone);
1176
1177 if(it)
1178 {
1179 m_pContextPopup->clear();
1180
1181 m_pContextPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Popup)),
1182 __tr2qs_ctx("&New Popup", "editor"), this, SLOT(newPopup()));
1183
1184 m_pContextPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Discard)),
1185 __tr2qs_ctx("Re&move Popup", "editor"), this, SLOT(removeCurrentPopup()))
1186 ->setEnabled(it);
1187
1188 m_pContextPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Save)),
1189 __tr2qs_ctx("&Export Popup to...", "editor"), this, SLOT(exportCurrentPopup()))
1190 ->setEnabled(it);
1191
1192 m_pContextPopup->popup(QCursor::pos());
1193 }
1194 else
1195 {
1196 m_pEmptyContextPopup->clear();
1197
1198 m_pEmptyContextPopup->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Popup)),
1199 __tr2qs_ctx("&New Popup", "editor"), this, SLOT(newPopup()));
1200 m_pEmptyContextPopup->popup(QCursor::pos());
1201 }
1202 }
1203
exportCurrentPopup()1204 void PopupEditorWidget::exportCurrentPopup()
1205 {
1206 if(!m_pLastEditedItem)
1207 return;
1208 saveLastEditedItem();
1209 if(!m_pLastEditedItem)
1210 return;
1211
1212 QString szName = QDir::homePath();
1213 if(!szName.endsWith(QString(KVI_PATH_SEPARATOR)))
1214 szName += KVI_PATH_SEPARATOR;
1215 szName += m_pLastEditedItem->popup()->popupName();
1216 szName += ".kvs";
1217
1218 QString szFile;
1219
1220 if(!KviFileDialog::askForSaveFileName(szFile, __tr2qs_ctx("Enter a Filename - KVIrc", "editor"), szName, KVI_FILTER_SCRIPT, true, true, true, this))
1221 return;
1222
1223 QString szOut;
1224 m_pLastEditedItem->popup()->generateDefPopup(szOut);
1225
1226 if(!KviFileUtils::writeFile(szFile, szOut))
1227 {
1228 QMessageBox::warning(this, __tr2qs_ctx("Writing to File Failed - KVIrc", "editor"), __tr2qs_ctx("Unable to write to the popups file.", "editor"), __tr2qs_ctx("OK", "editor"));
1229 }
1230 }
1231
exportAll()1232 void PopupEditorWidget::exportAll()
1233 {
1234 bool bSelectedOnly = true;
1235 exportPopups(bSelectedOnly);
1236 }
1237
exportSelected()1238 void PopupEditorWidget::exportSelected()
1239 {
1240 bool bSelectedOnly = false;
1241 exportPopups(bSelectedOnly);
1242 }
1243
exportPopups(bool bSelectedOnly)1244 void PopupEditorWidget::exportPopups(bool bSelectedOnly)
1245 {
1246 saveLastEditedItem();
1247
1248 QString out;
1249 int count = 0, topcount = m_pTreeWidget->topLevelItemCount();
1250
1251 for(int i = 0; i < topcount; i++)
1252 {
1253 MenuTreeWidgetItem * it = (MenuTreeWidgetItem *)m_pTreeWidget->topLevelItem(i);
1254 if((it->isSelected()) || (bSelectedOnly == true))
1255 {
1256 count++;
1257 QString tmp;
1258 it->popup()->generateDefPopup(tmp);
1259 out += tmp;
1260 out += "\n";
1261 }
1262 }
1263 if(!count && !bSelectedOnly)
1264 return;
1265
1266 QString szName = QDir::homePath();
1267 if(!szName.endsWith(QString(KVI_PATH_SEPARATOR)))
1268 szName += KVI_PATH_SEPARATOR;
1269 szName += "popups.kvs";
1270
1271 QString szFile;
1272
1273 if(!KviFileDialog::askForSaveFileName(szFile, __tr2qs_ctx("Enter a Filename - KVIrc", "editor"), szName, KVI_FILTER_SCRIPT, true, true, true, this))
1274 return;
1275
1276 if(!KviFileUtils::writeFile(szFile, out))
1277 {
1278 QMessageBox::warning(this, __tr2qs_ctx("Writing to File Failed - KVIrc", "editor"), __tr2qs_ctx("Unable to write to the popups file.", "editor"), __tr2qs_ctx("OK", "editor"));
1279 }
1280 }
1281
removeCurrentPopup()1282 void PopupEditorWidget::removeCurrentPopup()
1283 {
1284 if(m_pLastEditedItem)
1285 {
1286 MenuTreeWidgetItem * it = m_pLastEditedItem;
1287 m_pLastEditedItem = nullptr;
1288 delete it;
1289 if(!m_pLastEditedItem)
1290 currentItemChanged(nullptr, nullptr);
1291 }
1292 }
1293
newPopup()1294 void PopupEditorWidget::newPopup()
1295 {
1296 QString newName;
1297 getUniquePopupName(nullptr, newName);
1298 MenuTreeWidgetItem * it = new MenuTreeWidgetItem(m_pTreeWidget, new KviKvsPopupMenu(newName));
1299 m_pTreeWidget->setCurrentItem(it);
1300 }
1301
saveLastEditedItem()1302 void PopupEditorWidget::saveLastEditedItem()
1303 {
1304 if(!m_pLastEditedItem)
1305 return;
1306
1307 KviKvsPopupMenu * m = m_pEditor->getMenu();
1308 QString tmp = m->popupName();
1309 QString old = m_pLastEditedItem->m_pPopup->popupName();
1310 if(!KviQString::equalCI(tmp, old))
1311 {
1312 getUniquePopupName(m_pLastEditedItem, tmp);
1313 m->setPopupName(tmp);
1314 }
1315
1316 m_pLastEditedItem->replacePopup(m);
1317 m_pLastEditedItem->setText(0, m->popupName());
1318 }
1319
currentItemChanged(QTreeWidgetItem * it,QTreeWidgetItem *)1320 void PopupEditorWidget::currentItemChanged(QTreeWidgetItem * it, QTreeWidgetItem *)
1321 {
1322 saveLastEditedItem();
1323
1324 m_pLastEditedItem = (MenuTreeWidgetItem *)it;
1325 m_pEditor->edit(m_pLastEditedItem);
1326 }
1327
showEvent(QShowEvent * e)1328 void PopupEditorWidget::showEvent(QShowEvent * e)
1329 {
1330 oneTimeSetup();
1331 QWidget::showEvent(e);
1332 }
1333
commit()1334 void PopupEditorWidget::commit()
1335 {
1336 m_bSaving = true;
1337 if(!m_bOneTimeSetupDone)
1338 return;
1339
1340 saveLastEditedItem();
1341
1342 int topcount = m_pTreeWidget->topLevelItemCount();
1343
1344 // Copy the original popup dict
1345 KviPointerHashTable<QString, KviKvsPopupMenu> copy(*(KviKvsPopupManager::instance()->popupDict()));
1346 copy.setAutoDelete(false);
1347
1348 for(int i = 0; i < topcount; i++)
1349 {
1350 MenuTreeWidgetItem * it = (MenuTreeWidgetItem *)m_pTreeWidget->topLevelItem(i);
1351 KviKvsPopupMenu * p = KviKvsPopupManager::instance()->get(it->m_pPopup->popupName());
1352 p->doClear();
1353 p->copyFrom(it->m_pPopup);
1354 // remove it from the original copy
1355 copy.remove(p->popupName());
1356 }
1357
1358 // the remaining elements in the copy need to be removed from
1359 // the "new" dictionary (they are no longer used)
1360 KviPointerHashTableIterator<QString, KviKvsPopupMenu> iter(copy);
1361
1362 while(iter.current())
1363 {
1364 KviKvsPopupManager::instance()->remove(iter.currentKey());
1365 ++iter;
1366 }
1367
1368 g_pApp->savePopups();
1369 m_bSaving = false;
1370 }
1371
getUniquePopupName(MenuTreeWidgetItem * item,QString & buffer)1372 void PopupEditorWidget::getUniquePopupName(MenuTreeWidgetItem * item, QString & buffer)
1373 {
1374 KVI_ASSERT(m_bOneTimeSetupDone);
1375
1376 if(buffer.isEmpty())
1377 buffer = __tr2qs_ctx("unnamed", "editor");
1378 QString newName = buffer;
1379
1380 bool bFound = true;
1381 int idx = 1;
1382 int topcount = m_pTreeWidget->topLevelItemCount();
1383
1384 while(bFound)
1385 {
1386 bFound = false;
1387
1388 for(int i = 0; i < topcount; i++)
1389 {
1390 MenuTreeWidgetItem * ch = (MenuTreeWidgetItem *)m_pTreeWidget->topLevelItem(i);
1391
1392 if(KviQString::equalCI(newName, ch->m_pPopup->popupName()) && (ch != item))
1393 {
1394 bFound = true;
1395 newName = QString("%1.%2").arg(buffer).arg(idx);
1396 idx++;
1397 break;
1398 }
1399 }
1400 }
1401
1402 buffer = newName;
1403 }
1404
PopupEditorWindow()1405 PopupEditorWindow::PopupEditorWindow()
1406 : KviWindow(KviWindow::ScriptEditor, "popupeditor", nullptr)
1407 {
1408 g_pPopupEditorWindow = this;
1409
1410 QGridLayout * g = new QGridLayout();
1411 m_pEditor = new PopupEditorWidget(this);
1412 g->addWidget(m_pEditor, 0, 0, 1, 4);
1413
1414 QPushButton * btn = new QPushButton(__tr2qs_ctx("&OK", "editor"), this);
1415 connect(btn, SIGNAL(clicked()), this, SLOT(okClicked()));
1416 btn->setIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Accept)));
1417 g->addWidget(btn, 1, 1);
1418
1419 btn = new QPushButton(__tr2qs_ctx("&Apply", "editor"), this);
1420 connect(btn, SIGNAL(clicked()), this, SLOT(applyClicked()));
1421 btn->setIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Accept)));
1422 g->addWidget(btn, 1, 2);
1423
1424 btn = new QPushButton(__tr2qs_ctx("Cancel", "editor"), this);
1425 connect(btn, SIGNAL(clicked()), this, SLOT(cancelClicked()));
1426 btn->setIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Discard)));
1427 g->addWidget(btn, 1, 3);
1428
1429 g->setRowStretch(0, 1);
1430 g->setColumnStretch(0, 1);
1431 setLayout(g);
1432 }
1433
~PopupEditorWindow()1434 PopupEditorWindow::~PopupEditorWindow()
1435 {
1436 g_pPopupEditorWindow = nullptr;
1437 }
1438
okClicked()1439 void PopupEditorWindow::okClicked()
1440 {
1441 m_pEditor->commit();
1442 close();
1443 }
1444
myIconPtr()1445 QPixmap * PopupEditorWindow::myIconPtr()
1446 {
1447 return g_pIconManager->getSmallIcon(KviIconManager::PopupEditor);
1448 }
1449
fillCaptionBuffers()1450 void PopupEditorWindow::fillCaptionBuffers()
1451 {
1452 m_szPlainTextCaption = __tr2qs_ctx("Popup Editor", "editor");
1453 }
1454