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