File indexing completed on 2024-05-05 16:27:22

0001 /* This file is part of KGraphViewer.
0002    Copyright (C) 2005-2007 Gael de Chalendar <kleag@free.fr>
0003 
0004    KGraphViewer is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU General Public
0006    License as published by the Free Software Foundation, version 2.
0007 
0008    This program is distributed in the hope that it will be useful,
0009    but WITHOUT ANY WARRANTY; without even the implied warranty of
0010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0011    General Public License for more details.
0012 
0013    You should have received a copy of the GNU General Public License
0014    along with this program; if not, write to the Free Software
0015    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0016    02110-1301, USA
0017 */
0018 
0019 #include "kgrapheditor.h"
0020 #include "KGraphEditorElementTreeWidget.h"
0021 #include "KGraphEditorNodesTreeWidget.h"
0022 #include "kgrapheditorConfigDialog.h"
0023 #include "kgrapheditor_debug.h"
0024 #include "kgrapheditorsettings.h"
0025 #include "part/kgraphviewer_part.h"
0026 #include "ui_preferencesOpenInExistingWindow.h"
0027 #include "ui_preferencesParsing.h"
0028 #include "ui_preferencesReload.h"
0029 #include "ui_preferencesReopenPreviouslyOpenedFiles.h"
0030 
0031 #include <KActionCollection>
0032 #include <KService>
0033 #include <QDebug>
0034 #include <QDockWidget>
0035 #include <QFileDialog>
0036 #include <QMessageBox>
0037 #include <QStandardPaths>
0038 #include <QStatusBar>
0039 #include <QTabWidget>
0040 #include <QTreeWidget>
0041 #include <QUrl>
0042 #include <QtDBus/QtDBus>
0043 #include <kconfig.h>
0044 #include <kconfigdialog.h>
0045 #include <kedittoolbar.h>
0046 #include <klocalizedstring.h>
0047 #include <kparts/partmanager.h>
0048 #include <krecentfilesaction.h>
0049 #include <kstandardaction.h>
0050 #include <ktoggleaction.h>
0051 #include <ktoolbar.h>
0052 
0053 #include <iostream>
0054 
0055 using namespace KGraphViewer;
0056 
0057 KGraphEditor::KGraphEditor()
0058     : KParts::MainWindow()
0059     , m_rfa(nullptr)
0060     , m_currentPart(nullptr)
0061 {
0062     // set the shell's ui resource file
0063     setXMLFile("kgrapheditorui.rc");
0064 
0065     m_widget = new QTabWidget(this);
0066     m_widget->setTabsClosable(true);
0067     connect(m_widget, SIGNAL(tabCloseRequested(int)), this, SLOT(close(int)));
0068     connect(m_widget, SIGNAL(currentChanged(int)), this, SLOT(newTabSelectedSlot(int)));
0069 
0070     setCentralWidget(m_widget);
0071 
0072     QDockWidget *topLeftDockWidget = new QDockWidget(this);
0073     topLeftDockWidget->setObjectName(QStringLiteral("TopLeftDockWidget"));
0074     m_treeWidget = new KGraphEditorNodesTreeWidget(topLeftDockWidget);
0075     connect(m_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotItemChanged(QTreeWidgetItem *, int)));
0076     connect(m_treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(slotItemClicked(QTreeWidgetItem *, int)));
0077     connect(m_treeWidget, SIGNAL(removeNode(QString)), this, SLOT(slotRemoveNode(QString)));
0078     connect(m_treeWidget, SIGNAL(addAttribute(QString)), this, SLOT(slotAddAttribute(QString)));
0079     connect(m_treeWidget, SIGNAL(removeAttribute(QString, QString)), this, SLOT(slotRemoveAttribute(QString, QString)));
0080 
0081     //   m_treeWidget->setItemDelegate(new VariantDelegate(m_treeWidget));
0082     m_treeWidget->setColumnCount(2);
0083     topLeftDockWidget->setWidget(m_treeWidget);
0084     addDockWidget(Qt::LeftDockWidgetArea, topLeftDockWidget);
0085 
0086     QDockWidget *bottomLeftDockWidget = new QDockWidget(this);
0087     bottomLeftDockWidget->setObjectName(QStringLiteral("BottomLeftDockWidget"));
0088     m_newElementAttributesWidget = new KGraphEditorElementTreeWidget(bottomLeftDockWidget);
0089     connect(m_newElementAttributesWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotNewElementItemChanged(QTreeWidgetItem *, int)));
0090     connect(m_newElementAttributesWidget, SIGNAL(addAttribute(QString)), this, SLOT(slotAddNewElementAttribute(QString)));
0091     connect(m_newElementAttributesWidget, SIGNAL(removeAttribute(QString)), this, SLOT(slotRemoveNewElementAttribute(QString)));
0092     m_newElementAttributesWidget->setColumnCount(2);
0093     bottomLeftDockWidget->setWidget(m_newElementAttributesWidget);
0094     addDockWidget(Qt::LeftDockWidgetArea, bottomLeftDockWidget);
0095 
0096     if (QDBusConnection::sessionBus().registerService("org.kde.kgrapheditor")) {
0097         qCDebug(KGRAPHEDITOR_LOG) << "Service Registered successfully";
0098         QDBusConnection::sessionBus().registerObject("/", this, QDBusConnection::ExportAllSlots);
0099 
0100     } else {
0101         qCDebug(KGRAPHEDITOR_LOG) << "Failed to register service...";
0102     }
0103 
0104     // Create a KParts part manager, to handle part activation/deactivation
0105     m_manager = new KParts::PartManager(this);
0106 
0107     // When the manager says the active part changes, the window updates (recreates) the GUI
0108     connect(m_manager, SIGNAL(activePartChanged(KParts::Part *)), this, SLOT(createGUI(KParts::Part *)));
0109 
0110     setupGUI(ToolBar | Keys | StatusBar | Save);
0111 
0112     // then, setup our actions
0113     setupActions();
0114 
0115     // this routine will find and load our Part.  it finds the Part by
0116     // name which is a bad idea usually.. but it's alright in this
0117     // case since our Part is made for this Shell
0118 
0119     // Creates the GUI with a null part to make appear the main app menus and tools
0120     createGUI(0);
0121 }
0122 
0123 KGraphEditor::~KGraphEditor()
0124 {
0125 }
0126 
0127 void KGraphEditor::reloadPreviousFiles()
0128 {
0129     QStringList previouslyOpenedFiles = KGraphEditorSettings::previouslyOpenedFiles();
0130     if ((previouslyOpenedFiles.empty() == false) && (QMessageBox::question(this, i18n("Session Restore"), i18n("Do you want to reload files from previous session?")) == QMessageBox::Yes)) {
0131         QStringList::const_iterator it, it_end;
0132         it = previouslyOpenedFiles.constBegin();
0133         it_end = previouslyOpenedFiles.constEnd();
0134         for (; it != it_end; it++) {
0135             openUrl(*it);
0136         }
0137     }
0138 }
0139 
0140 KParts::ReadOnlyPart *KGraphEditor::slotNewGraph()
0141 {
0142     KPluginFactory *factory = KPluginFactory::loadFactory(KPluginMetaData("kgraphviewerpart")).plugin;
0143     if (!factory) {
0144         // if we couldn't find our Part, we exit since the Shell by
0145         // itself can't do anything useful
0146         QMessageBox::critical(this, i18n("Unable to start"), i18n("Could not find the KGraphViewer part."));
0147         qApp->quit();
0148         // we return here, cause kapp->quit() only means "exit the
0149         // next time we enter the event loop...
0150         return nullptr;
0151     }
0152     KParts::ReadOnlyPart *part = factory->create<KParts::ReadOnlyPart>(this);
0153     KGraphViewerInterface *view = qobject_cast<KGraphViewerInterface *>(part);
0154     if (!view) {
0155         // This should not happen
0156         qCWarning(KGRAPHEDITOR_LOG) << "Failed to get KPart" << Qt::endl;
0157         return nullptr;
0158     }
0159     view->setReadWrite();
0160 
0161     QWidget *w = part->widget();
0162 
0163     m_tabsPartsMap[w] = part;
0164     m_tabsFilesMap[w] = "";
0165     connect(this, SIGNAL(hide(KParts::Part *)), part, SLOT(slotHide(KParts::Part *)));
0166 
0167     m_manager->addPart(part, true);
0168 
0169     m_widget->addTab(w, QIcon::fromTheme("kgraphviewer"), "");
0170     m_widget->setCurrentWidget(w);
0171     m_closeAction->setEnabled(true);
0172     return part;
0173 }
0174 
0175 void KGraphEditor::openUrl(const QUrl &url)
0176 {
0177     qCDebug(KGRAPHEDITOR_LOG) << url;
0178     KParts::ReadOnlyPart *part = slotNewGraph();
0179 
0180     //   (KGraphEditorSettings::parsingMode() == "external")
0181     //     ?kgv->setLayoutMethod(KGraphViewerInterface::ExternalProgram)
0182     //     :kgv->setLayoutMethod(KGraphViewerInterface::InternalLibrary);
0183 
0184     QString label = url.path().section('/', -1, -1);
0185     // @TODO set label
0186     m_widget->setTabText(m_widget->currentIndex(), label);
0187     m_tabsFilesMap[m_widget->currentWidget()] = url.path();
0188     part->openUrl(url);
0189 
0190     if (m_rfa) {
0191         m_rfa->addUrl(url);
0192     }
0193 
0194     m_openedFiles.push_back(url.path());
0195 }
0196 
0197 void KGraphEditor::fileOpen()
0198 {
0199     // this slot is called whenever the File->Open menu is selected,
0200     // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
0201     // button is clicked
0202     QFileDialog fileDialog(this);
0203     fileDialog.setMimeTypeFilters(QStringList(QStringLiteral("text/vnd.graphviz")));
0204     fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
0205     fileDialog.setFileMode(QFileDialog::ExistingFiles);
0206     if (fileDialog.exec() != QFileDialog::Accepted) {
0207         return;
0208     }
0209 
0210     for (const QUrl &url : fileDialog.selectedUrls()) {
0211         openUrl(url);
0212     }
0213 }
0214 
0215 void KGraphEditor::setupActions()
0216 {
0217     // create our actions
0218 
0219     actionCollection()->addAction(KStandardAction::New, "file_new", this, SLOT(fileNew()));
0220     actionCollection()->addAction(KStandardAction::Open, "file_open", this, SLOT(fileOpen()));
0221     m_rfa = (KRecentFilesAction *)actionCollection()->addAction(KStandardAction::OpenRecent, "file_open_recent", this, SLOT(slotURLSelected(QUrl)));
0222     m_rfa->loadEntries(KConfigGroup(KSharedConfig::openConfig(), "kgrapheditor"));
0223     actionCollection()->addAction(KStandardAction::Save, "file_save", this, SLOT(fileSave()));
0224     actionCollection()->addAction(KStandardAction::SaveAs, "file_save_as", this, SLOT(fileSaveAs()));
0225 
0226     m_closeAction = actionCollection()->addAction(KStandardAction::Close, "file_close", this, SLOT(close()));
0227     m_closeAction->setWhatsThis(i18n("Closes the current file"));
0228     m_closeAction->setEnabled(false);
0229 
0230     actionCollection()->addAction(KStandardAction::Quit, "file_quit", qApp, SLOT(quit()));
0231 
0232     m_statusbarAction = KStandardAction::showStatusbar(this, SLOT(optionsShowStatusbar()), this);
0233 
0234     actionCollection()->addAction(KStandardAction::ConfigureToolbars, "options_configure_toolbars", this, SLOT(optionsConfigureToolbars()));
0235     actionCollection()->addAction(KStandardAction::Preferences, "options_configure", this, SLOT(optionsConfigure()));
0236 
0237     QAction *edit_new_vertex = actionCollection()->addAction("edit_new_vertex");
0238     edit_new_vertex->setText(i18n("Create a New Vertex"));
0239     edit_new_vertex->setIcon(QPixmap(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kgraphviewerpart/pics/kgraphviewer-newnode.png")));
0240     connect(edit_new_vertex, SIGNAL(triggered(bool)), this, SLOT(slotEditNewVertex()));
0241 
0242     QAction *edit_new_edge = actionCollection()->addAction("edit_new_edge");
0243     edit_new_edge->setText(i18n("Create a New Edge"));
0244     edit_new_edge->setIcon(QPixmap(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kgraphviewerpart/pics/kgraphviewer-newedge.png")));
0245     connect(edit_new_edge, SIGNAL(triggered(bool)), this, SLOT(slotEditNewEdge()));
0246 }
0247 
0248 void KGraphEditor::closeEvent(QCloseEvent *event)
0249 {
0250     KGraphEditorSettings::setPreviouslyOpenedFiles(m_openedFiles);
0251     m_rfa->saveEntries(KConfigGroup(KSharedConfig::openConfig(), "kgrapheditor"));
0252 
0253     KGraphEditorSettings::self()->save();
0254     KXmlGuiWindow::closeEvent(event);
0255 }
0256 
0257 void KGraphEditor::fileNew()
0258 {
0259     // this slot is called whenever the File->New menu is selected,
0260     // the New shortcut is pressed (usually CTRL+N) or the New toolbar
0261     // button is clicked
0262 
0263     slotNewGraph();
0264 }
0265 
0266 void KGraphEditor::optionsShowToolbar()
0267 {
0268     // this is all very cut and paste code for showing/hiding the
0269     // toolbar
0270     if (m_toolbarAction->isChecked())
0271         toolBar()->show();
0272     else
0273         toolBar()->hide();
0274 }
0275 
0276 void KGraphEditor::optionsShowStatusbar()
0277 {
0278     // this is all very cut and paste code for showing/hiding the
0279     // statusbar
0280     if (m_statusbarAction->isChecked())
0281         statusBar()->show();
0282     else
0283         statusBar()->hide();
0284 }
0285 
0286 void KGraphEditor::optionsConfigureToolbars()
0287 {
0288     KConfigGroup conf(KConfigGroup(KSharedConfig::openConfig(), "kgrapheditor"));
0289     saveMainWindowSettings(conf);
0290 
0291     // use the standard toolbar editor
0292     KEditToolBar dlg(factory());
0293     connect(&dlg, SIGNAL(newToolbarConfig()), this, SLOT(applyNewToolbarConfig()));
0294     dlg.exec();
0295 }
0296 
0297 void KGraphEditor::optionsConfigure()
0298 {
0299     // An instance of your dialog could be already created and could be cached,
0300     // in which case you want to display the cached dialog instead of creating
0301     // another one
0302     if (KgeConfigurationDialog::showDialog("settings"))
0303         return;
0304 
0305     // KConfigDialog didn't find an instance of this dialog, so lets create it :
0306     KgeConfigurationDialog *dialog = new KgeConfigurationDialog(this, "settings", KGraphEditorSettings::self());
0307 
0308     Ui::KGraphViewerPreferencesParsingWidget *parsingWidget = dialog->m_parsingWidget;
0309     qCDebug(KGRAPHEDITOR_LOG) << KGraphEditorSettings::parsingMode();
0310     if (KGraphEditorSettings::parsingMode() == "external") {
0311         parsingWidget->external->setChecked(true);
0312     } else if (KGraphEditorSettings::parsingMode() == "internal") {
0313         parsingWidget->internal->setChecked(true);
0314     }
0315     connect((QObject *)parsingWidget->external, SIGNAL(toggled(bool)), this, SLOT(slotParsingModeExternalToggled(bool)));
0316     connect((QObject *)parsingWidget->internal, SIGNAL(toggled(bool)), this, SLOT(slotParsingModeInternalToggled(bool)));
0317 
0318     /*  KGraphViewerPreferencesReloadWidget*  reloadWidget =
0319           new KGraphViewerPreferencesReloadWidget( 0, "KGraphViewer Settings" );
0320       if (KGraphEditorSettings::reloadOnChangeMode() == "yes")
0321       {
0322         reloadWidget->reloadOnChangeMode->setButton(0);
0323       }
0324       else if (KGraphEditorSettings::reloadOnChangeMode() == "no")
0325       {
0326         reloadWidget->reloadOnChangeMode->setButton(1);
0327       }
0328       else if (KGraphEditorSettings::reloadOnChangeMode() == "ask")
0329       {
0330         reloadWidget->reloadOnChangeMode->setButton(2);
0331       }
0332 
0333       connect((QObject*)reloadWidget->reloadOnChangeMode, SIGNAL(clicked(int)), this, SLOT(reloadOnChangeMode_pressed(int)) );
0334 
0335       dialog->addPage( reloadWidget, i18n("Reloading"), "kgraphreloadoptions", i18n("Reloading"), true);
0336 
0337       KGraphViewerPreferencesOpenInExistingWindowWidget*  openingWidget =
0338         new KGraphViewerPreferencesOpenInExistingWindowWidget( 0, "KGraphViewer Settings" );
0339       if (KGraphEditorSettings::openInExistingWindowMode() == "yes")
0340       {
0341         openingWidget->openInExistingWindowMode->setButton(0);
0342       }
0343       else if (KGraphEditorSettings::openInExistingWindowMode() == "no")
0344       {
0345         openingWidget->openInExistingWindowMode->setButton(1);
0346       }
0347       else if (KGraphEditorSettings::openInExistingWindowMode() == "ask")
0348       {
0349         openingWidget->openInExistingWindowMode->setButton(2);
0350       }
0351 
0352       connect((QObject*)openingWidget->openInExistingWindowMode, SIGNAL(clicked(int)), this, SLOT(openInExistingWindowMode_pressed(int)) );
0353 
0354       dialog->addPage( openingWidget, i18n("Opening"), "kgraphopeningoptions", i18n("Opening"), true);
0355 
0356       KGraphViewerPreferencesReopenPreviouslyOpenedFilesWidget*  reopeningWidget =
0357         new KGraphViewerPreferencesReopenPreviouslyOpenedFilesWidget( 0, "KGraphViewer Settings" );
0358       if (KGraphEditorSettings::reopenPreviouslyOpenedFilesMode() == "yes")
0359       {
0360         reopeningWidget->reopenPreviouslyOpenedFilesMode->setButton(0);
0361       }
0362       else if (KGraphEditorSettings::reopenPreviouslyOpenedFilesMode() == "no")
0363       {
0364         reopeningWidget->reopenPreviouslyOpenedFilesMode->setButton(1);
0365       }
0366       else if (KGraphEditorSettings::reopenPreviouslyOpenedFilesMode() == "ask")
0367       {
0368         reopeningWidget->reopenPreviouslyOpenedFilesMode->setButton(2);
0369       }
0370 
0371       connect((QObject*)reopeningWidget->reopenPreviouslyOpenedFilesMode, SIGNAL(clicked(int)), this, SLOT(reopenPreviouslyOpenedFilesMode_pressed(int)) );
0372 
0373       dialog->addPage( reopeningWidget, i18n("Session Management"), "kgraphreopeningoptions", i18n("Session Management"), true);
0374       */
0375     //   connect(dialog, SIGNAL(settingsChanged()), this, SLOT(settingsChanged()));
0376 
0377     dialog->show();
0378 }
0379 
0380 void KGraphEditor::applyNewToolbarConfig()
0381 {
0382     applyMainWindowSettings(KConfigGroup(KSharedConfig::openConfig(), "kgrapheditor"));
0383 }
0384 
0385 // void KGraphViewer::reloadOnChangeMode_pressed(int value)
0386 // {
0387 //   qCDebug(KGRAPHEDITOR_LOG) << "reloadOnChangeMode_pressed " << value;
0388 //   switch (value)
0389 //   {
0390 //   case 0:
0391 //     KGraphEditorSettings::setReloadOnChangeMode("yes");
0392 //     break;
0393 //   case 1:
0394 //     KGraphEditorSettings::setReloadOnChangeMode("no");
0395 //     break;
0396 //   case 2:
0397 //     KGraphEditorSettings::setReloadOnChangeMode("ask");
0398 //     break;
0399 //   default:
0400 //   qCWarning(KGRAPHEDITOR_LOG) << "Invalid reload on change mode value: " << value;
0401 //     return;
0402 //   }
0403 //   qCDebug(KGRAPHEDITOR_LOG) << "emiting";
0404 //   emit(settingsChanged());
0405 //   KGraphEditorSettings::save();
0406 // }
0407 //
0408 // void KGraphViewer::openInExistingWindowMode_pressed(int value)
0409 // {
0410 //   std::cerr << "openInExistingWindowMode_pressed " << value << std::endl;
0411 //   switch (value)
0412 //   {
0413 //   case 0:
0414 //     KGraphEditorSettings::setOpenInExistingWindowMode("yes");
0415 //     break;
0416 //   case 1:
0417 //     KGraphEditorSettings::setOpenInExistingWindowMode("no");
0418 //     break;
0419 //   case 2:
0420 //     KGraphEditorSettings::setOpenInExistingWindowMode("ask");
0421 //     break;
0422 //   default:
0423 //   qCWarning(KGRAPHEDITOR_LOG) << "Invalid OpenInExistingWindow value: " << value << endl;
0424 //     return;
0425 //   }
0426 //
0427 //   std::cerr << "emiting" << std::endl;
0428 //   emit(settingsChanged());
0429 //   KGraphEditorSettings::save();
0430 // }
0431 //
0432 // void KGraphViewer::reopenPreviouslyOpenedFilesMode_pressed(int value)
0433 // {
0434 //   std::cerr << "reopenPreviouslyOpenedFilesMode_pressed " << value << std::endl;
0435 //   switch (value)
0436 //   {
0437 //   case 0:
0438 //     KGraphEditorSettings::setReopenPreviouslyOpenedFilesMode("yes");
0439 //     break;
0440 //   case 1:
0441 //     KGraphEditorSettings::setReopenPreviouslyOpenedFilesMode("no");
0442 //     break;
0443 //   case 2:
0444 //     KGraphEditorSettings::setReopenPreviouslyOpenedFilesMode("ask");
0445 //     break;
0446 //   default:
0447 //   qCWarning(KGRAPHEDITOR_LOG) << "Invalid ReopenPreviouslyOpenedFilesMode value: " << value << endl;
0448 //     return;
0449 //   }
0450 //
0451 //   std::cerr << "emiting" << std::endl;
0452 //   emit(settingsChanged());
0453 //   KGraphEditorSettings::save();
0454 // }
0455 
0456 void KGraphEditor::slotURLSelected(const QUrl &url)
0457 {
0458     openUrl(url);
0459 }
0460 
0461 void KGraphEditor::close(int index)
0462 {
0463     QWidget *tab = m_widget->widget(index);
0464     m_openedFiles.removeAll(m_tabsFilesMap[tab]);
0465     m_widget->removeTab(index);
0466     tab->hide();
0467     KParts::ReadOnlyPart *part = m_tabsPartsMap[tab];
0468     m_manager->removePart(part);
0469     m_tabsPartsMap.remove(tab);
0470     m_tabsFilesMap.remove(tab);
0471     delete part;
0472     part = nullptr;
0473     /*  delete tab;
0474       tab = nullptr;*/
0475     m_closeAction->setEnabled(m_widget->count() > 0);
0476 }
0477 
0478 void KGraphEditor::close()
0479 {
0480     int currentPage = m_widget->currentIndex();
0481     if (currentPage != -1) {
0482         close(currentPage);
0483     }
0484 }
0485 
0486 void KGraphEditor::fileSave()
0487 {
0488     QWidget *currentPage = m_widget->currentWidget();
0489     if (currentPage) {
0490         emit(saveTo(QUrl(m_tabsFilesMap[currentPage]).path()));
0491     }
0492 }
0493 
0494 void KGraphEditor::fileSaveAs()
0495 {
0496     QWidget *currentPage = m_widget->currentWidget();
0497     if (currentPage) {
0498         QFileDialog fileDialog(currentPage, i18n("Save current graph"));
0499         fileDialog.setMimeTypeFilters(QStringList(QStringLiteral("text/vnd.graphviz")));
0500         fileDialog.setAcceptMode(QFileDialog::AcceptSave);
0501         if (fileDialog.exec() != QFileDialog::Accepted) {
0502             return;
0503         }
0504         const QString fileName = fileDialog.selectedFiles().at(0);
0505         if (fileName.isEmpty()) {
0506             return;
0507         }
0508 
0509         m_tabsFilesMap[currentPage] = fileName;
0510         emit(saveTo(fileName));
0511     }
0512 }
0513 
0514 void KGraphEditor::newTabSelectedSlot(int index)
0515 {
0516     //   qCDebug(KGRAPHEDITOR_LOG) << tab;
0517     emit(hide((KParts::Part *)(m_manager->activePart())));
0518     QWidget *tab = m_widget->widget(index);
0519     if (tab) {
0520         slotSetActiveGraph(m_tabsPartsMap[tab]);
0521         m_manager->setActivePart(m_tabsPartsMap[tab]);
0522     }
0523 }
0524 
0525 void KGraphEditor::slotSetActiveGraph(KParts::ReadOnlyPart *part)
0526 {
0527     if (m_currentPart) {
0528         disconnect(this, SIGNAL(prepareAddNewElement(QMap<QString, QString>)), m_currentPart, SLOT(prepareAddNewElement(QMap<QString, QString>)));
0529         disconnect(this, SIGNAL(prepareAddNewEdge(QMap<QString, QString>)), m_currentPart, SLOT(prepareAddNewEdge(QMap<QString, QString>)));
0530         disconnect(this, SIGNAL(saveTo(QString)), m_currentPart, SLOT(saveTo(QString)));
0531         disconnect(this, SIGNAL(removeNode(QString)), m_currentPart, SLOT(slotRemoveNode(QString)));
0532         disconnect(this, SIGNAL(addAttribute(QString)), m_currentPart, SLOT(slotAddAttribute(QString)));
0533         disconnect(this, SIGNAL(removeAttribute(QString, QString)), m_currentPart, SLOT(slotRemoveAttribute(QString, QString)));
0534         disconnect(this, SIGNAL(update()), m_currentPart, SLOT(slotUpdate()));
0535         disconnect(this, SIGNAL(selectNode(QString)), m_currentPart, SLOT(slotSelectNode(QString)));
0536         disconnect(this, SIGNAL(saddNewEdge(QString, QString, QMap<QString, QString>)), m_currentPart, SLOT(slotAddNewEdge(QString, QString, QMap<QString, QString>)));
0537         disconnect(this, SIGNAL(renameNode(QString, QString)), m_currentPart, SLOT(slotRenameNode(QString, QString)));
0538         disconnect(this, SIGNAL(setAttribute(QString, QString, QString)), m_currentPart, SLOT(slotSetAttribute(QString, QString, QString)));
0539     }
0540     m_currentPart = part;
0541     m_treeWidget->clear();
0542     if (m_currentPart == nullptr) {
0543         return;
0544     }
0545     connect(this, SIGNAL(prepareAddNewElement(QMap<QString, QString>)), part, SLOT(prepareAddNewElement(QMap<QString, QString>)));
0546     connect(this, SIGNAL(prepareAddNewEdge(QMap<QString, QString>)), part, SLOT(prepareAddNewEdge(QMap<QString, QString>)));
0547     connect(this, SIGNAL(saveTo(QString)), part, SLOT(saveTo(QString)));
0548     connect(this, SIGNAL(removeNode(QString)), part, SLOT(slotRemoveNode(QString)));
0549     connect(this, SIGNAL(addAttribute(QString)), part, SLOT(slotAddAttribute(QString)));
0550     connect(this, SIGNAL(removeAttribute(QString, QString)), part, SLOT(slotRemoveAttribute(QString, QString)));
0551     connect(this, SIGNAL(update()), part, SLOT(slotUpdate()));
0552     connect(this, SIGNAL(selectNode(QString)), part, SLOT(slotSelectNode(QString)));
0553     connect(this, SIGNAL(removeElement(QString)), m_currentPart, SLOT(slotRemoveElement(QString)));
0554     connect(this, SIGNAL(saddNewEdge(QString, QString, QMap<QString, QString>)), m_currentPart, SLOT(slotAddNewEdge(QString, QString, QMap<QString, QString>)));
0555     connect(this, SIGNAL(renameNode(QString, QString)), m_currentPart, SLOT(slotRenameNode(QString, QString)));
0556     connect(this, SIGNAL(setAttribute(QString, QString, QString)), m_currentPart, SLOT(slotSetAttribute(QString, QString, QString)));
0557 
0558     QList<QString> nodesIds; // TODO = m_currentPart->nodesIds();
0559     QList<QTreeWidgetItem *> items;
0560     for (const QString &nodeId : nodesIds) {
0561         qCDebug(KGRAPHEDITOR_LOG) << "new item " << nodeId;
0562         QTreeWidgetItem *item = new QTreeWidgetItem((QTreeWidget *)nullptr, QStringList(nodeId));
0563         item->setFlags(item->flags() | Qt::ItemIsEditable);
0564         QMap<QString, QString> attributes; // TODO = m_currentPart->nodeAtributes(nodeId);
0565         for (const QString &attrib : attributes.keys()) {
0566             if (attrib != "_draw_" && attrib != "_ldraw_") {
0567                 QStringList list(attrib);
0568                 list << attributes[attrib];
0569                 QTreeWidgetItem *child = new QTreeWidgetItem((QTreeWidget *)nullptr, list);
0570                 child->setFlags(child->flags() | Qt::ItemIsEditable);
0571                 item->addChild(child);
0572             }
0573         }
0574         items.append(item);
0575     }
0576     qCDebug(KGRAPHEDITOR_LOG) << "inserting";
0577     m_treeWidget->insertTopLevelItems(0, items);
0578 
0579     connect(m_currentPart, SIGNAL(graphLoaded()), this, SLOT(slotGraphLoaded()));
0580 
0581     connect(m_currentPart, SIGNAL(newNodeAdded(QString)), this, SLOT(slotNewNodeAdded(QString)));
0582 
0583     connect(m_currentPart, SIGNAL(newEdgeAdded(QString, QString)), this, SLOT(slotNewEdgeAdded(QString, QString)));
0584 
0585     connect(m_currentPart, SIGNAL(removeElement(QString)), this, SLOT(slotRemoveElement(QString)));
0586 
0587     connect(m_currentPart, SIGNAL(selectionIs(QList<QString>, QPoint)), this, SLOT(slotSelectionIs(QList<QString>, QPoint)));
0588 
0589     connect(m_currentPart, SIGNAL(newEdgeFinished(QString, QString, QMap<QString, QString>)), this, SLOT(slotNewEdgeFinished(QString, QString, QMap<QString, QString>)));
0590 
0591     connect(m_currentPart, SIGNAL(hoverEnter(QString)), this, SLOT(slotHoverEnter(QString)));
0592 
0593     connect(m_currentPart, SIGNAL(hoverLeave(QString)), this, SLOT(slotHoverLeave(QString)));
0594 }
0595 
0596 void KGraphEditor::slotNewNodeAdded(const QString &id)
0597 {
0598     qCDebug(KGRAPHEDITOR_LOG) << id;
0599     update();
0600 }
0601 
0602 void KGraphEditor::slotNewEdgeAdded(const QString &ids, const QString &idt)
0603 {
0604     qCDebug(KGRAPHEDITOR_LOG) << ids << idt;
0605     update();
0606 }
0607 
0608 void KGraphEditor::slotNewEdgeFinished(const QString &srcId, const QString &tgtId, const QMap<QString, QString> &attribs)
0609 {
0610     qCDebug(KGRAPHEDITOR_LOG) << srcId << tgtId << attribs;
0611     emit saddNewEdge(srcId, tgtId, attribs);
0612     update();
0613 }
0614 
0615 void KGraphEditor::slotGraphLoaded()
0616 {
0617     qCDebug(KGRAPHEDITOR_LOG);
0618     disconnect(m_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotItemChanged(QTreeWidgetItem *, int)));
0619     disconnect(m_treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(slotItemClicked(QTreeWidgetItem *, int)));
0620 
0621     QList<QString> nodesIds; // TODO = m_currentPart->nodesIds();
0622     QList<QTreeWidgetItem *> items;
0623     for (const QString &nodeId : nodesIds) {
0624         qCDebug(KGRAPHEDITOR_LOG) << "item " << nodeId;
0625         QTreeWidgetItem *item;
0626         QList<QTreeWidgetItem *> existingItems = m_treeWidget->findItems(nodeId, Qt::MatchRecursive | Qt::MatchExactly);
0627         if (existingItems.isEmpty()) {
0628             item = new QTreeWidgetItem((QTreeWidget *)nullptr, QStringList(nodeId));
0629             items.append(item);
0630         } else {
0631             item = existingItems[0];
0632         }
0633         item->setFlags(item->flags() | Qt::ItemIsEditable);
0634         QMap<QString, QString> attributes; // TODO = m_currentPart->nodeAtributes(nodeId);
0635         QList<QString> keys = attributes.keys();
0636         for (int i = 0; i < item->childCount(); i++) {
0637             if (keys.contains(item->child(i)->text(0))) {
0638                 item->child(i)->setText(1, attributes[item->child(i)->text(0)]);
0639                 keys.removeAll(item->child(i)->text(0));
0640             }
0641         }
0642         for (const QString &attrib : keys) {
0643             if (attrib != "_draw_" && attrib != "_ldraw_") {
0644                 QStringList list(attrib);
0645                 list << attributes[attrib];
0646                 QTreeWidgetItem *child = new QTreeWidgetItem((QTreeWidget *)nullptr, list);
0647                 child->setFlags(child->flags() | Qt::ItemIsEditable);
0648                 item->addChild(child);
0649             }
0650         }
0651     }
0652     qCDebug(KGRAPHEDITOR_LOG) << "inserting";
0653     m_treeWidget->insertTopLevelItems(0, items);
0654     connect(m_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotItemChanged(QTreeWidgetItem *, int)));
0655     connect(m_treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(slotItemClicked(QTreeWidgetItem *, int)));
0656 }
0657 
0658 void KGraphEditor::slotItemChanged(QTreeWidgetItem *item, int column)
0659 {
0660     qCDebug(KGRAPHEDITOR_LOG);
0661     /* values column */
0662     if (column == 0) {
0663         QString oldNodeName = m_currentTreeWidgetItemText;
0664         QString newNodeName = item->text(0);
0665         emit(renameNode(oldNodeName, newNodeName));
0666     } else if (column == 1) {
0667         /* there is a parent ; it is an attribute line */
0668         if (item->parent()) {
0669             QString nodeLabel = item->parent()->text(0);
0670             QString attributeName = item->text(0);
0671             QString attributeValue = item->text(1);
0672             emit(setAttribute(nodeLabel, attributeName, attributeValue));
0673         }
0674     }
0675     emit update();
0676 }
0677 
0678 void KGraphEditor::slotItemClicked(QTreeWidgetItem *item, int column)
0679 {
0680     qCDebug(KGRAPHEDITOR_LOG) << column;
0681     m_currentTreeWidgetItemText = item->text(0);
0682 
0683     QString nodeName = item->parent() ? item->parent()->text(0) : item->text(0);
0684     emit selectNode(nodeName);
0685 }
0686 
0687 void KGraphEditor::slotEditNewVertex()
0688 {
0689     if (m_currentPart == nullptr) {
0690         qCDebug(KGRAPHEDITOR_LOG) << "new vertex: no part selected";
0691         return;
0692     }
0693     qCDebug(KGRAPHEDITOR_LOG) << "new vertex";
0694     emit(prepareAddNewElement(m_newElementAttributes));
0695 }
0696 
0697 void KGraphEditor::slotEditNewEdge()
0698 {
0699     if (m_currentPart == nullptr) {
0700         qCDebug(KGRAPHEDITOR_LOG) << "new edge: no part selected";
0701         return;
0702     }
0703     qCDebug(KGRAPHEDITOR_LOG) << "new edge";
0704     emit(prepareAddNewEdge(m_newElementAttributes));
0705 }
0706 
0707 void KGraphEditor::slotRemoveNode(const QString &nodeName)
0708 {
0709     emit removeNode(nodeName);
0710     emit update();
0711 }
0712 
0713 void KGraphEditor::slotAddAttribute(const QString &attribName)
0714 {
0715     emit addAttribute(attribName);
0716     emit update();
0717 }
0718 
0719 void KGraphEditor::slotRemoveAttribute(const QString &nodeName, const QString &attribName)
0720 {
0721     emit removeAttribute(nodeName, attribName);
0722     emit update();
0723 }
0724 
0725 void KGraphEditor::slotNewElementItemChanged(QTreeWidgetItem *item, int column)
0726 {
0727     qCDebug(KGRAPHEDITOR_LOG);
0728     if (column == 0) {
0729         qCWarning(KGRAPHEDITOR_LOG) << "Item id change not handled";
0730         return;
0731     } else if (column == 1) {
0732         m_newElementAttributes[item->text(0)] = item->text(1);
0733     } else {
0734         qCWarning(KGRAPHEDITOR_LOG) << "Unknown column" << column;
0735         return;
0736     }
0737 }
0738 
0739 void KGraphEditor::slotAddNewElementAttribute(const QString &attrib)
0740 {
0741     m_newElementAttributes[attrib] = QString();
0742 }
0743 
0744 void KGraphEditor::slotRemoveNewElementAttribute(const QString &attrib)
0745 {
0746     m_newElementAttributes.remove(attrib);
0747 }
0748 
0749 void KGraphEditor::slotRemoveElement(const QString &id)
0750 {
0751     qCDebug(KGRAPHEDITOR_LOG) << id;
0752     m_treeWidget->slotRemoveElement(id);
0753     emit(removeElement(id));
0754 }
0755 
0756 void KGraphEditor::slotSelectionIs(const QList<QString> &elements, const QPoint &p)
0757 {
0758     qCDebug(KGRAPHEDITOR_LOG);
0759     Q_UNUSED(p);
0760     QList<QTreeWidgetItem *> items = m_treeWidget->selectedItems();
0761     for (QTreeWidgetItem *item : items) {
0762         item->setSelected(false);
0763     }
0764     for (const QString &elementName : elements) {
0765         QList<QTreeWidgetItem *> items = m_treeWidget->findItems(elementName, Qt::MatchExactly, 0);
0766         for (QTreeWidgetItem *item : items) {
0767             item->setSelected(true);
0768         }
0769     }
0770 }
0771 
0772 void KGraphEditor::slotParsingModeExternalToggled(bool value)
0773 {
0774     if (value) {
0775         KGraphEditorSettings::setParsingMode("external");
0776     }
0777     //   qCDebug(KGRAPHEDITOR_LOG) << "emiting";
0778     //   emit(settingsChanged());
0779     KGraphEditorSettings::self()->save();
0780 }
0781 
0782 void KGraphEditor::slotParsingModeInternalToggled(bool value)
0783 {
0784     if (value) {
0785         KGraphEditorSettings::setParsingMode("internal");
0786     }
0787     //   qCDebug(KGRAPHEDITOR_LOG) << "emiting";
0788     //   emit(settingsChanged());
0789     KGraphEditorSettings::self()->save();
0790 }
0791 
0792 void KGraphEditor::slotHoverEnter(const QString &id)
0793 {
0794     qCDebug(KGRAPHEDITOR_LOG) << id;
0795     statusBar()->showMessage(id);
0796 }
0797 
0798 void KGraphEditor::slotHoverLeave(const QString &id)
0799 {
0800     qCDebug(KGRAPHEDITOR_LOG) << id;
0801     statusBar()->showMessage("");
0802 }
0803 
0804 #include "moc_kgrapheditor.cpp"