1 /* This file is part of KGraphViewer.
2    Copyright (C) 2005-2007 Gael de Chalendar <kleag@free.fr>
3 
4    KGraphViewer is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public
6    License as published by the Free Software Foundation, version 2.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11    General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16    02110-1301, USA
17 */
18 
19 
20 #include "kgrapheditor.h"
21 #include "kgrapheditorConfigDialog.h"
22 #include "kgrapheditorsettings.h"
23 #include "kgrapheditor_debug.h"
24 #include "KGraphEditorNodesTreeWidget.h"
25 #include "KGraphEditorElementTreeWidget.h"
26 #include "ui_preferencesReload.h"
27 #include "ui_preferencesParsing.h"
28 #include "ui_preferencesOpenInExistingWindow.h"
29 #include "ui_preferencesReopenPreviouslyOpenedFiles.h"
30 #include "part/kgraphviewer_part.h"
31 
32 #include <kshortcutsdialog.h>
33 #include <QFileDialog>
34 #include <kconfig.h>
35 #include <QUrl>
36 #include <QTabWidget>
37 #include <kparts/partmanager.h>
38 #include <kedittoolbar.h>
39 #include <QDebug>
40 #include <QStandardPaths>
41 #include <kstandardaction.h>
42 #include <ktoggleaction.h>
43 #include <KPluginLoader>
44 #include <KService>
45 #include <QMessageBox>
46 #include <QStatusBar>
47 #include <kconfigdialog.h>
48 #include <QDebug>
49 #include <krecentfilesaction.h>
50 #include <ktoolbar.h>
51 #include <KActionCollection>
52 #include <klocalizedstring.h>
53 #include <QtDBus/QtDBus>
54 #include <QDockWidget>
55 #include <QTreeWidget>
56 
57 #include <iostream>
58 
59 using namespace KGraphViewer;
60 
KGraphEditor()61 KGraphEditor::KGraphEditor() :
62     KParts::MainWindow(),
63     m_rfa(nullptr),
64     m_currentPart(nullptr)
65 {
66   // set the shell's ui resource file
67   setXMLFile("kgrapheditorui.rc");
68 
69   m_widget = new QTabWidget(this);
70   m_widget->setTabsClosable(true);
71   connect(m_widget, SIGNAL(tabCloseRequested(int)), this, SLOT(close(int)));
72   connect(m_widget, SIGNAL(currentChanged(int)), this, SLOT(newTabSelectedSlot(int)));
73 
74   setCentralWidget(m_widget);
75 
76   QDockWidget* topLeftDockWidget = new QDockWidget(this);
77   topLeftDockWidget->setObjectName(QStringLiteral("TopLeftDockWidget"));
78   m_treeWidget = new KGraphEditorNodesTreeWidget(topLeftDockWidget);
79   connect(m_treeWidget,SIGNAL(itemChanged(QTreeWidgetItem*,int)),
80           this,SLOT(slotItemChanged(QTreeWidgetItem*,int)));
81   connect(m_treeWidget,SIGNAL(itemClicked(QTreeWidgetItem*,int)),
82           this,SLOT(slotItemClicked(QTreeWidgetItem*,int)));
83   connect(m_treeWidget, SIGNAL(removeNode(QString)),
84           this, SLOT(slotRemoveNode(QString)));
85   connect(m_treeWidget, SIGNAL(addAttribute(QString)),
86           this, SLOT(slotAddAttribute(QString)));
87   connect(m_treeWidget, SIGNAL(removeAttribute(QString,QString)),
88           this, SLOT(slotRemoveAttribute(QString,QString)));
89 
90 //   m_treeWidget->setItemDelegate(new VariantDelegate(m_treeWidget));
91   m_treeWidget->setColumnCount(2);
92   topLeftDockWidget->setWidget(m_treeWidget);
93   addDockWidget ( Qt::LeftDockWidgetArea, topLeftDockWidget );
94 
95   QDockWidget* bottomLeftDockWidget = new QDockWidget(this);
96   bottomLeftDockWidget->setObjectName(QStringLiteral("BottomLeftDockWidget"));
97   m_newElementAttributesWidget = new KGraphEditorElementTreeWidget(bottomLeftDockWidget);
98   connect(m_newElementAttributesWidget,SIGNAL(itemChanged(QTreeWidgetItem*,int)),
99           this,SLOT(slotNewElementItemChanged(QTreeWidgetItem*,int)));
100   connect(m_newElementAttributesWidget, SIGNAL(addAttribute(QString)),
101           this, SLOT(slotAddNewElementAttribute(QString)));
102   connect(m_newElementAttributesWidget, SIGNAL(removeAttribute(QString)),
103           this, SLOT(slotRemoveNewElementAttribute(QString)));
104   m_newElementAttributesWidget->setColumnCount(2);
105   bottomLeftDockWidget->setWidget(m_newElementAttributesWidget);
106   addDockWidget ( Qt::LeftDockWidgetArea, bottomLeftDockWidget );
107 
108 
109   if (QDBusConnection::sessionBus().registerService( "org.kde.kgrapheditor" ))
110   {
111     qCDebug(KGRAPHEDITOR_LOG) << "Service Registered successfully";
112     QDBusConnection::sessionBus().registerObject("/", this, QDBusConnection::ExportAllSlots);
113 
114   }
115   else
116   {
117     qCDebug(KGRAPHEDITOR_LOG) << "Failed to register service...";
118   }
119 
120   // Create a KParts part manager, to handle part activation/deactivation
121   m_manager = new KParts::PartManager( this );
122 
123   // When the manager says the active part changes, the window updates (recreates) the GUI
124   connect( m_manager, SIGNAL(activePartChanged(KParts::Part*)),
125            this, SLOT(createGUI(KParts::Part*)) );
126 
127   setupGUI(ToolBar | Keys | StatusBar | Save);
128 
129   // then, setup our actions
130   setupActions();
131 
132   // this routine will find and load our Part.  it finds the Part by
133   // name which is a bad idea usually.. but it's alright in this
134   // case since our Part is made for this Shell
135 
136   // Creates the GUI with a null part to make appear the main app menus and tools
137   createGUI(0);
138 }
139 
~KGraphEditor()140 KGraphEditor::~KGraphEditor()
141 {
142 }
143 
reloadPreviousFiles()144 void KGraphEditor::reloadPreviousFiles()
145 {
146   QStringList previouslyOpenedFiles = KGraphEditorSettings::previouslyOpenedFiles();
147   if ( (previouslyOpenedFiles.empty() == false)
148        && (QMessageBox::question(this,
149               i18n("Session Restore"),
150               i18n("Do you want to reload files from previous session?")) == QMessageBox::Yes) )
151   {
152     QStringList::const_iterator it, it_end;
153     it = previouslyOpenedFiles.constBegin(); it_end = previouslyOpenedFiles.constEnd();
154     for (; it != it_end; it++)
155     {
156       openUrl(*it);
157     }
158   }
159 }
160 
slotNewGraph()161 KParts::ReadOnlyPart *KGraphEditor::slotNewGraph()
162 {
163   KPluginFactory *factory = KPluginLoader("kgraphviewerpart").factory();
164   if (!factory)
165   {
166     // if we couldn't find our Part, we exit since the Shell by
167     // itself can't do anything useful
168     QMessageBox::critical(this, i18n("Unable to start"), i18n("Could not find the KGraphViewer part."));
169     qApp->quit();
170     // we return here, cause kapp->quit() only means "exit the
171     // next time we enter the event loop...
172     return nullptr;
173   }
174   KParts::ReadOnlyPart* part = factory->create<KParts::ReadOnlyPart>(this);
175   KGraphViewerInterface *view = qobject_cast<KGraphViewerInterface *>(part);
176   if (!view)
177   {
178     // This should not happen
179     qCWarning(KGRAPHEDITOR_LOG) << "Failed to get KPart" << endl;
180     return nullptr;
181   }
182   view->setReadWrite();
183 
184     QWidget *w = part->widget();
185 
186     m_tabsPartsMap[w] = part;
187     m_tabsFilesMap[w] = "";
188     connect(this,SIGNAL(hide(KParts::Part*)),part,SLOT(slotHide(KParts::Part*)));
189 
190     m_manager->addPart(part, true);
191 
192     m_widget->addTab(w, QIcon::fromTheme("kgraphviewer"), "");
193     m_widget->setCurrentWidget(w);
194     m_closeAction->setEnabled(true);
195   return part;
196 }
197 
openUrl(const QUrl & url)198 void KGraphEditor::openUrl(const QUrl& url)
199 {
200   qCDebug(KGRAPHEDITOR_LOG) << url;
201   KParts::ReadOnlyPart *part = slotNewGraph();
202 
203 //   (KGraphEditorSettings::parsingMode() == "external")
204 //     ?kgv->setLayoutMethod(KGraphViewerInterface::ExternalProgram)
205 //     :kgv->setLayoutMethod(KGraphViewerInterface::InternalLibrary);
206 
207   QString label = url.path().section('/',-1,-1);
208   // @TODO set label
209   m_widget->setTabText(m_widget->currentIndex(), label);
210   m_tabsFilesMap[m_widget->currentWidget()] = url.path();
211   part->openUrl(url);
212 
213   if (m_rfa) {
214     m_rfa->addUrl(url);
215   }
216 
217   m_openedFiles.push_back(url.path());
218 }
219 
fileOpen()220 void KGraphEditor::fileOpen()
221 {
222   // this slot is called whenever the File->Open menu is selected,
223   // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
224   // button is clicked
225   QFileDialog fileDialog(this);
226   fileDialog.setMimeTypeFilters(QStringList(QStringLiteral("text/vnd.graphviz")));
227   fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
228   fileDialog.setFileMode(QFileDialog::ExistingFiles);
229   if (fileDialog.exec() != QFileDialog::Accepted) {
230     return;
231   }
232 
233   foreach (const QUrl& url, fileDialog.selectedUrls()) {
234     openUrl(url);
235   }
236 }
237 
238 
setupActions()239 void KGraphEditor::setupActions()
240 {
241   // create our actions
242 
243   actionCollection()->addAction( KStandardAction::New, "file_new", this, SLOT(fileNew()) );
244   actionCollection()->addAction( KStandardAction::Open, "file_open", this, SLOT(fileOpen()) );
245   m_rfa = (KRecentFilesAction*) actionCollection()->addAction(KStandardAction::OpenRecent, "file_open_recent", this, SLOT(slotURLSelected(QUrl)) );
246   m_rfa->loadEntries(KConfigGroup(KSharedConfig::openConfig(), "kgrapheditor"));
247   actionCollection()->addAction( KStandardAction::Save, "file_save", this, SLOT(fileSave()) );
248   actionCollection()->addAction( KStandardAction::SaveAs, "file_save_as", this, SLOT(fileSaveAs()) );
249 
250   m_closeAction = actionCollection()->addAction( KStandardAction::Close, "file_close", this, SLOT(close()) );
251   m_closeAction->setWhatsThis(i18n("Closes the current file"));
252   m_closeAction->setEnabled(false);
253 
254   actionCollection()->addAction( KStandardAction::Quit, "file_quit", qApp, SLOT(quit()) );
255 
256   m_statusbarAction = KStandardAction::showStatusbar(this, SLOT(optionsShowStatusbar()), this);
257 
258   actionCollection()->addAction( KStandardAction::KeyBindings, "options_configure_keybinding", this, SLOT(optionsConfigureKeys()) );
259 //   KStandardAction::keyBindings(this, SLOT(optionsConfigureKeys()), this);
260   actionCollection()->addAction( KStandardAction::ConfigureToolbars, "options_configure_toolbars", this, SLOT(optionsConfigureToolbars()) );
261   actionCollection()->addAction( KStandardAction::Preferences, "options_configure", this, SLOT(optionsConfigure()) );
262 
263   QAction* edit_new_vertex = actionCollection()->addAction( "edit_new_vertex" );
264   edit_new_vertex->setText(i18n("Create a New Vertex"));
265   edit_new_vertex->setIcon(QPixmap(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kgraphviewerpart/pics/kgraphviewer-newnode.png")));
266   connect( edit_new_vertex, SIGNAL(triggered(bool)), this, SLOT(slotEditNewVertex()) );
267 
268   QAction* edit_new_edge = actionCollection()->addAction( "edit_new_edge" );
269   edit_new_edge->setText(i18n("Create a New Edge"));
270   edit_new_edge->setIcon(QPixmap(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kgraphviewerpart/pics/kgraphviewer-newedge.png")));
271   connect( edit_new_edge, SIGNAL(triggered(bool)), this, SLOT(slotEditNewEdge()) );
272 }
273 
closeEvent(QCloseEvent * event)274 void KGraphEditor::closeEvent(QCloseEvent *event)
275 {
276   KGraphEditorSettings::setPreviouslyOpenedFiles(m_openedFiles);
277   m_rfa->saveEntries(KConfigGroup(KSharedConfig::openConfig(), "kgrapheditor"));
278 
279   KGraphEditorSettings::self()->save();
280   KXmlGuiWindow::closeEvent(event);
281 }
282 
fileNew()283 void KGraphEditor::fileNew()
284 {
285   // this slot is called whenever the File->New menu is selected,
286   // the New shortcut is pressed (usually CTRL+N) or the New toolbar
287   // button is clicked
288 
289   slotNewGraph();
290 }
291 
292 
optionsShowToolbar()293 void KGraphEditor::optionsShowToolbar()
294 {
295   // this is all very cut and paste code for showing/hiding the
296   // toolbar
297   if (m_toolbarAction->isChecked())
298       toolBar()->show();
299   else
300       toolBar()->hide();
301 }
302 
optionsShowStatusbar()303 void KGraphEditor::optionsShowStatusbar()
304 {
305   // this is all very cut and paste code for showing/hiding the
306   // statusbar
307   if (m_statusbarAction->isChecked())
308       statusBar()->show();
309   else
310       statusBar()->hide();
311 }
312 
optionsConfigureKeys()313 void KGraphEditor::optionsConfigureKeys()
314 {
315   KShortcutsDialog::configure(actionCollection());
316 }
317 
optionsConfigureToolbars()318 void KGraphEditor::optionsConfigureToolbars()
319 {
320     KConfigGroup conf(KConfigGroup(KSharedConfig::openConfig(), "kgrapheditor"));
321     saveMainWindowSettings(conf);
322 
323   // use the standard toolbar editor
324   KEditToolBar dlg(factory());
325   connect(&dlg, SIGNAL(newToolbarConfig()),
326           this, SLOT(applyNewToolbarConfig()));
327   dlg.exec();
328 }
329 
optionsConfigure()330 void KGraphEditor::optionsConfigure()
331 {
332   //An instance of your dialog could be already created and could be cached,
333   //in which case you want to display the cached dialog instead of creating
334   //another one
335   if ( KgeConfigurationDialog::showDialog( "settings" ) )
336     return;
337 
338   //KConfigDialog didn't find an instance of this dialog, so lets create it :
339   KgeConfigurationDialog* dialog = new KgeConfigurationDialog(this, "settings", KGraphEditorSettings::self());
340 
341   Ui::KGraphViewerPreferencesParsingWidget*  parsingWidget = dialog->m_parsingWidget;
342   qCDebug(KGRAPHEDITOR_LOG) << KGraphEditorSettings::parsingMode();
343   if (KGraphEditorSettings::parsingMode() == "external")
344   {
345     parsingWidget->external->setChecked(true);
346   }
347   else if (KGraphEditorSettings::parsingMode() == "internal")
348   {
349     parsingWidget->internal->setChecked(true);
350   }
351   connect((QObject*)parsingWidget->external, SIGNAL(toggled(bool)), this, SLOT(slotParsingModeExternalToggled(bool)) );
352   connect((QObject*)parsingWidget->internal, SIGNAL(toggled(bool)), this, SLOT(slotParsingModeInternalToggled(bool)) );
353 
354 
355 /*  KGraphViewerPreferencesReloadWidget*  reloadWidget =
356       new KGraphViewerPreferencesReloadWidget( 0, "KGraphViewer Settings" );
357   if (KGraphEditorSettings::reloadOnChangeMode() == "yes")
358   {
359     reloadWidget->reloadOnChangeMode->setButton(0);
360   }
361   else if (KGraphEditorSettings::reloadOnChangeMode() == "no")
362   {
363     reloadWidget->reloadOnChangeMode->setButton(1);
364   }
365   else if (KGraphEditorSettings::reloadOnChangeMode() == "ask")
366   {
367     reloadWidget->reloadOnChangeMode->setButton(2);
368   }
369 
370   connect((QObject*)reloadWidget->reloadOnChangeMode, SIGNAL(clicked(int)), this, SLOT(reloadOnChangeMode_pressed(int)) );
371 
372   dialog->addPage( reloadWidget, i18n("Reloading"), "kgraphreloadoptions", i18n("Reloading"), true);
373 
374   KGraphViewerPreferencesOpenInExistingWindowWidget*  openingWidget =
375     new KGraphViewerPreferencesOpenInExistingWindowWidget( 0, "KGraphViewer Settings" );
376   if (KGraphEditorSettings::openInExistingWindowMode() == "yes")
377   {
378     openingWidget->openInExistingWindowMode->setButton(0);
379   }
380   else if (KGraphEditorSettings::openInExistingWindowMode() == "no")
381   {
382     openingWidget->openInExistingWindowMode->setButton(1);
383   }
384   else if (KGraphEditorSettings::openInExistingWindowMode() == "ask")
385   {
386     openingWidget->openInExistingWindowMode->setButton(2);
387   }
388 
389   connect((QObject*)openingWidget->openInExistingWindowMode, SIGNAL(clicked(int)), this, SLOT(openInExistingWindowMode_pressed(int)) );
390 
391   dialog->addPage( openingWidget, i18n("Opening"), "kgraphopeningoptions", i18n("Opening"), true);
392 
393   KGraphViewerPreferencesReopenPreviouslyOpenedFilesWidget*  reopeningWidget =
394     new KGraphViewerPreferencesReopenPreviouslyOpenedFilesWidget( 0, "KGraphViewer Settings" );
395   if (KGraphEditorSettings::reopenPreviouslyOpenedFilesMode() == "yes")
396   {
397     reopeningWidget->reopenPreviouslyOpenedFilesMode->setButton(0);
398   }
399   else if (KGraphEditorSettings::reopenPreviouslyOpenedFilesMode() == "no")
400   {
401     reopeningWidget->reopenPreviouslyOpenedFilesMode->setButton(1);
402   }
403   else if (KGraphEditorSettings::reopenPreviouslyOpenedFilesMode() == "ask")
404   {
405     reopeningWidget->reopenPreviouslyOpenedFilesMode->setButton(2);
406   }
407 
408   connect((QObject*)reopeningWidget->reopenPreviouslyOpenedFilesMode, SIGNAL(clicked(int)), this, SLOT(reopenPreviouslyOpenedFilesMode_pressed(int)) );
409 
410   dialog->addPage( reopeningWidget, i18n("Session Management"), "kgraphreopeningoptions", i18n("Session Management"), true);
411   */
412 //   connect(dialog, SIGNAL(settingsChanged()), this, SLOT(settingsChanged()));
413 
414   dialog->show();
415 }
416 
applyNewToolbarConfig()417 void KGraphEditor::applyNewToolbarConfig()
418 {
419   applyMainWindowSettings(KConfigGroup(KSharedConfig::openConfig(), "kgrapheditor"));
420 }
421 
422 // void KGraphViewer::reloadOnChangeMode_pressed(int value)
423 // {
424 //   qCDebug(KGRAPHEDITOR_LOG) << "reloadOnChangeMode_pressed " << value;
425 //   switch (value)
426 //   {
427 //   case 0:
428 //     KGraphEditorSettings::setReloadOnChangeMode("yes");
429 //     break;
430 //   case 1:
431 //     KGraphEditorSettings::setReloadOnChangeMode("no");
432 //     break;
433 //   case 2:
434 //     KGraphEditorSettings::setReloadOnChangeMode("ask");
435 //     break;
436 //   default:
437 //   qCWarning(KGRAPHEDITOR_LOG) << "Invalid reload on change mode value: " << value;
438 //     return;
439 //   }
440 //   qCDebug(KGRAPHEDITOR_LOG) << "emiting";
441 //   emit(settingsChanged());
442 //   KGraphEditorSettings::save();
443 // }
444 //
445 // void KGraphViewer::openInExistingWindowMode_pressed(int value)
446 // {
447 //   std::cerr << "openInExistingWindowMode_pressed " << value << std::endl;
448 //   switch (value)
449 //   {
450 //   case 0:
451 //     KGraphEditorSettings::setOpenInExistingWindowMode("yes");
452 //     break;
453 //   case 1:
454 //     KGraphEditorSettings::setOpenInExistingWindowMode("no");
455 //     break;
456 //   case 2:
457 //     KGraphEditorSettings::setOpenInExistingWindowMode("ask");
458 //     break;
459 //   default:
460 //   qCWarning(KGRAPHEDITOR_LOG) << "Invalid OpenInExistingWindow value: " << value << endl;
461 //     return;
462 //   }
463 //
464 //   std::cerr << "emiting" << std::endl;
465 //   emit(settingsChanged());
466 //   KGraphEditorSettings::save();
467 // }
468 //
469 // void KGraphViewer::reopenPreviouslyOpenedFilesMode_pressed(int value)
470 // {
471 //   std::cerr << "reopenPreviouslyOpenedFilesMode_pressed " << value << std::endl;
472 //   switch (value)
473 //   {
474 //   case 0:
475 //     KGraphEditorSettings::setReopenPreviouslyOpenedFilesMode("yes");
476 //     break;
477 //   case 1:
478 //     KGraphEditorSettings::setReopenPreviouslyOpenedFilesMode("no");
479 //     break;
480 //   case 2:
481 //     KGraphEditorSettings::setReopenPreviouslyOpenedFilesMode("ask");
482 //     break;
483 //   default:
484 //   qCWarning(KGRAPHEDITOR_LOG) << "Invalid ReopenPreviouslyOpenedFilesMode value: " << value << endl;
485 //     return;
486 //   }
487 //
488 //   std::cerr << "emiting" << std::endl;
489 //   emit(settingsChanged());
490 //   KGraphEditorSettings::save();
491 // }
492 
493 
slotURLSelected(const QUrl & url)494 void KGraphEditor::slotURLSelected(const QUrl& url)
495 {
496   openUrl(url);
497 }
498 
close(int index)499 void KGraphEditor::close(int index)
500 {
501   QWidget *tab = m_widget->widget(index);
502   m_openedFiles.removeAll(m_tabsFilesMap[tab]);
503   m_widget->removeTab(index);
504   tab->hide();
505   KParts::ReadOnlyPart *part = m_tabsPartsMap[tab];
506   m_manager->removePart(part);
507   m_tabsPartsMap.remove(tab);
508   m_tabsFilesMap.remove(tab);
509   delete part; part = nullptr;
510 /*  delete tab;
511   tab = nullptr;*/
512   m_closeAction->setEnabled(m_widget->count() > 0);
513 }
514 
close()515 void KGraphEditor::close()
516 {
517   int currentPage = m_widget->currentIndex();
518   if (currentPage != -1)
519   {
520     close(currentPage);
521   }
522 }
523 
fileSave()524 void KGraphEditor::fileSave()
525 {
526   QWidget* currentPage = m_widget->currentWidget();
527   if (currentPage)
528   {
529     emit(saveTo(QUrl(m_tabsFilesMap[currentPage]).path()));
530   }
531 }
532 
fileSaveAs()533 void KGraphEditor::fileSaveAs()
534 {
535   QWidget* currentPage = m_widget->currentWidget();
536   if (currentPage)
537   {
538     QFileDialog fileDialog(currentPage, i18n("Save current graph"));
539     fileDialog.setMimeTypeFilters(QStringList(QStringLiteral("text/vnd.graphviz")));
540     fileDialog.setAcceptMode(QFileDialog::AcceptSave);
541     if (fileDialog.exec() != QFileDialog::Accepted) {
542       return;
543     }
544     const QString fileName = fileDialog.selectedFiles().at(0);
545     if (fileName.isEmpty()) {
546       return;
547     }
548 
549     m_tabsFilesMap[currentPage] = fileName;
550     emit(saveTo(fileName));
551   }
552 }
553 
newTabSelectedSlot(int index)554 void KGraphEditor::newTabSelectedSlot(int index)
555 {
556 //   qCDebug(KGRAPHEDITOR_LOG) << tab;
557   emit(hide((KParts::Part*)(m_manager->activePart())));
558   QWidget *tab = m_widget->widget(index);
559   if (tab) {
560     slotSetActiveGraph(m_tabsPartsMap[tab]);
561     m_manager->setActivePart(m_tabsPartsMap[tab]);
562   }
563 }
564 
slotSetActiveGraph(KParts::ReadOnlyPart * part)565 void KGraphEditor::slotSetActiveGraph(KParts::ReadOnlyPart *part)
566 {
567   if (m_currentPart)
568   {
569     disconnect(this,SIGNAL(prepareAddNewElement(QMap<QString,QString>)),m_currentPart,SLOT(prepareAddNewElement(QMap<QString,QString>)));
570     disconnect(this,SIGNAL(prepareAddNewEdge(QMap<QString,QString>)),m_currentPart,SLOT(prepareAddNewEdge(QMap<QString,QString>)));
571     disconnect(this,SIGNAL(saveTo(QString)),m_currentPart,SLOT(saveTo(QString)));
572     disconnect(this,SIGNAL(removeNode(QString)),m_currentPart,SLOT(slotRemoveNode(QString)));
573     disconnect(this,SIGNAL(addAttribute(QString)),m_currentPart,SLOT(slotAddAttribute(QString)));
574     disconnect(this,SIGNAL(removeAttribute(QString,QString)),m_currentPart,SLOT(slotRemoveAttribute(QString,QString)));
575     disconnect(this,SIGNAL(update()),m_currentPart,SLOT(slotUpdate()));
576     disconnect(this,SIGNAL(selectNode(QString)),m_currentPart,SLOT(slotSelectNode(QString)));
577     disconnect(this,SIGNAL(saddNewEdge(QString,QString,QMap<QString,QString>)),
578            m_currentPart,SLOT(slotAddNewEdge(QString,QString,QMap<QString,QString>)));
579     disconnect(this,SIGNAL(renameNode(QString,QString)),
580             m_currentPart,SLOT(slotRenameNode(QString,QString)));
581     disconnect(this,SIGNAL(setAttribute(QString,QString,QString)),m_currentPart,SLOT(slotSetAttribute(QString,QString,QString)));
582   }
583   m_currentPart = part;
584   m_treeWidget->clear();
585   if (m_currentPart == nullptr)
586   {
587     return;
588   }
589   connect(this,SIGNAL(prepareAddNewElement(QMap<QString,QString>)),part,SLOT(prepareAddNewElement(QMap<QString,QString>)));
590   connect(this,SIGNAL(prepareAddNewEdge(QMap<QString,QString>)),part,SLOT(prepareAddNewEdge(QMap<QString,QString>)));
591   connect(this,SIGNAL(saveTo(QString)),part,SLOT(saveTo(QString)));
592   connect(this,SIGNAL(removeNode(QString)),part,SLOT(slotRemoveNode(QString)));
593   connect(this,SIGNAL(addAttribute(QString)),part,SLOT(slotAddAttribute(QString)));
594   connect(this,SIGNAL(removeAttribute(QString,QString)),part,SLOT(slotRemoveAttribute(QString,QString)));
595   connect(this,SIGNAL(update()),part,SLOT(slotUpdate()));
596   connect(this,SIGNAL(selectNode(QString)),part,SLOT(slotSelectNode(QString)));
597   connect( this,SIGNAL(removeElement(QString)),m_currentPart,SLOT(slotRemoveElement(QString)));
598   connect(this,SIGNAL(saddNewEdge(QString,QString,QMap<QString,QString>)),m_currentPart,SLOT(slotAddNewEdge(QString,QString,QMap<QString,QString>)));
599   connect(this,SIGNAL(renameNode(QString,QString)),m_currentPart,SLOT(slotRenameNode(QString,QString)));
600   connect(this,SIGNAL(setAttribute(QString,QString,QString)),m_currentPart,SLOT(slotSetAttribute(QString,QString,QString)));
601 
602   QList<QString> nodesIds;//TODO = m_currentPart->nodesIds();
603   QList<QTreeWidgetItem *> items;
604   foreach (const QString& nodeId, nodesIds)
605   {
606     qCDebug(KGRAPHEDITOR_LOG)<< "new item " << nodeId;
607     QTreeWidgetItem* item = new QTreeWidgetItem((QTreeWidget*)nullptr, QStringList(nodeId));
608     item->setFlags(item->flags() | Qt::ItemIsEditable);
609     QMap<QString,QString> attributes;//TODO = m_currentPart->nodeAtributes(nodeId);
610     foreach (const QString& attrib, attributes.keys())
611     {
612       if (attrib != "_draw_" && attrib != "_ldraw_")
613       {
614         QStringList list(attrib);
615         list << attributes[attrib];
616         QTreeWidgetItem* child = new QTreeWidgetItem((QTreeWidget*)nullptr, list);
617         child->setFlags(child->flags() | Qt::ItemIsEditable);
618         item->addChild(child);
619       }
620     }
621     items.append(item);
622   }
623   qCDebug(KGRAPHEDITOR_LOG) << "inserting";
624   m_treeWidget->insertTopLevelItems(0, items);
625 
626 
627   connect( m_currentPart, SIGNAL(graphLoaded()),
628            this, SLOT(slotGraphLoaded()) );
629 
630   connect( m_currentPart, SIGNAL(newNodeAdded(QString)),
631           this, SLOT(slotNewNodeAdded(QString)) );
632 
633   connect( m_currentPart, SIGNAL(newEdgeAdded(QString,QString)),
634             this, SLOT(slotNewEdgeAdded(QString,QString)) );
635 
636   connect( m_currentPart, SIGNAL(removeElement(QString)),
637             this, SLOT(slotRemoveElement(QString)) );
638 
639   connect( m_currentPart, SIGNAL(selectionIs(QList<QString>,QPoint)),
640             this, SLOT(slotSelectionIs(QList<QString>,QPoint)) );
641 
642   connect( m_currentPart, SIGNAL(newEdgeFinished(QString,QString,QMap<QString, QString>)),
643             this, SLOT(slotNewEdgeFinished(QString,QString,QMap<QString, QString>)) );
644 
645   connect( m_currentPart, SIGNAL(hoverEnter(QString)),
646            this, SLOT(slotHoverEnter(QString)) );
647 
648   connect( m_currentPart, SIGNAL(hoverLeave(QString)),
649           this, SLOT(slotHoverLeave(QString)) );
650 }
651 
slotNewNodeAdded(const QString & id)652 void KGraphEditor::slotNewNodeAdded(const QString& id)
653 {
654   qCDebug(KGRAPHEDITOR_LOG) << id;
655   update();
656 }
657 
slotNewEdgeAdded(const QString & ids,const QString & idt)658 void KGraphEditor::slotNewEdgeAdded(const QString& ids, const QString& idt)
659 {
660   qCDebug(KGRAPHEDITOR_LOG) << ids << idt;
661   update();
662 }
663 
slotNewEdgeFinished(const QString & srcId,const QString & tgtId,const QMap<QString,QString> & attribs)664 void KGraphEditor::slotNewEdgeFinished( const QString& srcId, const QString& tgtId, const QMap<QString, QString>&attribs)
665 {
666   qCDebug(KGRAPHEDITOR_LOG) << srcId << tgtId << attribs;
667   emit saddNewEdge(srcId,tgtId,attribs);
668   update();
669 }
670 
slotGraphLoaded()671 void KGraphEditor::slotGraphLoaded()
672 {
673   qCDebug(KGRAPHEDITOR_LOG);
674   disconnect(m_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
675            this,SLOT(slotItemChanged(QTreeWidgetItem*,int)));
676   disconnect(m_treeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)),
677            this,SLOT(slotItemClicked(QTreeWidgetItem*,int)));
678 
679   QList<QString> nodesIds;//TODO = m_currentPart->nodesIds();
680   QList<QTreeWidgetItem *> items;
681   foreach (const QString& nodeId, nodesIds)
682   {
683     qCDebug(KGRAPHEDITOR_LOG)<< "item " << nodeId;
684     QTreeWidgetItem* item;
685     QList<QTreeWidgetItem*> existingItems = m_treeWidget->findItems(nodeId,Qt::MatchRecursive|Qt::MatchExactly);
686     if (existingItems.isEmpty())
687     {
688       item = new QTreeWidgetItem((QTreeWidget*)nullptr, QStringList(nodeId));
689       items.append(item);
690     }
691     else
692     {
693       item = existingItems[0];
694     }
695     item->setFlags(item->flags() | Qt::ItemIsEditable);
696     QMap<QString,QString> attributes; //TODO = m_currentPart->nodeAtributes(nodeId);
697     QList<QString> keys = attributes.keys();
698     for (int i=0; i < item->childCount();i++)
699     {
700       if (keys.contains(item->child(i)->text(0)))
701       {
702         item->child(i)->setText(1,attributes[item->child(i)->text(0)]);
703         keys.removeAll(item->child(i)->text(0));
704       }
705     }
706     foreach (const QString &attrib, keys)
707     {
708       if (attrib != "_draw_" && attrib != "_ldraw_")
709       {
710         QStringList list(attrib);
711         list << attributes[attrib];
712         QTreeWidgetItem* child = new QTreeWidgetItem((QTreeWidget*)nullptr, list);
713         child->setFlags(child->flags() | Qt::ItemIsEditable);
714         item->addChild(child);
715       }
716     }
717 }
718   qCDebug(KGRAPHEDITOR_LOG) << "inserting";
719   m_treeWidget->insertTopLevelItems(0, items);
720   connect(m_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
721            this,SLOT(slotItemChanged(QTreeWidgetItem*,int)));
722   connect(m_treeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)),
723            this,SLOT(slotItemClicked(QTreeWidgetItem*,int)));
724 }
725 
slotItemChanged(QTreeWidgetItem * item,int column)726 void KGraphEditor::slotItemChanged ( QTreeWidgetItem * item, int column )
727 {
728   qCDebug(KGRAPHEDITOR_LOG) ;
729   /* values column */
730   if (column == 0)
731   {
732     QString oldNodeName = m_currentTreeWidgetItemText;
733     QString newNodeName = item->text(0);
734     emit(renameNode(oldNodeName,newNodeName));
735   }
736   else if (column == 1)
737   {
738     /* there is a parent ; it is an attribute line */
739     if (item->parent())
740     {
741       QString nodeLabel = item->parent()->text(0);
742       QString attributeName = item->text(0);
743       QString attributeValue = item->text(1);
744       emit (setAttribute(nodeLabel,attributeName,attributeValue));
745     }
746   }
747   emit update();
748 }
749 
slotItemClicked(QTreeWidgetItem * item,int column)750 void KGraphEditor::slotItemClicked ( QTreeWidgetItem * item, int column )
751 {
752   qCDebug(KGRAPHEDITOR_LOG) << column;
753   m_currentTreeWidgetItemText = item->text(0);
754 
755   QString nodeName = item->parent() ?
756                         item->parent()->text(0) :
757                         item->text(0);
758   emit selectNode(nodeName);
759 }
760 
slotEditNewVertex()761 void KGraphEditor::slotEditNewVertex()
762 {
763   if (m_currentPart == nullptr)
764   {
765     qCDebug(KGRAPHEDITOR_LOG) << "new vertex: no part selected";
766     return;
767   }
768   qCDebug(KGRAPHEDITOR_LOG) << "new vertex";
769   emit(prepareAddNewElement(m_newElementAttributes));
770 }
771 
slotEditNewEdge()772 void KGraphEditor::slotEditNewEdge()
773 {
774   if (m_currentPart == nullptr)
775   {
776     qCDebug(KGRAPHEDITOR_LOG) << "new edge: no part selected";
777     return;
778   }
779   qCDebug(KGRAPHEDITOR_LOG) << "new edge";
780   emit(prepareAddNewEdge(m_newElementAttributes));
781 }
782 
slotRemoveNode(const QString & nodeName)783 void KGraphEditor::slotRemoveNode(const QString& nodeName)
784 {
785   emit removeNode(nodeName);
786   emit update();
787 }
788 
slotAddAttribute(const QString & attribName)789 void KGraphEditor::slotAddAttribute(const QString& attribName)
790 {
791   emit addAttribute(attribName);
792   emit update();
793 }
794 
slotRemoveAttribute(const QString & nodeName,const QString & attribName)795 void KGraphEditor::slotRemoveAttribute(const QString& nodeName, const QString& attribName)
796 {
797   emit removeAttribute(nodeName,attribName);
798   emit update();
799 }
800 
slotNewElementItemChanged(QTreeWidgetItem * item,int column)801 void KGraphEditor::slotNewElementItemChanged(QTreeWidgetItem* item ,int column)
802 {
803   qCDebug(KGRAPHEDITOR_LOG);
804   if (column == 0)
805   {
806     qCWarning(KGRAPHEDITOR_LOG) << "Item id change not handled";
807     return;
808   }
809   else if (column == 1)
810   {
811     m_newElementAttributes[item->text(0)] = item->text(1);
812   }
813   else
814   {
815     qCWarning(KGRAPHEDITOR_LOG) << "Unknown column" << column;
816     return;
817   }
818 }
819 
slotAddNewElementAttribute(const QString & attrib)820 void KGraphEditor::slotAddNewElementAttribute(const QString& attrib)
821 {
822   m_newElementAttributes[attrib] = QString();
823 }
824 
slotRemoveNewElementAttribute(const QString & attrib)825 void KGraphEditor::slotRemoveNewElementAttribute(const QString& attrib)
826 {
827   m_newElementAttributes.remove(attrib);
828 }
829 
slotRemoveElement(const QString & id)830 void KGraphEditor::slotRemoveElement(const QString& id)
831 {
832   qCDebug(KGRAPHEDITOR_LOG) << id;
833   m_treeWidget->slotRemoveElement(id);
834   emit(removeElement(id));
835 }
836 
slotSelectionIs(const QList<QString> & elements,const QPoint & p)837 void KGraphEditor::slotSelectionIs(const QList<QString>& elements , const QPoint& p)
838 {
839   qCDebug(KGRAPHEDITOR_LOG);
840   Q_UNUSED(p);
841   QList<QTreeWidgetItem*> items = m_treeWidget->selectedItems();
842   foreach (QTreeWidgetItem* item, items)
843   {
844     item->setSelected(false);
845   }
846   foreach (const QString &elementName, elements)
847   {
848     QList<QTreeWidgetItem*> items = m_treeWidget->findItems(elementName,Qt::MatchExactly,0);
849     foreach (QTreeWidgetItem* item, items)
850     {
851       item->setSelected(true);
852     }
853   }
854 }
855 
slotParsingModeExternalToggled(bool value)856 void KGraphEditor::slotParsingModeExternalToggled(bool value)
857 {
858   if (value)
859   {
860     KGraphEditorSettings::setParsingMode("external");
861   }
862   //   qCDebug(KGRAPHEDITOR_LOG) << "emiting";
863   //   emit(settingsChanged());
864   KGraphEditorSettings::self()->save();
865 }
866 
slotParsingModeInternalToggled(bool value)867 void KGraphEditor::slotParsingModeInternalToggled(bool value)
868 {
869   if (value)
870   {
871     KGraphEditorSettings::setParsingMode("internal");
872   }
873   //   qCDebug(KGRAPHEDITOR_LOG) << "emiting";
874   //   emit(settingsChanged());
875   KGraphEditorSettings::self()->save();
876 }
877 
slotHoverEnter(const QString & id)878 void KGraphEditor::slotHoverEnter(const QString& id)
879 {
880   qCDebug(KGRAPHEDITOR_LOG) << id;
881   statusBar()->showMessage(id);
882 }
883 
slotHoverLeave(const QString & id)884 void KGraphEditor::slotHoverLeave(const QString& id)
885 {
886   qCDebug(KGRAPHEDITOR_LOG) << id;
887   statusBar()->showMessage("");
888 }
889