summaryrefslogtreecommitdiffstats
path: root/quanta/utility
diff options
context:
space:
mode:
Diffstat (limited to 'quanta/utility')
-rw-r--r--quanta/utility/Makefile.am20
-rw-r--r--quanta/utility/myprocess.h36
-rw-r--r--quanta/utility/newstuff.cpp144
-rw-r--r--quanta/utility/newstuff.h121
-rw-r--r--quanta/utility/qpevents.cpp403
-rw-r--r--quanta/utility/qpevents.h90
-rw-r--r--quanta/utility/quantabookmarks.cpp399
-rw-r--r--quanta/utility/quantabookmarks.h99
-rw-r--r--quanta/utility/quantacommon.cpp753
-rw-r--r--quanta/utility/quantacommon.h225
-rw-r--r--quanta/utility/quantanetaccess.cpp268
-rw-r--r--quanta/utility/quantanetaccess.h86
-rw-r--r--quanta/utility/resource.h59
-rw-r--r--quanta/utility/tagaction.cpp1285
-rw-r--r--quanta/utility/tagaction.h137
-rw-r--r--quanta/utility/tagactionmanager.cpp83
-rw-r--r--quanta/utility/tagactionmanager.h74
-rw-r--r--quanta/utility/tagactionset.cpp1172
-rw-r--r--quanta/utility/tagactionset.h161
-rw-r--r--quanta/utility/toolbartabwidget.cpp351
-rw-r--r--quanta/utility/toolbartabwidget.h111
-rw-r--r--quanta/utility/toolbarxmlgui.cpp27
-rw-r--r--quanta/utility/toolbarxmlgui.h32
23 files changed, 6136 insertions, 0 deletions
diff --git a/quanta/utility/Makefile.am b/quanta/utility/Makefile.am
new file mode 100644
index 00000000..56522430
--- /dev/null
+++ b/quanta/utility/Makefile.am
@@ -0,0 +1,20 @@
+noinst_LTLIBRARIES = libutility.la
+
+METASOURCES = AUTO
+
+libutility_la_SOURCES = quantacommon.cpp tagaction.cpp toolbartabwidget.cpp \
+ toolbarxmlgui.cpp newstuff.cpp quantanetaccess.cpp qpevents.cpp quantabookmarks.cpp \
+ tagactionmanager.cpp tagactionset.cpp
+
+AM_CPPFLAGS = -I$(top_srcdir)/quanta/src \
+ -I$(top_srcdir)/quanta/parsers \
+ -I$(top_srcdir)/quanta/messages \
+ -I$(top_srcdir)/quanta/dialogs/tagdialogs \
+ -I$(top_srcdir)/quanta/parts/kafka \
+ -I$(top_srcdir)/quanta/project \
+ -I$(top_srcdir)/lib \
+ $(KNEWSTUFF_INCLUDES) \
+ $(KMDI_INCLUDES) $(all_includes)
+
+libutility_la_LDFLAGS = $(all_libraries)
+noinst_HEADERS = qpevents.h tagactionmanager.h tagactionset.h
diff --git a/quanta/utility/myprocess.h b/quanta/utility/myprocess.h
new file mode 100644
index 00000000..a495cdf9
--- /dev/null
+++ b/quanta/utility/myprocess.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ myprocess.h
+ -------------------
+ begin : Jun 25 2003
+ copyright : (C) 2003 by Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYPROCESS_H
+#define MYPROCESS_H
+
+#include <kprocess.h>
+
+class MyProcess:public KProcess
+{
+ Q_OBJECT
+
+ public:
+ MyProcess();
+ virtual ~MyProcess() {};
+
+ protected:
+ virtual int commSetupDoneC();
+};
+
+
+
+#endif
+
diff --git a/quanta/utility/newstuff.cpp b/quanta/utility/newstuff.cpp
new file mode 100644
index 00000000..f6cbf397
--- /dev/null
+++ b/quanta/utility/newstuff.cpp
@@ -0,0 +1,144 @@
+/***************************************************************************
+ newstuff.cpp - description
+ -------------------
+ begin : Tue Jun 22 12:19:55 2004
+ copyright : (C) 2004 by Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+ //qt includes
+#include <qfileinfo.h>
+
+//kde includes
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <ktar.h>
+
+//app includes
+#include "newstuff.h"
+#include "dtds.h"
+#include "resource.h"
+#include "quantacommon.h"
+#include "qextfileinfo.h"
+
+void QNewDTEPStuff::installResource()
+{
+ bool ok = true;
+ KTar tar(m_tarName, "application/x-gzip");
+ if (tar.open(IO_ReadOnly))
+ {
+ const KArchiveDirectory *directory = tar.directory();
+ QString dtepDir =KGlobal::dirs()->saveLocation("data") + resourceDir + "dtep/";
+ QString dtdName = (*directory->entries().at(0));
+ if (dtdName.isEmpty())
+ {
+ ok = false;
+ } else
+ {
+ directory->copyTo(dtepDir, true);
+ DTDs::ref()->slotLoadDTEP(dtepDir + dtdName, false);
+ }
+ tar.close();
+ } else
+ ok = false;
+ if (!ok)
+ KMessageBox::error(parentWidget(), i18n("There was an error with the downloaded DTEP tarball file. Possible causes are damaged archive or invalid directory structure in the archive."), i18n("DTEP Installation Error"));
+}
+
+QNewToolbarStuff::QNewToolbarStuff(const QString &type, QWidget *parentWidget)
+ :KNewStuffSecure(type, parentWidget)
+{
+ connect(this, SIGNAL(loadToolbarFile(const KURL&)), parentWidget, SLOT(slotLoadToolbarFile(const KURL&)));
+}
+
+
+void QNewToolbarStuff::installResource()
+{
+ KURL destURL = KURL::fromPathOrURL(KGlobal::dirs()->saveLocation("data") + resourceDir + "toolbars/" + QFileInfo(m_tarName).fileName());
+ bool ok = true;
+ if (QuantaCommon::checkOverwrite(destURL, parentWidget()))
+ {
+ if (!QExtFileInfo::copy(KURL::fromPathOrURL(m_tarName), destURL, -1, true, false, parentWidget()))
+ ok = false;
+ else
+ {
+ if (KMessageBox::questionYesNo(parentWidget(), i18n("Do you want to load the newly downloaded toolbar?"), i18n("Load Toolbar"), i18n("Load"), KStdGuiItem::cancel()) == KMessageBox::Yes)
+ {
+ emit loadToolbarFile(destURL);
+ }
+ }
+ if (!ok)
+ KMessageBox::error(parentWidget(), i18n("There was an error with the downloaded toolbar tarball file. Possible causes are damaged archive or invalid directory structure in the archive."), i18n("Toolbar Installation Error"));
+ }
+}
+
+QNewTemplateStuff::QNewTemplateStuff(const QString &type, QWidget *parentWidget)
+ :KNewStuffSecure(type, parentWidget)
+{
+ connect(this, SIGNAL(openFile(const KURL&)), parentWidget, SLOT(slotFileOpen(const KURL&)));
+}
+
+
+void QNewTemplateStuff::installResource()
+{
+ KURL destURL = KURL::fromPathOrURL(KGlobal::dirs()->saveLocation("data") + resourceDir + "templates/" + QFileInfo(m_tarName).fileName());
+ bool ok = true;
+ if (QuantaCommon::checkOverwrite(destURL, parentWidget()))
+ {
+ if (!QExtFileInfo::copy(KURL::fromPathOrURL(m_tarName), destURL, -1, true, false, parentWidget()))
+ ok = false;
+ else
+ {
+ if (KMessageBox::questionYesNo(parentWidget(), i18n("Do you want to open the newly downloaded template?"), i18n("Open Template"), KStdGuiItem::open(), KStdGuiItem::cancel()) == KMessageBox::Yes)
+ {
+ emit openFile(destURL);
+ }
+ }
+ if (!ok)
+ KMessageBox::error(parentWidget(), i18n("There was an error with the downloaded template file."), i18n("Template Installation Error"));
+ }
+}
+
+void QNewScriptStuff::installResource()
+{
+ bool ok = true;
+ KTar tar(m_tarName, "application/x-gzip");
+ if (tar.open(IO_ReadOnly))
+ {
+ const KArchiveDirectory *directory = tar.directory();
+ QString scriptsDir =KGlobal::dirs()->saveLocation("data") + resourceDir + "scripts/";
+ directory->copyTo(scriptsDir, true);
+ tar.close();
+ } else
+ ok = false;
+
+ if (!ok)
+ KMessageBox::error(parentWidget(), i18n("There was an error with the downloaded script tarball file. Possible causes are damaged archive or invalid directory structure in the archive."), i18n("Script Installation Error"));
+}
+
+void QNewDocStuff::installResource()
+{
+ bool ok = true;
+ KTar tar(m_tarName, "application/x-gzip");
+ if (tar.open(IO_ReadOnly))
+ {
+ const KArchiveDirectory *directory = tar.directory();
+ QString docDir =KGlobal::dirs()->saveLocation("data") + resourceDir + "doc/";
+ directory->copyTo(docDir, true);
+ tar.close();
+ } else
+ ok = false;
+
+ if (!ok)
+ KMessageBox::error(parentWidget(), i18n("There was an error with the downloaded script tarball file. Possible causes are damaged archive or invalid directory structure in the archive."), i18n("Documentation Installation Error"));
+}
+
+#include "newstuff.moc"
diff --git a/quanta/utility/newstuff.h b/quanta/utility/newstuff.h
new file mode 100644
index 00000000..dd2ad104
--- /dev/null
+++ b/quanta/utility/newstuff.h
@@ -0,0 +1,121 @@
+/***************************************************************************
+ newstuff.h - description
+ -------------------
+ begin : Tue Jun 22 12:19:55 2004
+ copyright : (C) 2004 by Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+#ifndef NEWSTUFF_H
+#define NEWSTUFF_H
+
+//qt includes
+#include <qobject.h>
+
+//kde includes
+#include <knewstuff/knewstuffsecure.h>
+/**
+Makes possible downloading and installing a DTEP resource files from a server.
+
+@author Andras Mantia
+*/
+
+class KURL;
+
+class QNewDTEPStuff: public KNewStuffSecure
+{
+ Q_OBJECT
+
+public:
+ QNewDTEPStuff(const QString &type, QWidget *parentWidget=0)
+ :KNewStuffSecure(type, parentWidget){};
+ ~QNewDTEPStuff() {};
+
+private:
+ virtual void installResource();
+};
+
+/**
+Makes possible downloading and installing a Toolbar resource files from a server.
+
+@author Andras Mantia
+*/
+class QNewToolbarStuff: public KNewStuffSecure
+{
+ Q_OBJECT
+
+public:
+ QNewToolbarStuff(const QString &type, QWidget *parentWidget=0);
+ ~QNewToolbarStuff() {};
+
+signals:
+ void loadToolbarFile(const KURL&);
+
+private:
+ virtual void installResource();
+};
+
+/**
+Makes possible downloading and installing a template resource files from a server.
+
+@author Andras Mantia
+*/
+class QNewTemplateStuff: public KNewStuffSecure
+{
+ Q_OBJECT
+
+public:
+ QNewTemplateStuff(const QString &type, QWidget *parentWidget=0);
+ ~QNewTemplateStuff() {};
+
+signals:
+ void openFile(const KURL&);
+
+private:
+ virtual void installResource();
+};
+
+/**
+Makes possible downloading and installing a script resource files from a server.
+
+@author Andras Mantia
+*/
+class QNewScriptStuff: public KNewStuffSecure
+{
+ Q_OBJECT
+
+public:
+ QNewScriptStuff(const QString &type, QWidget *parentWidget=0)
+ :KNewStuffSecure(type, parentWidget){};
+ ~QNewScriptStuff() {};
+
+private:
+ virtual void installResource();
+};
+
+/**
+Makes possible downloading and installing a documentation resource files from a server.
+
+@author Andras Mantia
+ */
+class QNewDocStuff: public KNewStuffSecure
+{
+ Q_OBJECT
+
+ public:
+ QNewDocStuff(const QString &type, QWidget *parentWidget=0)
+ :KNewStuffSecure(type, parentWidget){};
+ ~QNewDocStuff() {};
+
+ private:
+ virtual void installResource();
+};
+
+#endif
diff --git a/quanta/utility/qpevents.cpp b/quanta/utility/qpevents.cpp
new file mode 100644
index 00000000..bb0d5db4
--- /dev/null
+++ b/quanta/utility/qpevents.cpp
@@ -0,0 +1,403 @@
+/***************************************************************************
+ qpevents.cpp - description
+ -------------------
+ begin : Sun Jul 11 2004
+ copyright : (C) 2004 Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+//qt includes
+#include <qdatetime.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+//kde includes
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+//app includes
+#include "qpevents.h"
+#include "document.h"
+#include "project.h"
+#include "qextfileinfo.h"
+#include "viewmanager.h"
+#include "resource.h"
+#include "quanta.h"
+#include "tagaction.h"
+
+//TODO: Better create a class for each internal event action
+QPEvents::QPEvents(QObject *parent, const char *name)
+ : QObject(parent, name)
+{
+ m_eventNames["before_save"] = i18n("Before Document Save");
+ m_eventNames["after_save"] = i18n("After Document Save");
+ m_eventNames["after_open"] = i18n("After Document Open");
+ m_eventNames["before_close"] = i18n("Before Document Close");
+ m_eventNames["after_close"] = i18n("After Document Close");
+ m_eventNames["after_project_open"] = i18n("After Project Open");
+ m_eventNames["before_project_close"] = i18n("Before Project Close");
+ m_eventNames["after_project_close"] = i18n("After Project Close");
+ m_eventNames["upload_requested"] = i18n("Upload Requested");
+ m_eventNames["before_upload"] = i18n("Before Document Upload");
+ m_eventNames["after_upload"] = i18n("After Document Upload");
+ m_eventNames["after_project_add"] = i18n("After Addition to Project");
+ m_eventNames["after_project_remove"] = i18n("After Removal From Project");
+ m_eventNames["after_commit"] = i18n("After Commit to CVS");
+ m_eventNames["after_update"] = i18n("After Update From CVS");
+ m_eventNames["after_file_move"] = i18n("After Moving File Inside Project");
+ m_eventNames["quanta_start"] = i18n("Quanta Start");
+ m_eventNames["quanta_exit"] = i18n("Quanta Exit");
+// m_eventNames["after_multiple_save"] = i18n("After saving more files at once (like Save All)");
+
+ m_actionNames["email"] = i18n("Send Email");
+ m_actionNames["log"] = i18n("Log Event");
+ m_actionNames["script"] = i18n("Script Action");
+ m_actionNames["action"] = i18n("Non-Script Action");
+}
+
+
+QPEvents::~QPEvents()
+{
+}
+
+void QPEvents::slotEventHappened(const QString& name, const QString& argument1, const QString& argument2)
+{
+ if (!quantaApp || !Project::ref()->eventsEnabled())
+ return;
+ EventActions *events = Project::ref()->events();
+ if (!events) return;
+ if (events->contains(name))
+ {
+ m_eventName = name;
+ QValueList<EventAction> evList = (*events)[name];
+ for (QValueList<EventAction>::Iterator it = evList.begin(); it != evList.end(); ++it)
+ {
+ EventAction ev = *it;
+ if (ev.type == EventAction::Internal)
+ {
+ if (KMessageBox::warningContinueCancel(0L, i18n("<qt>An internal action (<i>%1</i>) associated with an event (<i>%2</i>) will be executed. Do you want to allow the execution of this action?</qt>").arg(ev.action).arg(name), i18n("Event Triggered"), i18n("Execute"), "Warn about internal actions") == KMessageBox::Cancel)
+ return;
+ } else
+ {
+ if (KMessageBox::warningContinueCancel(0L, i18n("<qt>An external action (<i>%1</i>) associated with an event (<i>%2</i>) will be executed. Do you want to allow the execution of this action?</qt>").arg(ev.action).arg(name), i18n("Event Triggered"), i18n("Execute"), "Warn about external actions") == KMessageBox::Cancel)
+ return;
+ }
+ KURL url = KURL::fromPathOrURL(argument1);
+ KURL url2 = KURL::fromPathOrURL(argument2);
+ if (url.isValid())
+ {
+ bool inProject = Project::ref()->contains(url);
+ if (inProject)
+ {
+ if (name == "upload_requested")
+ {
+ ev.arguments << i18n("An upload was initiated");
+ ev.arguments << url.path();
+ handleEvent(ev);
+ }
+ }
+ if (inProject && url2.isValid())
+ {
+ if (name == "before_upload")
+ {
+ ev.arguments << i18n("About to upload a document");
+ ev.arguments << url.path();
+ ev.arguments << url2.path();
+ handleEvent(ev);
+ } else
+ if (name == "after_upload")
+ {
+ ev.arguments << i18n("Document uploaded");
+ ev.arguments << url.path();
+ ev.arguments << url2.path();
+ handleEvent(ev);
+ } else
+ if (name == "after_file_move")
+ {
+ ev.arguments << i18n("Document moved");
+ ev.arguments << url.path();
+ ev.arguments << url2.path();
+ handleEvent(ev);
+ }
+ } else
+ {
+ QString relativePath = QExtFileInfo::toRelative(url, Project::ref()->projectBaseURL()).path();
+ if (inProject && name == "after_save")
+ {
+ ev.arguments << i18n("Document saved");
+ ev.arguments << relativePath;
+ handleEvent(ev);
+ } else
+ if (inProject && name == "before_save")
+ {
+ ev.arguments << i18n("About to save a document");
+ ev.arguments << relativePath;
+ handleEvent(ev);
+ } else
+ if (inProject && name == "after_open")
+ {
+ ev.arguments << i18n("Document opened");
+ ev.arguments << relativePath;
+ handleEvent(ev);
+ } else
+ if (inProject && name == "after_close")
+ {
+ ev.arguments << i18n("Document closed");
+ ev.arguments << relativePath;
+ handleEvent(ev);
+ } else
+ if (inProject && name == "before_close")
+ {
+ ev.arguments << i18n("About to close a document");
+ ev.arguments << relativePath;
+ handleEvent(ev);
+ } else
+ if (name == "after_project_open")
+ {
+ ev.arguments << i18n("Project opened");
+ ev.arguments << url.path();
+ handleEvent(ev);
+ } else
+ if (name == "after_project_close")
+ {
+ ev.arguments << i18n("Project closed");
+ ev.arguments << url.path();
+ handleEvent(ev);
+ } else
+ if (name == "before_project_close")
+ {
+ ev.arguments << i18n("About to close the project");
+ ev.arguments << url.path();
+ handleEvent(ev);
+ } else
+ if (name == "after_project_add")
+ {
+ ev.arguments << i18n("Document added to project");
+ ev.arguments << url.path();
+ handleEvent(ev);
+ } else
+ if (name == "after_project_remove")
+ {
+ ev.arguments << i18n("Document removed from project");
+ ev.arguments << url.path();
+ handleEvent(ev);
+ }
+ }
+ } else
+ if (name == "after_commit")
+ {
+ ev.arguments << i18n("Document committed");
+ ev.arguments << argument1;
+ handleEvent(ev);
+ } else
+ if (name == "after_update")
+ {
+ ev.arguments << i18n("Document updated");
+ ev.arguments << argument1;
+ handleEvent(ev);
+ } else
+ if (name == "quanta_start")
+ {
+ ev.arguments << i18n("Quanta has been started");
+ ev.arguments << argument1;
+ handleEvent(ev);
+ } else
+ if (name == "quanta_exit")
+ {
+ ev.arguments << i18n("Quanta is shutting down");
+ ev.arguments << argument1;
+ handleEvent(ev);
+ }
+ }
+ }
+ if (!m_eventNames.contains(name))
+ KMessageBox::sorry(0L, i18n("<qt>Unsupported event <b>%1</b>.</qt>").arg(name), i18n("Event Handling Error"));
+}
+
+bool QPEvents::handleEvent(const EventAction& ev)
+{
+ if (ev.type == EventAction::Internal)
+ {
+ if (ev.action == "email")
+ {
+ QString receiver = ev.arguments[0];
+ TeamMember member;
+ if (receiver == "teamleader")
+ member = Project::ref()->teamLeader();
+ else if (receiver.startsWith("subprojectleader-"))
+ {
+ QString s = receiver.remove("subprojectleader-");
+ member = Project::ref()->subprojectLeader(s);
+ SubProject subProject;
+ QValueList<SubProject> *subprojects = Project::ref()->subprojects();
+ for (uint i = 0 ; i < subprojects->count(); i++)
+ {
+ if ((*subprojects)[i].name == s)
+ {
+ subProject = (*subprojects)[i];
+ break;
+ }
+ }
+ if (!subProject.location.isEmpty() && !ev.arguments[2].startsWith(subProject.location))
+ {
+ kdDebug(24000) << ev.arguments[2] << " is not part of the " << subProject.name << "subproject \"" << subProject.location << "\". " << endl;
+ return true;
+ }
+ }
+ else if (receiver.startsWith("taskleader-"))
+ member = Project::ref()->taskLeader(receiver.remove("taskleader-"));
+
+ QString body;
+ for (uint i = 2; i < ev.arguments.count(); i++)
+ body += ev.arguments[i] + "\n";
+ kapp->invokeMailer(member.name + "<" + member.email + ">", "", "", ev.arguments[1], body, "", QStringList(), "");
+
+ return true;
+ }
+ if (ev.action == "log")
+ {
+ QString logFile = ev.arguments[0];
+ KURL url = KURL::fromPathOrURL(logFile);
+ if (url.isValid() && !url.isLocalFile())
+ {
+ KMessageBox::sorry(0L, i18n("Logging to remote files is not supported."));
+ return false;
+ }
+ if (!logFile.startsWith("/"))
+ {
+ url = Project::ref()->projectBaseURL();
+ url.addPath(logFile);
+ if (!url.isLocalFile())
+ {
+ KMessageBox::sorry(0L, i18n("Logging to files inside a remote project is not supported."));
+ return false;
+ }
+ }
+ QFile file(url.path());
+ bool result;
+ if (ev.arguments[2] == "create_new")
+ result = file.open(IO_WriteOnly);
+ else
+ result = file.open(IO_WriteOnly | IO_Append);
+ if (result)
+ {
+ QTextStream stream(&file);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ //Note: the log text should not be translated.
+ QString s = QDateTime::currentDateTime().toString(Qt::ISODate) + ": ";
+ s.append( "Event : " + m_eventName + " : ");
+ s.append( "Action: " + ev.action + " : ");
+ if (ev.arguments[1] == "full")
+ {
+ s.append( "Arguments: ");
+ for (uint i = 1; i < ev.arguments.count(); i++)
+ s.append(ev.arguments[i] + " | ");
+ }
+ s[s.length() - 1] = '\n';
+ stream << s;
+ file.close();
+ }
+ if (!result)
+ {
+ KMessageBox::sorry(0L, i18n("<qt>Logging failed. Check that you have write access to <i>%1</i>.").arg(url.path()));
+ return false;
+ }
+ } else
+ KMessageBox::sorry(0L, i18n("<qt>Unsupported internal event action : <b>%1</b>.</qt>").arg(ev.action));
+ } else
+ if (ev.type == EventAction::External)
+ {
+ //KMessageBox::sorry(0L, i18n("External event actions are not yet supported."));
+ if (ev.action == "script" || ev.action =="action")
+ {
+ QString name = ev.arguments[0];
+ KAction *action = quantaApp->actionCollection()->action(name);
+ TagAction *tagAction = dynamic_cast<TagAction*>(action);
+ if (tagAction)
+ {
+ bool blocking = (ev.arguments[1] == "yes");
+ EventAction event = ev;
+ event.arguments.remove(event.arguments.at(1));
+ tagAction->addArguments(event.arguments);
+ tagAction->execute(blocking);
+ }
+ else
+ if (action)
+ {
+ action->activate();
+ } else
+ KMessageBox::sorry(0L, i18n("<qt>The <b>%1</b> script action was not found on your system.</qt>").arg(name), i18n("Action Execution Error"));
+ } else
+ KMessageBox::sorry(0L, i18n("Unsupported external event action."));
+ } else
+ KMessageBox::sorry(0L, i18n("Unknown event type."));
+ return false;
+}
+
+QString QPEvents::fullEventName(const QString &name)
+{
+ if (m_eventNames.contains(name))
+ return m_eventNames[name];
+ else
+ return name;
+}
+
+QString QPEvents::fullActionName(const QString& name)
+{
+ if (m_actionNames.contains(name))
+ return m_actionNames[name];
+ else
+ return name;
+}
+
+QString QPEvents::eventName(const QString &fullName)
+{
+ for (QMap<QString, QString>::ConstIterator it = m_eventNames.constBegin(); it != m_eventNames.constEnd(); ++it)
+ {
+ if (fullName == it.data())
+ return it.key();
+ }
+ return fullName;
+}
+
+QString QPEvents::actionName(const QString &fullName)
+{
+ for (QMap<QString, QString>::ConstIterator it = m_actionNames.constBegin(); it != m_actionNames.constEnd(); ++it)
+ {
+ if (fullName == it.data())
+ return it.key();
+ }
+ return fullName;
+}
+
+QStringList QPEvents::eventNames()
+{
+ QStringList names;
+ for (QMap<QString, QString>::ConstIterator it = m_eventNames.constBegin(); it != m_eventNames.constEnd(); ++it)
+ {
+ names << it.data();
+ }
+ return names;
+}
+
+QStringList QPEvents::actionNames()
+{
+ QStringList names;
+ for (QMap<QString, QString>::ConstIterator it = m_actionNames.constBegin(); it != m_actionNames.constEnd(); ++it)
+ {
+ names << it.data();
+ }
+ return names;
+}
+
+#include "qpevents.moc"
diff --git a/quanta/utility/qpevents.h b/quanta/utility/qpevents.h
new file mode 100644
index 00000000..83f6d37b
--- /dev/null
+++ b/quanta/utility/qpevents.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ qpevents.h - description
+ -------------------
+ begin : Sun Jul 11 2004
+ copyright : (C) 2004 Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef QPEVENTS_H
+#define QPEVENTS_H
+
+#include <qobject.h>
+
+/**
+@author Andras Mantia
+*/
+
+/** Describes an event action. */
+struct EventAction {
+ /** Possible event types */
+ enum Types {
+ Internal = 0,
+ External = 1
+ };
+ /** The type of the event. See @ref Types */
+ uint type;
+ /** the name of the action to be executed. In case of external events
+ this is the name of the script, in case of internal events it can be one of the
+ following: "email"
+ */
+ QString action;
+ /** The arguments for the event action. It is different for each action.
+ */
+ QStringList arguments;
+};
+
+/** The configured events. The key is the event name, the data is the event description.
+For example: events["before_save"] points to the event data that needs to be used
+before a file is saved. Possible key names are: before_save, after_save, after_open,
+after_project_open, after_project_save, before_upload, after_upload, after_project_add,
+after_project_remove, after_commit
+*/
+typedef QMap<QString, QValueList<EventAction> > EventActions;
+
+class QPEvents : public QObject
+{
+Q_OBJECT
+public:
+ static QPEvents* const ref(QObject *parent = 0L)
+ {
+ static QPEvents *m_ref;
+ if (!m_ref) m_ref = new QPEvents(parent);
+ return m_ref;
+ }
+ ~QPEvents();
+ QString fullEventName(const QString &name);
+ QString fullActionName(const QString &name);
+ QString eventName(const QString &fullName);
+ QString actionName(const QString &fullName);
+ QStringList eventNames();
+ QStringList actionNames();
+
+public slots:
+ /** Called when an event has happened */
+ void slotEventHappened(const QString& name, const QString& argument1, const QString& argument2);
+
+private:
+ QPEvents(QObject *parent = 0, const char *name = 0);
+ /** Calls the action associated with an event. Returns true if the call succeeded, false
+ otherwise. The call might fail if:
+ - the action type is unknown
+ - the script cannot be found
+ - the user canceled the execution
+ */
+ bool handleEvent(const EventAction& ev);
+
+ QMap<QString, QString> m_eventNames;
+ QMap<QString, QString> m_actionNames;
+ QString m_eventName;
+};
+
+#endif
diff --git a/quanta/utility/quantabookmarks.cpp b/quanta/utility/quantabookmarks.cpp
new file mode 100644
index 00000000..ebca5843
--- /dev/null
+++ b/quanta/utility/quantabookmarks.cpp
@@ -0,0 +1,399 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002, 2003, 2004 Anders Lund <anders.lund@lund.tdcadsl.dk>
+ Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org>
+ Copyright (C) 2005 Andras Mantia <amantia@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "quantabookmarks.h"
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kaction.h>
+#include <kdebug.h>
+#include <kpopupmenu.h>
+#include <kstringhandler.h>
+#include <ktexteditor/markinterface.h>
+#include <ktexteditor/editinterface.h>
+#include <ktexteditor/viewcursorinterface.h>
+
+#include <qregexp.h>
+#include <qmemarray.h>
+#include <qevent.h>
+
+#include "viewmanager.h"
+#include "document.h"
+
+/**
+ Utility: selection sort
+ sort a QMemArray<uint> in ascending order.
+ max it the largest (zerobased) index to sort.
+ To sort the entire array: ssort( *array, array.size() -1 );
+ This is only efficient if ran only once.
+*/
+static void ssort( QMemArray<uint> &a, int max )
+{
+ uint tmp, j, maxpos;
+ for ( uint h = max; h >= 1; h-- )
+ {
+ maxpos = 0;
+ for ( j = 0; j <= h; j++ )
+ maxpos = a[j] > a[maxpos] ? j : maxpos;
+ tmp = a[maxpos];
+ a[maxpos] = a[h];
+ a[h] = tmp;
+ }
+}
+
+// TODO add a insort() or bubble_sort - more efficient for aboutToShow() ?
+
+QuantaBookmarks::QuantaBookmarks(ViewManager *parent,Sorting sort, bool onlyFromActualDocument )
+ : QObject( parent, "bookmarks" )
+ , m_sorting(sort)
+ , m_onlyFromActualDocument(onlyFromActualDocument)
+{
+ m_viewManager = parent;
+ _tries=0;
+ m_bookmarksMenu = 0L;
+ m_doc = 0L;
+}
+
+QuantaBookmarks::~QuantaBookmarks()
+{
+}
+
+void QuantaBookmarks::createActions( KActionCollection* ac )
+{
+ m_bookmarksMenu = (new KActionMenu(i18n("&Bookmarks"), ac, "bookmarks"))->popupMenu();
+ init(ac);
+}
+
+void QuantaBookmarks::init(KActionCollection* ac)
+{
+ m_bookmarkToggle = new KToggleAction(
+ i18n("Set &Bookmark"), "bookmark", CTRL+Key_B,
+ this, SLOT(toggleBookmark()),
+ ac, "bookmarks_toggle" );
+ m_bookmarkToggle->setWhatsThis(i18n("If a line has no bookmark then add one, otherwise remove it."));
+ m_bookmarkToggle->setCheckedState( i18n("Clear &Bookmark") );
+
+ m_bookmarkClear = new KAction(
+ i18n("Clear &All Bookmarks"), 0,
+ this, SLOT(clearBookmarks()),
+ ac, "bookmarks_clear");
+ m_bookmarkClear->setWhatsThis(i18n("Remove all bookmarks of the current document."));
+
+ m_goNext = new KAction(
+ i18n("Next Bookmark"), "next", ALT + Key_PageDown,
+ this, SLOT(goNext()),
+ ac, "bookmarks_next");
+ m_goNext->setWhatsThis(i18n("Go to the next bookmark."));
+
+ m_goPrevious = new KAction(
+ i18n("Previous Bookmark"), "previous", ALT + Key_PageUp,
+ this, SLOT(goPrevious()),
+ ac, "bookmarks_previous");
+ m_goPrevious->setWhatsThis(i18n("Go to the previous bookmark."));
+
+ //connect the aboutToShow() and aboutToHide() signals with
+ //the bookmarkMenuAboutToShow() and bookmarkMenuAboutToHide() slots
+ connect( m_bookmarksMenu, SIGNAL(aboutToShow()), this, SLOT(bookmarkMenuAboutToShow()));
+ connect( m_bookmarksMenu, SIGNAL(aboutToHide()), this, SLOT(bookmarkMenuAboutToHide()) );
+
+ marksChanged ();
+}
+
+void QuantaBookmarks::setBookmarksMenu(QPopupMenu* bookmarksMenu)
+
+{
+ m_bookmarksMenu = bookmarksMenu;
+ init();
+}
+
+void QuantaBookmarks::toggleBookmark ()
+{
+ Document *doc = m_doc;
+ if (!doc)
+ doc = m_viewManager->activeDocument();
+ if (doc && doc->markIf)
+ {
+ uint mark = doc->markIf->mark(doc->viewCursorIf->cursorLine());
+ if( mark & KTextEditor::MarkInterface::markType01 )
+ doc->markIf->removeMark(doc->viewCursorIf->cursorLine(),
+ KTextEditor::MarkInterface::markType01 );
+ else
+ doc->markIf->addMark(doc->viewCursorIf->cursorLine(),
+ KTextEditor::MarkInterface::markType01 );
+ }
+ marksChanged();
+}
+
+void QuantaBookmarks::clearBookmarks ()
+{
+ Document *doc = m_viewManager->activeDocument();
+ if (doc && doc->markIf)
+ {
+ QPtrList<KTextEditor::Mark> m = doc->markIf->marks();
+ for (uint i=0; i < m.count(); i++)
+ doc->markIf->removeMark( m.at(i)->line, KTextEditor::MarkInterface::markType01 );
+
+ // just to be sure ;)
+ marksChanged ();
+ }
+}
+
+int QuantaBookmarks::insertBookmarks(QPopupMenu& menu, Document *doc, bool insertNavigationItems )
+{
+ int insertedItems = 0;
+ if (doc->markIf)
+ {
+ uint line = doc->viewCursorIf->cursorLine();
+ const QRegExp re("&(?!&)");
+ int idx( -1 );
+ int old_menu_count = menu.count();
+ KTextEditor::Mark *next = 0;
+ KTextEditor::Mark *prev = 0;
+
+ QPtrList<KTextEditor::Mark> m = doc->markIf->marks();
+ QMemArray<uint> sortArray( m.count() );
+ QPtrListIterator<KTextEditor::Mark> it( m );
+
+ if ( it.count() > 0 && insertNavigationItems)
+ menu.insertSeparator();
+
+ for( int i = 0; *it; ++it)
+ {
+ if( (*it)->type & KTextEditor::MarkInterface::markType01 )
+ {
+ QString bText = KStringHandler::rEmSqueeze
+ ( doc->editIf->textLine( (*it)->line ),
+ menu.fontMetrics(), 32 );
+ bText.replace(re, "&&"); // kill undesired accellerators!
+ bText.replace('\t', ' '); // kill tabs, as they are interpreted as shortcuts
+
+ if ( m_sorting == Position )
+ {
+ sortArray[i] = (*it)->line;
+ ssort( sortArray, i );
+ idx = sortArray.find( (*it)->line );
+ if (insertNavigationItems)
+ idx += 3;
+ i++;
+ }
+
+ menu.insertItem(
+ QString("%1 - \"%2\"").arg( (*it)->line+1 ).arg( bText ),
+ 0, (*it)->line, idx );
+ insertedItems++;
+
+ if ( (*it)->line < line )
+ {
+ if ( ! prev || prev->line < (*it)->line )
+ prev = (*it);
+ }
+
+ else if ( (*it)->line > line )
+ {
+ if ( ! next || next->line > (*it)->line )
+ next = (*it);
+ }
+ }
+ }
+
+ if (insertNavigationItems)
+ {
+ idx = ++old_menu_count;
+ if ( next )
+ {
+ m_goNext->setText( i18n("&Next: %1 - \"%2\"").arg( next->line + 1 )
+ .arg( KStringHandler::rsqueeze( doc->editIf->textLine( next->line ), 24 ) ) );
+ m_goNext->plug( &menu, idx );
+ idx++;
+ }
+ if ( prev )
+ {
+ m_goPrevious->setText( i18n("&Previous: %1 - \"%2\"").arg(prev->line + 1 )
+ .arg( KStringHandler::rsqueeze( doc->editIf->textLine( prev->line ), 24 ) ) );
+ m_goPrevious->plug( &menu, idx );
+ idx++;
+ }
+ if ( next || prev )
+ menu.insertSeparator( idx );
+ }
+ connect(&menu, SIGNAL(activated(int)), this, SLOT(gotoLineNumber(int)));
+ }
+ return insertedItems;
+}
+
+void QuantaBookmarks::bookmarkMenuAboutToShow()
+{
+ KConfig *config = kapp->config();
+ if (config->hasGroup("Kate View Defaults"))
+ {
+ config->setGroup("Kate View Defaults");
+ m_sorting = config->readNumEntry("Bookmark Menu Sorting", 0) == 0 ? Position : Creation;
+ }
+ for (uint i = 0; i < m_othersMenuList.count(); i++)
+ {
+ delete m_othersMenuList[i];
+ }
+ m_othersMenuList.clear();
+ m_others.clear();
+ m_bookmarksMenu->clear();
+ marksChanged();
+
+ Document *doc = m_doc;
+ if (!doc)
+ doc = m_viewManager->activeDocument();
+ QValueList<Document*> openedDocuments = m_viewManager->openedDocuments();
+ if (doc && doc->markIf)
+ {
+ QPtrList<KTextEditor::Mark> m = doc->markIf->marks();
+
+ if (!m_onlyFromActualDocument)
+ {
+ m_bookmarkToggle->setChecked( doc->markIf->mark( doc->viewCursorIf->cursorLine() )
+ & KTextEditor::MarkInterface::markType01 );
+ m_bookmarkToggle->plug( m_bookmarksMenu );
+ m_bookmarkClear->plug( m_bookmarksMenu );
+ }
+
+ insertBookmarks(*m_bookmarksMenu, doc, !m_onlyFromActualDocument);
+ if (openedDocuments.count() > 1 && !m_onlyFromActualDocument)
+ m_bookmarksMenu->insertSeparator();
+ }
+ if (!m_onlyFromActualDocument)
+ {
+ int i = 0;
+ for (QValueList<Document*>::Iterator it = openedDocuments.begin(); it != openedDocuments.end(); ++it)
+ {
+ if (*it != doc)
+ {
+ QPopupMenu *menu = new QPopupMenu(m_bookmarksMenu);
+ m_bookmarksMenu->insertItem((*it)->url().fileName(), menu);
+ if (insertBookmarks(*menu, *it, false) > 0)
+ {
+ m_othersMenuList.append(menu);
+ m_others.append(*it);
+ i++;
+ } else
+ delete menu;
+ }
+ }
+ }
+}
+
+/*
+ Make sure next/prev actions are plugged, and have a clean text
+*/
+void QuantaBookmarks::bookmarkMenuAboutToHide()
+{
+ m_bookmarkToggle->plug( m_bookmarksMenu );
+ m_bookmarkClear->plug( m_bookmarksMenu );
+ m_goNext->setText( i18n("Next Bookmark") );
+ m_goNext->plug( m_bookmarksMenu );
+ m_goPrevious->setText( i18n("Previous Bookmark") );
+ m_goPrevious->plug( m_bookmarksMenu );
+}
+
+void QuantaBookmarks::goNext()
+{
+ Document *doc = m_doc;
+ if (!doc)
+ doc = m_viewManager->activeDocument();
+ if (doc && doc->markIf)
+ {
+ QPtrList<KTextEditor::Mark> m = doc->markIf->marks();
+ if (m.isEmpty())
+ return;
+
+ uint line = doc->viewCursorIf->cursorLine();
+ int found = -1;
+
+ for (uint z=0; z < m.count(); z++)
+ if ( (m.at(z)->line > line) && ((found == -1) || (uint(found) > m.at(z)->line)) )
+ found = m.at(z)->line;
+
+ if (found != -1)
+ doc->viewCursorIf->setCursorPositionReal(found, 0);
+ }
+}
+
+void QuantaBookmarks::goPrevious()
+{
+ Document *doc = m_doc;
+ if (!doc)
+ doc = m_viewManager->activeDocument();
+ if (doc && doc->markIf)
+ {
+ QPtrList<KTextEditor::Mark> m = doc->markIf->marks();
+ if (m.isEmpty())
+ return;
+
+ uint line = doc->viewCursorIf->cursorLine();
+ int found = -1;
+
+ for (uint z=0; z < m.count(); z++)
+ if ((m.at(z)->line < line) && ((found == -1) || (uint(found) < m.at(z)->line)))
+ found = m.at(z)->line;
+
+ if (found != -1)
+ doc->viewCursorIf->setCursorPositionReal(found, 0);
+ }
+}
+
+void QuantaBookmarks::gotoLineNumber(int line)
+{
+ Document *doc = m_doc;
+ if (!doc)
+ doc = m_viewManager->activeDocument();
+ const QObject *s = sender();
+ for (uint i = 0; i < m_othersMenuList.count(); i++)
+ {
+ if (s == m_othersMenuList[i])
+ {
+ doc = m_others[i];
+ break;
+ }
+ }
+ if (doc)
+ {
+ if (doc->isUntitled())
+ {
+ emit gotoFileAndLine("file:" + doc->url().path(), line, 0);
+ } else
+ {
+ emit gotoFileAndLine(doc->url().url(), line, 0);
+ }
+ }
+}
+
+
+void QuantaBookmarks::marksChanged ()
+{
+ Document *doc = m_doc;
+ if (!doc)
+ doc = m_viewManager->activeDocument();
+ if (doc && doc->markIf)
+ {
+ m_bookmarkClear->setEnabled( !doc->markIf->marks().isEmpty() );
+ }
+}
+
+#include "quantabookmarks.moc"
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/quanta/utility/quantabookmarks.h b/quanta/utility/quantabookmarks.h
new file mode 100644
index 00000000..10c0aad4
--- /dev/null
+++ b/quanta/utility/quantabookmarks.h
@@ -0,0 +1,99 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002, 2003 Anders Lund <anders.lund@lund.tdcadsl.dk>
+ Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org>
+ Copyright (C) 2005 Andras Mantia <amantia@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/* Extended bookmark manager. Code taken from the Kate part and adapted to
+Quanta, so it works over multiple document */
+
+#ifndef QUANTABOOKMARKS_H
+#define QUANTABOOKMARKS_H
+
+#include <qobject.h>
+#include <qptrlist.h>
+
+namespace KTextEditor { class Mark; }
+
+class ViewManager;
+class Document;
+
+class KAction;
+class KToggleAction;
+class KActionCollection;
+class QPopupMenu;
+class QMenuData;
+
+
+
+class QuantaBookmarks : public QObject
+{
+ Q_OBJECT
+
+ public:
+ enum Sorting { Position, Creation };
+ QuantaBookmarks(ViewManager *parent, Sorting sort=Position, bool onlyFromActualDocument = false );
+ virtual ~QuantaBookmarks();
+
+ void createActions( KActionCollection* );
+ void setBookmarksMenu(QPopupMenu* bookmarksMenu);
+
+ QuantaBookmarks::Sorting sorting() { return m_sorting; };
+ void setSorting( Sorting s ) { m_sorting = s; };
+ void setDocument(Document *doc) {m_doc = doc;}
+
+ protected:
+ int insertBookmarks(QPopupMenu& menu, Document *doc, bool insertNavigationItems = true);
+ void init(KActionCollection* ac = 0L);
+
+ private slots:
+ void toggleBookmark();
+ void clearBookmarks();
+
+ void bookmarkMenuAboutToShow();
+ void bookmarkMenuAboutToHide();
+
+ void goNext();
+ void goPrevious();
+ void gotoLineNumber(int line);
+
+ void marksChanged ();
+
+ signals:
+ void gotoFileAndLine(const QString&, int, int);
+
+ private:
+ KToggleAction* m_bookmarkToggle;
+ KAction* m_bookmarkClear;
+ KAction* m_goNext;
+ KAction* m_goPrevious;
+
+ Sorting m_sorting;
+ QPopupMenu* m_bookmarksMenu;
+ QValueList<QPopupMenu*> m_othersMenuList;
+ QValueList<Document*> m_others;
+ ViewManager* m_viewManager;
+ Document *m_doc;
+ bool m_onlyFromActualDocument;
+
+ uint _tries;
+};
+
+#endif
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
+// vim: noet ts=2
diff --git a/quanta/utility/quantacommon.cpp b/quanta/utility/quantacommon.cpp
new file mode 100644
index 00000000..7cc7fb1b
--- /dev/null
+++ b/quanta/utility/quantacommon.cpp
@@ -0,0 +1,753 @@
+/***************************************************************************
+ quantacommon.cpp - description
+ -------------------
+ begin : Sat Jul 27 2002
+ copyright : (C) 2002, 2003 by Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+//system includes
+#include <sys/types.h>
+#include <unistd.h>
+
+//qt includes
+#include <qstringlist.h>
+#include <qdict.h>
+#include <qdir.h>
+#include <qdom.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qwidget.h>
+
+//kde includes
+#include <kapplication.h>
+#include <dcopref.h>
+#include <kurl.h>
+#include <kdirwatch.h>
+#include <kmimetype.h>
+#include <kstandarddirs.h>
+#include <kmessagebox.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kprotocolinfo.h>
+#include <kprogress.h>
+#include <ktempdir.h>
+#include <ktempfile.h>
+
+//remove the below ones when KQPasteAction is removed
+#include <dcopclient.h>
+#include <kdebug.h>
+#include <kpopupmenu.h>
+#include <ktoolbar.h>
+#include <ktoolbarbutton.h>
+#include <kstringhandler.h>
+#include <qwhatsthis.h>
+#include <qtimer.h>
+#include <qclipboard.h>
+#include <qdatastream.h>
+
+#include "qextfileinfo.h"
+#include "quantacommon.h"
+#include "tag.h"
+#include "dtds.h"
+//#include "resource.h"
+
+
+QConfig qConfig; //holds the main configuration settings
+QString tmpDir;
+
+QRegExp scriptBeginRx;
+QRegExp scriptEndRx;
+
+Node *baseNode;
+Parser *parser;
+KDirWatch *fileWatcher;
+KProgress *progressBar;
+
+QString toolbarExtension = ".toolbar.tgz";
+QRegExp newLineRx("\\n");
+QStringList charList; //hold the list of the &char; chars. See the data/chars file.
+QMap<int, QString> replacementMap;
+QPtrList<KTempFile> tempFileList;
+QPtrList<KTempDir> tempDirList;
+bool typingInProgress;
+
+QuantaCommon::QuantaCommon(){
+}
+
+QuantaCommon::~QuantaCommon(){
+}
+
+/** convert tag to upper or lower case */
+QString QuantaCommon::tagCase( const QString& tag)
+{
+ QString sTag = tag;
+
+ switch (qConfig.tagCase)
+ {
+ case 1: sTag = tag.lower();
+ break;
+ case 2: sTag = tag.upper();
+ }
+ return sTag;
+}
+
+/** convert attr of tag to upper or lower case */
+QString QuantaCommon::attrCase( const QString& attr)
+{
+ QString sAttr = attr;
+
+ switch (qConfig.attrCase)
+ {
+ case 1: sAttr = attr.lower();
+ break;
+ case 2: sAttr = attr.upper();
+ }
+ return sAttr;
+}
+
+/** returns the attribute value in quoted form, by taking care of the
+quotation setting*/
+QString QuantaCommon::quoteAttributeValue(const QString& value)
+{
+ QString quote = qConfig.attrValueQuotation;
+ return quote + value + quote;
+}
+
+/** Set's up the url correctly from urlString. */
+void QuantaCommon::setUrl(KURL &url, const QString& urlString)
+{
+ KURL oldUrl = url;
+ url = urlString;
+ if (!KProtocolInfo::isKnownProtocol(url))
+ {
+ url = oldUrl;
+ url.setPath(urlString);
+ if (url.protocol().isEmpty())
+ url.setProtocol("file");
+ }
+}
+
+/** No descriptions */
+bool QuantaCommon::isSingleTag(const QString& dtdName, const QString& tag)
+{
+ bool single = false;
+
+ //!doctype is a common tag to all DTDs not listed in the tagsList
+ if(tag.lower() == "!doctype" || tag.lower() == "?xml")
+ return true;
+
+ const DTDStruct* dtd = DTDs::ref()->find(dtdName);
+ if (dtd && !tag.isEmpty())
+ {
+ QString searchForTag = (dtd->caseSensitive) ? tag : tag.upper();
+ QTag* qtag = dtd->tagsList->find(searchForTag);
+ if (qtag)
+ single = qtag->isSingle();
+ }
+
+ return single;
+}
+
+/** No descriptions */
+bool QuantaCommon::isOptionalTag(const QString& dtdName, const QString& tag)
+{
+ bool optional = false;
+
+ const DTDStruct* dtd = DTDs::ref()->find(dtdName);
+ if (dtd && !tag.isEmpty())
+ {
+ QString searchForTag = (dtd->caseSensitive) ? tag : tag.upper();
+ QTag* qtag = dtd->tagsList->find(searchForTag);
+ if (qtag)
+ optional = qtag->isOptional();
+ }
+
+ return optional;
+}
+/** No descriptions */
+bool QuantaCommon::isKnownTag(const QString& dtdName, const QString& tag)
+{
+ bool known = false;
+
+ const DTDStruct* dtd = DTDs::ref()->find(dtdName);
+ if (dtd && !tag.isEmpty())
+ {
+ QString searchForTag = (dtd->caseSensitive) ? tag : tag.upper();
+ if (dtd->tagsList->find(searchForTag))
+ known = true;
+ }
+
+ return known;
+}
+
+AttributeList* QuantaCommon::tagAttributes(const QString& dtdName, const QString& tag)
+{
+ AttributeList* attrs = 0L;
+
+ const DTDStruct* dtd = DTDs::ref()->find(dtdName);
+ if (dtd && !tag.isEmpty())
+ {
+ QString searchForTag = (dtd->caseSensitive) ? tag : tag.upper();
+ QTag* qtag = dtd->tagsList->find(searchForTag);
+ if (qtag)
+ attrs = qtag->attributes();
+ }
+
+ return attrs;
+}
+
+/** Returns the QTag object for the tag "tag" from the DTD named "dtdname". */
+QTag* QuantaCommon::tagFromDTD(const QString& dtdName, const QString& tag)
+{
+ const DTDStruct* dtd = DTDs::ref()->find(dtdName);
+ return tagFromDTD(dtd, tag);
+}
+
+/** Returns the QTag object for the tag "tag" from the DTD. */
+QTag* QuantaCommon::tagFromDTD(const DTDStruct *dtd, const QString& tag)
+{
+ QTag *qtag = 0;
+ if (dtd && !tag.isEmpty())
+ {
+ QString searchForTag = (dtd->caseSensitive) ? tag : tag.upper();
+ qtag = dtd->tagsList->find(searchForTag);
+ }
+
+ return qtag;
+}
+
+/** Returns the QTag object for the node "node" from node's DTD. */
+QTag* QuantaCommon::tagFromDTD(Node *node)
+{
+ if(!node || !node->tag)
+ return 0L;
+
+ return tagFromDTD(node->tag->dtd(), node->tag->name);
+}
+
+/** Returns an XML style string containing the GUI for attributes. */
+QString QuantaCommon::xmlFromAttributes(AttributeList* attributes)
+{
+ QString xmlStr;
+ QTextStream stream( &xmlStr, IO_WriteOnly );
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ if (attributes)
+ {
+ int row = 0;
+ for ( uint i = 0; i< attributes->count();i++)
+ {
+ Attribute *attribute = attributes->at(i);
+ QString name = attribute->name.left(1).upper()+attribute->name.right(attribute->name.length()-1);
+ stream << " <attr name=\"" + attribute->name +"\" type=\""+attribute->type+"\"";
+ if (!attribute->defaultValue.isEmpty())
+ stream << " defaultValue=\"" + attribute->defaultValue + "\"";
+ if (!attribute->status.isEmpty())
+ stream << " status=\"" + attribute->status + "\"";
+ stream << ">" << endl;
+ stream << " <text>" << name << "</text>" << endl;
+ if (attribute->type != "check")
+ {
+ stream << " <textlocation col=\"0\" row=\"" << row << "\" />" << endl;
+ }
+ stream << " <location col=\"1\" row=\"" << row << "\" />" << endl;
+
+ if (attribute->type == "list")
+ {
+ stream << " <items>" << endl;
+ for (uint j = 0; j < attribute->values.count(); j++)
+ {
+ stream << " <item>" << attribute->values[j] << "</item>" << endl;
+ }
+ stream << " </items>" << endl;
+ }
+ stream << " </attr>" << endl << endl ;
+ row++;
+ } //for
+ } //if
+
+ return xmlStr;
+}
+
+ /** Returns 0 if the (line,col) is inside the area specified by the other
+arguments, -1 if it is before the area and 1 if it is after. */
+int QuantaCommon::isBetween(int line, int col, int bLine, int bCol, int eLine,
+int eCol){
+ int pos = 0;
+ if (line < bLine || (line == bLine && (col < bCol) )) pos = -1; //it is before
+ if (line > eLine || (line == eLine && (col > eCol) )) pos = 1; //it is after
+
+ return pos;
+}
+
+/** Returns a pointer to a KStandardDirs object usable for plugin searchup. type
+is the plugin binary type (exe or lib). The returned pointer must be deleted by
+the caller!! */
+KStandardDirs* QuantaCommon::pluginDirs(const char *type)
+{
+ KStandardDirs *dirs = new KStandardDirs();
+ dirs->addKDEDefaults();
+ for (uint i = 0; i < qConfig.pluginSearchPaths.count(); i++)
+ {
+ dirs->addResourceDir(type, qConfig.pluginSearchPaths[i]);
+ }
+ return dirs;
+}
+/** Return true, if the url belong to the mimetype group. */
+bool QuantaCommon::checkMimeGroup(const KURL& url, const QString& group)
+{
+ KMimeType::List list = KMimeType::allMimeTypes();
+ KMimeType::List::iterator it;
+ bool status = false;
+ KMimeType::Ptr mime = KMimeType::findByURL(url);
+ QString mimetype = mime->name();
+ mimetype = mimetype.section('/',-1);
+ for ( it = list.begin(); it != list.end(); ++it )
+ {
+ if ( ((*it)->name().contains(group)) && ((*it)->name().find(mimetype) != -1)
+) {
+ status = true;
+ break;
+ }
+ }
+
+ if (!status && group == "text")
+ {
+ if (url.isLocalFile())
+ {
+ KMimeType::Format f = KMimeType::findFormatByFileContent(url.path());
+ if (f.text && f.compression == KMimeType::Format::NoCompression)
+ status = true;
+ } else
+ {
+ QVariant v = mime->property("X-KDE-text");
+ if (v.isValid())
+ status = v.toBool();
+ }
+ }
+ if (!status && group == "text" && mimetype == "x-zerosize")
+ status = true;
+
+ return status;
+}
+
+/** Return true, if the url has the mimetype type. */
+bool QuantaCommon::checkMimeType(const KURL& url, const QString& type)
+{
+ bool status = false;
+ QString mimetype = KMimeType::findByURL(url)->name();
+ mimetype = mimetype.section('/',-1);
+ if (mimetype == type) status = true;
+
+ return status;
+}
+
+/** Return true, if the url has exactly the mimetype type. */
+bool QuantaCommon::checkExactMimeType(const KURL& url, const QString& type)
+{
+ bool status = false;
+ QString mimetype = KMimeType::findByURL(url)->name();
+ if (mimetype == type) status = true;
+
+ return status;
+}
+
+/** Returns the url without the filename. */
+KURL QuantaCommon::convertToPath(const KURL& url)
+{
+ KURL result = url;
+ result.setFileName("");
+ result.adjustPath(1);
+ return result;
+}
+
+/** Return a string to be used when an url is saved to the project file.
+ Returns url.url() if it's an absolute url and
+ url.path() if the url is relative */
+QString QuantaCommon::qUrl(const KURL &url)
+{
+ QString result = url.path();
+ if (url.path().startsWith("/")) result = url.url();
+
+ return result;
+}
+/** No descriptions */
+void QuantaCommon::dirCreationError(QWidget *widget, const KURL& url)
+{
+ KMessageBox::error(widget, i18n("<qt>Cannot create folder<br><b>%1</b>.<br>Check that you have write permission in the parent folder or that the connection to<br><b>%2</b><br> is valid.</qt>")
+ .arg(url.prettyURL(0, KURL::StripFileProtocol))
+ .arg(url.protocol()+"://"+url.user()+"@"+url.host()));}
+
+/**
+Adds the backslash before the special chars (like ?, *, . ) so the returned
+string can be used in regular expressions.*/
+QString QuantaCommon::makeRxCompatible(const QString& s)
+{
+ const uint max = 7;
+ const QRegExp rxs[max]={QRegExp("\\?"),
+ QRegExp("\\*"),
+ QRegExp("\\."),
+ QRegExp("\\^"),
+ QRegExp("\\$"),
+ QRegExp("\\{"),
+ QRegExp("\\}")
+ };
+ const QString strs[max]={QString("\\?"),
+ QString("\\*"),
+ QString("\\."),
+ QString("\\^"),
+ QString("\\$"),
+ QString("\\{"),
+ QString("\\}")
+ };
+ QString str = s;
+ for (uint i = 0; i < max - 1; i++)
+ {
+ str.replace(rxs[i], strs[i]);
+ }
+
+ return str;
+}
+
+/** Returns the translated a_str in English. A "back-translation" useful e.g in case of CSS elements selected from a listbox. */
+QString QuantaCommon::i18n2normal(const QString& a_str)
+{
+//TODO: a QMap lookup would be faster, but we need a pre-built QMap<QString,QString>
+ const int keywordNum = 15 *5;
+ const QString keywords[keywordNum] =
+ {"normal", "italic", "oblique", "serif", "sans-serif",
+ "cursive", "fantasy", "monospace", "small-caps", "lighter",
+ "bold", "bolder", "xx-small", "x-small", "small",
+ "medium", "large", "x-large", "xx-large", "smaller",
+ "larger", "repeat", "repeat-x", "repeat-y", "no-repeat",
+ "scroll", "fixed", "top", "center", "bottom",
+ "left", "right", "none", "underline", "overline"
+ "line-through", "blibk", "justify","baseline", "sub",
+ "super", "text-top","text-bottom","capitalize","uppercase",
+ "lowercase","thin", "thick", "[length value]","dotted",
+ "dashed", "solid", "double", "groove", "ridge",
+ "inset", "outset", "block", "inline", "list-item",
+ "none", "pre", "nowrap", "disc", "circle",
+ "square", "decimal", "lower-roman","upper-roman","lower-alpha",
+ "upper-alpha","inside","outside", "auto", "both" };
+ QString str = a_str;
+ if (!a_str.isEmpty())
+ {
+ for (int i = 0; i < keywordNum; i++)
+ {
+ if (!keywords[i].isEmpty() && a_str == i18n(keywords[i].utf8()))
+ {
+ str = keywords[i];
+ break;
+ }
+ }
+ }
+ return str;
+}
+
+static const QChar space(' ');
+
+void QuantaCommon::removeCommentsAndQuotes(QString &str, const DTDStruct *dtd)
+{
+ //Replace all the commented strings and the escaped quotation marks (\", \')
+ // with spaces so they will not mess up our parsing
+ int pos = 0;
+ int l;
+ QString s;
+ while (pos != -1)
+ {
+ pos = dtd->commentsStartRx.search(str, pos);
+ if (pos != -1)
+ {
+ s = dtd->commentsStartRx.cap();
+ if (s == "\\\"" || s == "\\'")
+ {
+ int i = pos;
+ int slahNum = 0;
+ while (i > 0 && str[i] == '\\')
+ {
+ slahNum++;
+ i--;
+ }
+ if (slahNum % 2 == 0)
+ {
+ pos++;
+ } else
+ {
+ str[pos] = space;
+ str[pos+1] = space;
+ pos += 2;
+ }
+ } else
+ {
+ s = dtd->comments[s];
+ l = str.find(s, pos);
+ l = (l == -1) ? str.length() : l;
+ for (int i = pos; i < l ; i++)
+ {
+ str[i] = space;
+ }
+ pos = l + s.length();
+ }
+ }
+ }
+
+ //Now replace the quoted strings with spaces
+ QRegExp strRx("(\"[^\"]*\"|'[^']*')");
+ pos = 0;
+ while (pos != -1)
+ {
+ pos = strRx.search(str, pos);
+ if (pos != -1)
+ {
+ l = strRx.matchedLength();
+ for (int i = pos; i < pos + l ; i++)
+ {
+ str[i] = space;
+ }
+ pos += l;
+ }
+ }
+
+}
+
+bool QuantaCommon::insideCommentsOrQuotes(int position, const QString &string, const DTDStruct *dtd)
+{
+ //Return true if position is inside a commented or quoted string
+ QString str = string;
+ int pos = 0;
+ int l;
+ QString s;
+ while (pos != -1)
+ {
+ pos = dtd->commentsStartRx.search(str, pos);
+ if (pos == position)
+ return true;
+ if (pos != -1)
+ {
+ s = dtd->commentsStartRx.cap();
+ if (s == "\\\"" || s == "\\'")
+ {
+ int i = pos;
+ int slahNum = 0;
+ while (i > 0 && str[i] == '\\')
+ {
+ slahNum++;
+ i--;
+ }
+ if (slahNum % 2 == 0)
+ {
+ pos++;
+ } else
+ {
+ str[pos] = space;
+ str[pos+1] = space;
+ pos += 2;
+ }
+ } else
+ {
+ s = dtd->comments[s];
+ l = str.find(s, pos);
+ l = (l == -1) ? str.length() : l;
+ for (int i = pos; i < l ; i++)
+ {
+ str[i] = space;
+ if (i == position)
+ return true;
+ }
+ pos = l + s.length();
+ }
+ }
+ }
+
+ //Now replace the quoted strings with spaces
+ const QRegExp strRx("(\"[^\"]*\"|'[^']*')");
+ pos = 0;
+ while (pos != -1)
+ {
+ pos = strRx.search(str, pos);
+ if (pos != -1)
+ {
+ l = strRx.matchedLength();
+ for (int i = pos; i < pos + l ; i++)
+ {
+ str[i] = space;
+ if (i == position)
+ return true;
+ }
+ pos += l;
+ }
+ }
+
+ return false;
+}
+
+DCOPReply QuantaCommon::callDCOPMethod(const QString& interface, const QString& method, const QString& arguments)
+{
+ QStringList argumentList = QStringList::split(",", arguments, true);
+ QString app = "quanta";
+ if (!kapp->inherits("KUniqueApplication"))
+ {
+ pid_t pid = ::getpid();
+ app += QString("-%1").arg(pid);
+ }
+ DCOPRef quantaRef(app.utf8(), interface.utf8());
+ DCOPReply reply;
+ int argumentCount = argumentList.count();
+ if (argumentCount == 0)
+ {
+ reply = quantaRef.call(method.utf8());
+ }
+ else if (argumentCount == 1)
+ {
+ reply = quantaRef.call(method.utf8(), argumentList[0]);
+ }
+ else if (argumentCount == 2)
+ reply = quantaRef.call(method.utf8(), argumentList[0], argumentList[1]);
+ else if (argumentCount == 3)
+ reply = quantaRef.call(method.utf8(), argumentList[0], argumentList[1], argumentList[2]);
+ else if (argumentCount == 4)
+ reply = quantaRef.call(method.utf8(), argumentList[0], argumentList[1], argumentList[2], argumentList[3]);
+ else if (argumentCount == 5)
+ reply = quantaRef.call(method.utf8(), argumentList[0], argumentList[1], argumentList[2], argumentList[3], argumentList[4]);
+ else if (argumentCount == 6)
+ reply = quantaRef.call(method.utf8(), argumentList[0], argumentList[1], argumentList[2], argumentList[3], argumentList[4], argumentList[5]);
+ else if (argumentCount == 7)
+ reply = quantaRef.call(method.utf8(), argumentList[0], argumentList[1], argumentList[2], argumentList[3], argumentList[4], argumentList[5], argumentList[6]);
+ else if (argumentCount == 8)
+ reply = quantaRef.call(method.utf8(), argumentList[0], argumentList[1], argumentList[2], argumentList[3], argumentList[4], argumentList[5], argumentList[6], argumentList[7]);
+
+ return reply;
+}
+
+void QuantaCommon::normalizeStructure(QString f,QStringList& l)
+{
+ f.remove("\t");
+ f.remove("\n");
+ f.remove("\r");
+
+ while(f.contains("<"))
+ {
+ QString z(f);
+ z.truncate(z.find(">")+1);
+ z.remove(0,z.find("<"));
+ f.remove(0,f.find(">")+1);
+ l.append(z);
+ }
+}
+
+bool QuantaCommon::closesTag(Tag *tag1, Tag *tag2)
+{
+ if (tag1->nameSpace.isEmpty())
+ {
+ if (!tag2->nameSpace.isEmpty())
+ return false; //namespace missmatch
+ QString tag1Name = tag1->dtd()->caseSensitive ? tag1->name : tag1->name.upper();
+ QString tag2Name = tag2->dtd()->caseSensitive ? tag2->name : tag2->name.upper();
+ if ("/" + tag1Name != tag2Name)
+ return false; //not the closing tag
+ } else
+ {
+ if (tag2->nameSpace.isEmpty())
+ return false; //namespace missmatch
+ QString tag1Name = tag1->dtd()->caseSensitive ? (tag1->nameSpace + tag1->name) : (tag1->nameSpace.upper() + tag1->name.upper());
+ QString tag2Name = tag2->dtd()->caseSensitive ? (tag2->nameSpace + tag2->name) : (tag2->nameSpace.upper() + tag2->name.upper());
+ if ("/" + tag1Name != tag2Name)
+ return false; //namespace missmatch or not the closing tag
+ }
+ return true;
+}
+
+bool QuantaCommon::closesTag(QString namespaceName, QString tagName, bool caseSensitive,
+ QString namespaceName2, QString tagName2, bool caseSensitive2)
+{
+ QString tag1Name, tag2Name;
+ if(namespaceName.isEmpty())
+ {
+ if(!namespaceName.isEmpty())
+ return false;//namespace missmatch
+ tag1Name = caseSensitive ? tagName : tagName.upper();
+ tag2Name = caseSensitive2 ? tagName2 : tagName2.upper();
+ if("/" + tag1Name != tag2Name)
+ return false;//not the closing tag
+ }
+ else
+ {
+ if(namespaceName2.isEmpty())
+ return false;//namespace missmatch
+ tag1Name = caseSensitive ? (namespaceName + tagName) : (namespaceName.upper() +
+ tagName.upper());
+ tag2Name = caseSensitive2 ? (namespaceName2 + tagName2) : (namespaceName2.upper() +
+ tagName2.upper());
+ if("/" + tag1Name != tag2Name)
+ return false; //namespace missmatch or not the closing tag
+ }
+ return true;
+}
+
+int QuantaCommon::denyBinaryInsert(QWidget *window)
+{
+ int result = KMessageBox::questionYesNo(window, i18n("The file type is not recognized. \
+ Opening binary files may confuse Quanta.\n Are you sure you want to open this file?"),
+ i18n("Unknown Type"), KStdGuiItem::open(), i18n("Do Not Open"), "Open Everything");
+ return result;
+}
+
+bool QuantaCommon::checkOverwrite(const KURL& url, QWidget *window)
+{
+ bool result = true;
+
+ if (QExtFileInfo::exists(url, false, window))
+ {
+ if (KMessageBox::warningContinueCancel(window,
+ i18n( "<qt>The file <b>%1</b> already exists.<br>Do you want to overwrite it?</qt>" ).arg(url.prettyURL(0, KURL::StripFileProtocol)), QString::null, i18n("Overwrite")) == KMessageBox::Cancel)
+ result = false;
+ }
+
+ return result;
+}
+
+QStringList QuantaCommon::readPathListEntry(KConfig *config, const QString &pKey)
+{
+ QStringList list = config->readPathListEntry(pKey);
+ QStringList::Iterator end = list.end();
+ for (QStringList::Iterator it = list.begin(); it != end; ++it)
+ {
+ KURL u = KURL::fromPathOrURL(*it);
+ if (u.isValid() && u.isLocalFile())
+ {
+ u.setPath(QExtFileInfo::canonicalPath(u.path()));
+ *it = u.url();
+ }
+ }
+ return list;
+}
+
+QString QuantaCommon::readPathEntry(KConfig *config, const QString &pKey)
+{
+ QString path = config->readPathEntry(pKey);
+ KURL u = KURL::fromPathOrURL(path);
+ if (u.isValid() && u.isLocalFile())
+ {
+ u.setPath(QExtFileInfo::canonicalPath(u.path()));
+ path = u.url();
+ }
+ return path;
+}
+
+QString QuantaCommon::encodedChar(uint code)
+{
+
+ if (replacementMap.contains(code))
+ return QString("%1;").arg(replacementMap[code]);
+ else
+ return QString("&#%1;").arg(code);
+}
+
diff --git a/quanta/utility/quantacommon.h b/quanta/utility/quantacommon.h
new file mode 100644
index 00000000..a88276b7
--- /dev/null
+++ b/quanta/utility/quantacommon.h
@@ -0,0 +1,225 @@
+/***************************************************************************
+ quantacommon.h - description
+ -------------------
+ begin : Sat Jul 27 2002
+ copyright : (C) 2002, 2003 by Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+#ifndef QUANTACOMMON_H
+#define QUANTACOMMON_H
+
+#include <kdeversion.h>
+
+#include "qtag.h"
+#include "node.h"
+#include "parser.h"
+
+/**Some common, mostly static functions.
+ *@author Andras Mantia
+ */
+
+#define DEFAULT_DTD QString("-//W3C//DTD HTML 4.01 Transitional//EN")
+
+class QString;
+class DCOPReply;
+class KURL;
+class KStandardDirs;
+class QWidget;
+class Tag;
+
+class KConfig;
+class KPopupMenu;
+
+/** Describes one abbreviation group */
+class Abbreviation{
+public:
+/*A list with abbreviations in the for of: <template templatename, code> */
+ QMap<QString, QString> abbreviations;
+ QStringList dteps;
+};
+
+
+//Quanta main configuration structure
+class QConfig{
+public:
+ //Tag style options
+ uint tagCase;
+ uint attrCase;
+ QChar attrValueQuotation;
+ bool closeOptionalTags;
+ bool closeTags;
+ bool updateClosingTags;
+
+ //editor settings
+ bool useAutoCompletion;
+ bool enableDTDToolbar;
+ QString defaultEncoding;
+
+ //parser options
+ bool instantUpdate;
+ bool showEmptyNodes;
+ bool showClosingTags;
+ uint refreshFrequency;
+ QString defaultDocType;
+ uint expandLevel;
+ bool showDTDSelectDialog;
+ QString showCloseButtons; ///< can be Disabled, ShowAlways or ShowDelayed
+ uint toolviewTabs; ///< how does the toolview tabs look like
+
+ //kafka sync options
+ bool quantaRefreshOnFocus;
+ int quantaRefreshDelay;
+ bool kafkaRefreshOnFocus;
+ int kafkaRefreshDelay;
+
+ //kafka indentation options
+ bool inlineNodeIndentation;
+
+ //environment options
+ QString globalDataDir; //not stored, initialized on app startup
+ QStringList pluginSearchPaths; //global but read from plugins.rc
+ QString markupMimeTypes;
+ QString scriptMimeTypes;
+ QString imageMimeTypes;
+ QString textMimeTypes;
+ QString previewPosition;
+ QString docPosition;
+ QString windowLayout;
+ uint autosaveInterval;
+ QString backupDirPath;
+ QString quantaPID;
+ bool showHiddenFiles; ///< show hidden files in files treeview?
+ bool saveTrees; ///< save tree status for local trees?
+ QMap<QString, Abbreviation> abbreviations; ///< the abbreviation groups
+ bool replaceAccented; ///< replace or not the accented characters
+ bool replaceNotInEncoding; ///< replace characters with their entity number if they cannot be saved in the current encoding of the document.
+ bool smartTagInsertion; //enable/disable smartTagInsertion
+ };
+
+typedef struct DirInfo{
+ QString mimeType;
+ QString preText;
+ QString postText;
+ bool usePrePostText;
+ };
+
+/**Some common, mostly static functions.
+ *@author Andras Mantia
+ */
+
+class QuantaCommon {
+public:
+ QuantaCommon();
+ ~QuantaCommon();
+
+ /** convert tag to upper or lower case */
+ static QString tagCase( const QString& tag);
+ /** convert tag to upper or lower case */
+ static QString attrCase( const QString& attr);
+/** returns the attribute value in quoted form, by taking care of the
+quotation setting*/
+ static QString quoteAttributeValue(const QString& value);
+ /** Set's up the url correctly from urlString. */
+ static void setUrl(KURL &url, const QString& urlString);
+ /** No descriptions */
+ static bool isSingleTag(const QString& dtdName, const QString& tag);
+ /** No descriptions */
+ static bool isOptionalTag(const QString& dtdName, const QString& tag);
+ /** No descriptions */
+ static bool isKnownTag(const QString& dtdName, const QString& tag);
+ /** No descriptions */
+ static AttributeList* tagAttributes(const QString& dtdName, const QString& tag);
+ /** Returns the QTag object for the tag "tag" from the DTD named "dtdname". */
+ static QTag* tagFromDTD(const QString& dtdName, const QString& tag);
+ /** Returns the QTag object for the tag "tag" from the DTD. */
+ static QTag* tagFromDTD(const DTDStruct* dtd, const QString& tag);
+ /** Returns the QTag object for the node "node" from node's DTD. */
+ static QTag* tagFromDTD(Node *node);
+ /** Returns an XML style string containing the GUI for attributes. */
+ static QString xmlFromAttributes(AttributeList* attributes);
+ /** Returns 0 if the (line,col) is inside the area specified by the other arguments,
+ -1 if it is before the area and 1 if it is after. */
+ static int isBetween(int line, int col, int bLine, int bCol, int eLine, int eCol);
+ /** Returns a pointer to a KStandardDirs object usable for plugin searchup. type is the plugin binary type (exe or lib). The returned
+pointer must be deleted by the caller!! */
+ static KStandardDirs* pluginDirs(const char *type);
+
+ /** Return true, if the url has the mimetype starting with type. */
+ static bool checkMimeGroup(const KURL& url, const QString& type);
+ /** Return true, if the url has the mimetype type. */
+ static bool checkMimeType(const KURL& url, const QString& type);
+ /** Return true, if the url has exactly the mimetype type. */
+ static bool checkExactMimeType(const KURL& url, const QString& type);
+ /** Returns the url without the filename. */
+ static KURL convertToPath(const KURL& url);
+ /** Return a string to be used when an url is saved to the project file.
+ Returns url.url() if it's an absolute url and
+ url.path() if the url is relative */
+ static QString qUrl(const KURL& url);
+ /** No descriptions */
+ static void dirCreationError(QWidget *widget, const KURL& url);
+ /**
+ Adds the backslash before the special chars (like ?, *, . ) so the returned string can be used in regular expressions.
+ */
+ static QString makeRxCompatible(const QString& s);
+ /** Returns the translated a_str in English. A "back-translation" useful e.g in case of CSS elements selected from a listbox. */
+ static QString i18n2normal(const QString& a_str);
+
+/** No descriptions */
+ static void normalizeStructure(QString f,QStringList& l);
+ /**Returns true if tag2 is the closing pair of tag1. It's namespace aware.*/
+ static bool closesTag(Tag *tag1, Tag *tag2);
+ static bool closesTag(QString namespaceName, QString tagName, bool caseSensitive,
+ QString namespaceName2, QString tagName2, bool caseSensitive2);
+ static int denyBinaryInsert(QWidget *window);
+ static void removeCommentsAndQuotes(QString& str, const DTDStruct* dtd);
+ static bool insideCommentsOrQuotes(int position, const QString &string, const DTDStruct *dtd);
+ /** Calls a Quanta DCOP method.
+ * @param interface the DCOP interface the method belongs to
+ * @param method the DCOP method name (with the argument types)
+ * @param arguments comma separated list of argument
+ * @return the return value of the DCOP caller
+ */
+ static DCOPReply callDCOPMethod(const QString& interface, const QString& method, const QString& arguments);
+ /** Checks if url exists and shows a question about overwriting it.
+ * @param url the url to check
+ * @return true if the user answered yes, false otherwise.
+ */
+ static bool checkOverwrite(const KURL& url, QWidget *window);
+
+ /**
+ * Same as KConfigBase::readPathListEntry, but resolves symlinks
+ * @param config
+ * @param pKey
+ * @return
+ */
+ static QStringList readPathListEntry(KConfig *config, const QString &pKey);
+
+ /**
+ * Same as KConfigBase::readPathEntry, but resolves symlinks
+ * @param config
+ * @param pKey
+ * @return
+ */
+ static QString readPathEntry(KConfig *config, const QString &pKey);
+
+ /**
+ * Returns the HTML encoding string for character with the specified code.
+ * If no such literal encoding is known (like &auml;), the numeric encoding
+ * is returned: &#code;
+ * @param code the numeric code of the character
+ * @return the encoded string
+ */
+ static QString encodedChar(uint code);
+
+};
+
+#endif
diff --git a/quanta/utility/quantanetaccess.cpp b/quanta/utility/quantanetaccess.cpp
new file mode 100644
index 00000000..095f9e08
--- /dev/null
+++ b/quanta/utility/quantanetaccess.cpp
@@ -0,0 +1,268 @@
+/***************************************************************************
+ quantanetaccess.h - description
+ -------------------
+ begin : Jun 21 2004
+ copyright : (C) 2004 by Jens Herden <jhe@kdewebdev.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+#include <qstring.h>
+#include <qwidget.h>
+#include <qdir.h>
+
+#include <kio/netaccess.h>
+#include <kurl.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kfileitem.h>
+#include <kstringhandler.h>
+
+#include "qextfileinfo.h"
+#include "quantanetaccess.h"
+#include "project.h"
+
+bool QuantaNetAccess::upload(const QString& src, const KURL& target, QWidget* window, bool confirm)
+{
+ bool ok = KIO::NetAccess::upload(src, target, window);
+ if (ok) {
+ checkProjectInsert(target, window, confirm);
+ } else {
+ if (confirm)
+ errorMsg(window);
+ }
+ return ok;
+}
+
+
+bool QuantaNetAccess::file_copy( const KURL& src, const KURL& target, int permissions,
+ bool overwrite, bool resume, QWidget* window, bool confirm)
+{
+ bool ok = KIO::NetAccess::file_copy( src, target, permissions, overwrite, resume, window );
+ if (ok) {
+ checkProjectInsert(target, window, confirm);
+ } else {
+ if (confirm)
+ errorMsg(window);
+ }
+ return ok;
+}
+
+
+bool QuantaNetAccess::file_move( const KURL& src, const KURL& target, int permissions,
+ bool overwrite, bool resume, QWidget* window, bool confirm)
+{
+ // don't ask if move is inside of the project
+ bool oldConfirm = confirm;
+ if ( Project::ref()->projectBaseURL().isParentOf(src) &&
+ Project::ref()->projectBaseURL().isParentOf(target) )
+ {
+ confirm = false;
+ }
+ if ( !checkProjectRemove(src, window, confirm)) {
+ return false;
+ }
+ bool ok = KIO::NetAccess::file_move( src, target, permissions, overwrite, resume, window );
+ if (ok) {
+ checkProjectInsert(target, window, confirm);
+ } else {
+ if (oldConfirm)
+ errorMsg(window);
+ }
+ return ok;
+}
+
+
+bool QuantaNetAccess::dircopy( const KURL::List & srcList, const KURL & target, QWidget* window, bool confirm )
+{
+ bool ok = KIO::NetAccess::dircopy( srcList, target, window );
+ if (ok) {
+ KURL url;
+ for ( KURL::List::ConstIterator it = srcList.begin(); it != srcList.end(); ++it ) {
+ url = target;
+ url.adjustPath(+1);
+ url.setFileName((*it).fileName());
+ checkProjectInsert(url, window, confirm);
+ }
+ } else {
+ if (confirm)
+ errorMsg(window);
+ }
+ return ok;
+}
+
+
+bool QuantaNetAccess::move( const KURL::List& srcList, const KURL& target, QWidget* window, bool confirm )
+{
+ KURL targetURL = adjustURL(target);
+ bool oldConfirm = confirm;
+ bool moveInsideProject = false;
+ bool targetInProject = Project::ref()->projectBaseURL().isParentOf(targetURL);
+ KURL url;
+ // first we ask about the URLs in the list without actually removing them from the project
+ for ( KURL::List::ConstIterator it = srcList.begin(); it != srcList.end(); ++it ) {
+ //don't ask if move is inside of the project
+ url = adjustURL(*it);
+ if (targetInProject && Project::ref()->projectBaseURL().isParentOf(url) )
+ {
+ confirm = false;
+ moveInsideProject = true;
+ }
+ if ( !checkProjectRemove(*it, window, confirm, false)) {
+ return false;
+ confirm = oldConfirm;
+ }
+ }
+ // all URLs are confirmed, we remove them from the project
+ for ( KURL::List::ConstIterator it = srcList.begin(); it != srcList.end(); ++it ) {
+ if ( Project::ref()->projectBaseURL().isParentOf(*it) )
+ Project::ref()->slotRemove(*it);
+ }
+ bool ok = KIO::NetAccess::move( srcList, targetURL, window );
+ if (ok) {
+ KURL url;
+ for ( KURL::List::ConstIterator it = srcList.begin(); it != srcList.end(); ++it ) {
+ url = target;
+ url.adjustPath(+1);
+ url.setFileName((*it).fileName());
+ checkProjectInsert(url, window, confirm);
+ Project::ref()->urlMoved(*it, url);
+ }
+ } else {
+ if (confirm)
+ errorMsg(window);
+ }
+ return ok;
+}
+
+
+bool QuantaNetAccess::del( const KURL & url, QWidget* window, bool confirm )
+{
+ if ( !checkProjectDel(url, window, confirm)) {
+ return false;
+ }
+ bool ok = KIO::NetAccess::del( url, window );
+ if (!ok && confirm)
+ {
+ errorMsg(window);
+ }
+ return ok;
+}
+
+
+bool QuantaNetAccess::mkdir( const KURL & url, QWidget* window, int permissions, bool confirm )
+{
+ KURL u = url;
+ u.adjustPath(-1); //some servers refuse to create directories ending with a slash
+ bool ok = KIO::NetAccess::mkdir( u, window, permissions );
+ if (ok) {
+ checkProjectInsert(url, window, confirm);
+ } else {
+ if (confirm)
+ errorMsg(window);
+ }
+ return ok;
+}
+
+
+void QuantaNetAccess::checkProjectInsert(const KURL& target, QWidget* window, bool confirm)
+{
+ if ( !Project::ref()->hasProject()) return;
+ KURL saveUrl = adjustURL(target);
+ KURL baseURL = Project::ref()->projectBaseURL();
+ if ( baseURL.isParentOf(saveUrl) && !Project::ref()->contains(saveUrl) )
+ {
+ if (confirm)
+ {
+ QString nice = QExtFileInfo::toRelative(saveUrl, baseURL).path();
+ nice = KStringHandler::lsqueeze(nice, 60);
+ if ( KMessageBox::Yes != KMessageBox::questionYesNo(window, i18n("<qt>Do you want to add <br><b>%1</b><br> to the project?</qt>").arg(nice), i18n("Add to Project"), KStdGuiItem::add(), i18n("Do Not Add"), "AddToProject") )
+ {
+ return;
+ }
+ }
+ KFileItem fileItem(KFileItem::Unknown, KFileItem::Unknown, saveUrl);
+ if ( fileItem.isDir() )
+ Project::ref()->slotAddDirectory(saveUrl, false);
+ else
+ Project::ref()->slotInsertFile(saveUrl);
+ }
+}
+
+
+bool QuantaNetAccess::checkProjectRemove(const KURL& src, QWidget* window, bool confirm, bool remove)
+{
+ if ( !Project::ref()->hasProject() ) return true;
+ KURL url = adjustURL(src);
+ KURL baseURL = Project::ref()->projectBaseURL();
+ if ( baseURL.isParentOf(url) && Project::ref()->contains(url) )
+ {
+ if (confirm)
+ {
+ QString nice = QExtFileInfo::toRelative(url, baseURL).path();
+ nice = KStringHandler::lsqueeze(nice, 60);
+ if ( KMessageBox::Continue != KMessageBox::warningContinueCancel(window, i18n("<qt>Do you really want to remove <br><b>%1</b><br> from the project?</qt>").arg(nice), i18n("Remove From Project"), KStdGuiItem::remove(), "RemoveFromProject") )
+ {
+ return false;
+ }
+ }
+ if (remove)
+ Project::ref()->slotRemove(url);
+ }
+ return true;
+}
+
+
+bool QuantaNetAccess::checkProjectDel(const KURL& src, QWidget* window, bool confirm)
+{
+ KURL url = adjustURL(src);
+ if ( Project::ref()->hasProject() )
+ {
+ if ( Project::ref()->projectBaseURL().isParentOf(url) && Project::ref()->contains(url) )
+ {
+ if (confirm)
+ {
+ QString nice = url.prettyURL(0, KURL::StripFileProtocol);
+ nice = KStringHandler::csqueeze(nice, 60);
+ if ( KMessageBox::Continue != KMessageBox::warningContinueCancel(window, i18n("<qt>Do you really want to delete <br><b>%1</b><br> and remove it from the project?</qt>").arg(nice), i18n("Delete & Remove From Project"), KStdGuiItem::del(), "DeleteAndRemoveFromProject") )
+ {
+ return false;
+ }
+ }
+ Project::ref()->slotRemove(url);
+ return true;
+ }
+ }
+ // confirm normal delete if wanted
+ if (confirm) {
+ QString nice = url.prettyURL(0, KURL::StripFileProtocol);
+ nice = KStringHandler::csqueeze(nice, 60);
+ return (KMessageBox::Continue == KMessageBox::warningContinueCancel(window, i18n("<qt>Do you really want to delete <br><b>%1</b>?</qt>").arg(nice), i18n("Delete File or Folder"), KStdGuiItem::del(), "DeleteFileOrFolder") );
+ }
+ return true;
+}
+
+KURL QuantaNetAccess::adjustURL(const KURL &url)
+{
+ KURL u = url;
+ if ( u.isLocalFile() )
+ {
+ QDir dir(u.path());
+ u.setPath(dir.canonicalPath());
+ }
+ return u;
+}
+
+
+void QuantaNetAccess::errorMsg(QWidget* window)
+{
+ QString msg = KIO::NetAccess::lastErrorString();
+ if ( !msg.isEmpty())
+ KMessageBox::sorry(window, msg);
+}
diff --git a/quanta/utility/quantanetaccess.h b/quanta/utility/quantanetaccess.h
new file mode 100644
index 00000000..abdedc86
--- /dev/null
+++ b/quanta/utility/quantanetaccess.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ quantanetaccess.h - description
+ -------------------
+ begin : Sat Jul 27 2002
+ copyright : (C) 2004 by Jens Herden <jhe@kdewebdev.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+#ifndef QUANTANETACCESS_H
+#define QUANTANETACCESS_H
+
+
+/** @short helperclass to track changes in the project
+
+ This class be used as replacement of KIO::NetAccess (look there for details).
+ Every possible impact on the project will be monitored and signaled to the project.
+
+ If you don't want user interaction use the extra parameter confirm
+
+ If the user don't accept the removal from the project no action happens
+ and the caller gets false as result.
+*/
+
+class QuantaNetAccess
+{
+public:
+
+ static bool upload(const QString& src, const KURL& target, QWidget* window, bool confirm = true);
+
+ static bool copy( const KURL & src, const KURL & target, QWidget* window, bool confirm = true )
+ {
+ return file_copy( src, target, -1, false /*not overwrite*/, false, window, confirm );
+ }
+
+ static bool file_copy( const KURL& src, const KURL& target, int permissions,
+ bool overwrite, bool resume, QWidget* window, bool confirm = true );
+
+ static bool file_move( const KURL& src, const KURL& target, int permissions,
+ bool overwrite, bool resume, QWidget* window, bool confirm = true );
+
+ static bool dircopy( const KURL & src, const KURL & target, QWidget* window, bool confirm = true )
+ {
+ KURL::List srcList;
+ srcList.append( src );
+ return dircopy( srcList, target, window, confirm );
+ };
+
+ static bool dircopy( const KURL::List & srcList, const KURL & target, QWidget* window, bool confirm = true );
+
+ static bool move( const KURL& src, const KURL& target, QWidget* window, bool confirm = true )
+ {
+ KURL::List srcList;
+ srcList.append( src );
+ return move( srcList, target, window, confirm );
+ }
+
+ static bool move( const KURL::List& srcList, const KURL& target, QWidget* window, bool confirm = true );
+
+ static bool del( const KURL & url, QWidget* window, bool confirm = true );
+
+ static bool mkdir( const KURL & url, QWidget* window, int permissions, bool confirm = true );
+
+ static void checkProjectInsert(const KURL& target, QWidget* window, bool confirm = true);
+
+ static bool checkProjectRemove(const KURL& target, QWidget* window, bool confirm = true, bool remove = true);
+
+ static bool checkProjectDel(const KURL& target, QWidget* window, bool confirm = true);
+
+ static KURL adjustURL(const KURL &url);
+
+ static void errorMsg(QWidget* window = 0);
+
+private:
+ QuantaNetAccess() {};
+ ~QuantaNetAccess() {};
+
+};
+
+#endif
diff --git a/quanta/utility/resource.h b/quanta/utility/resource.h
new file mode 100644
index 00000000..3f09946e
--- /dev/null
+++ b/quanta/utility/resource.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ resource.h - description
+ -------------------
+ begin : ÷ÔÒ íÁÊ 9 13:29:57 EEST 2000
+ copyright : (C) 2000 by Dmitry Poplavsky & Alexander Yakovlev & Eric Laffoon <pdima@users.sourceforge.net,yshurik@linuxfan.com,sequitur@easystreet.com>
+ (C) 2001-2003 Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef RESOURCE_H
+#define RESOURCE_H
+
+
+class KDirWatch;
+class KProgress;
+class QuantaApp;
+class QStringList;
+class KTempFile;
+class KTempDir;
+
+class Node;
+class Parser;
+struct QConfig;
+struct DTDStruct;
+
+
+extern QConfig qConfig;
+extern QString tmpDir;
+
+extern QRegExp scriptBeginRx;
+extern QRegExp scriptEndRx;
+
+extern Node *baseNode;
+extern Parser *parser;
+
+extern KDirWatch *fileWatcher;
+
+extern QString toolbarExtension;
+extern QRegExp newLineRx;
+extern QStringList charList; //hold the list of the &char; chars. See the data/chars file.
+extern QPtrList<KTempFile> tempFileList;
+extern QPtrList<KTempDir> tempDirList;
+
+extern KProgress *progressBar;
+extern QuantaApp *quantaApp;
+extern const QString resourceDir;
+extern bool typingInProgress;
+
+extern int nodeNum;
+
+#endif // RESOURCE_H
diff --git a/quanta/utility/tagaction.cpp b/quanta/utility/tagaction.cpp
new file mode 100644
index 00000000..98bcf87c
--- /dev/null
+++ b/quanta/utility/tagaction.cpp
@@ -0,0 +1,1285 @@
+/***************************************************************************
+ tagaction.cpp - description
+ -------------------
+ begin : ?
+ copyright : (C) ? Dmitry Poplavsky
+ (C) 2002-2005 Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+//other includes
+#include <sys/types.h>
+#include <unistd.h>
+
+
+//qt includes
+#include <qdir.h>
+#include <qdom.h>
+#include <qfile.h>
+#include <qtimer.h>
+
+//kde includes
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kprocess.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kshortcut.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <ktexteditor/document.h>
+#include <ktexteditor/viewcursorinterface.h>
+#include <ktexteditor/editinterface.h>
+#include <ktexteditor/selectioninterface.h>
+#include <ktexteditor/selectioninterfaceext.h>
+
+//app includes
+#include "tagaction.h"
+#include "myprocess.h"
+#include "document.h"
+#include "quantaview.h"
+#include "quanta.h"
+// #include "quantadoc.h"
+#include "tagdialog.h"
+#include "messageoutput.h"
+#include "quantacommon.h"
+#include "resource.h"
+#include "qextfileinfo.h"
+#include "undoredo.h"
+#include "kafkacommon.h"
+#include "wkafkapart.h"
+#include "cursors.h"
+#include "tag.h"
+#include "project.h"
+
+#include "viewmanager.h"
+
+MyProcess::MyProcess():KProcess()
+{
+}
+
+int MyProcess::commSetupDoneC()
+{
+ ::setpgid(pid_, 0);
+ return KProcess::commSetupDoneC();
+}
+
+TagAction::TagAction( QDomElement *element, KMainWindow *parentMainWindow, bool toggle)
+ : KToggleAction(element->attribute("text").isEmpty() ? QString("") : i18n(element->attribute("text").utf8()),
+ KShortcut(element->attribute("shortcut")), 0, 0, parentMainWindow->actionCollection(), element->attribute("name")),
+ //disable toggle now m_toggle(toggle)
+ m_toggle(false)
+{
+ setToolTip(element->attribute("tooltip"));
+ m_parentMainWindow = parentMainWindow;
+ m_modified = false;
+ m_useInputFile = false;
+ m_useOutputFile = false;
+ tag = element->cloneNode().toElement();
+ QString s = tag.attribute("icon");
+ if (!QFileInfo(s).exists())
+ {
+ s = QFileInfo(s).fileName();
+ }
+ setIcon(s);
+ m_file = 0L;
+ loopStarted = false;
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,4,0)
+ connect(this, SIGNAL(activated(KAction::ActivationReason, Qt::ButtonState)),
+ SLOT(slotActionActivated(KAction::ActivationReason, Qt::ButtonState)));
+#else
+ connect(this, SIGNAL(activated()), SLOT(slotActionActivated()));
+#endif
+ connect(this, SIGNAL(showMessage(const QString&, bool)), m_parentMainWindow, SIGNAL(showMessage(const QString&, bool)));
+ connect(this, SIGNAL(clearMessages()), m_parentMainWindow, SIGNAL(clearMessages()));
+ connect(this, SIGNAL(showMessagesView()), m_parentMainWindow, SLOT(slotShowMessagesView()));
+ connect(this, SIGNAL(createNewFile()), m_parentMainWindow, SLOT(slotFileNew()));
+}
+
+TagAction::~TagAction()
+{
+}
+
+QString TagAction::type()
+{
+ return tag.attribute("type","");
+}
+
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,4,0)
+bool TagAction::slotActionActivated(KAction::ActivationReason reason, Qt::ButtonState /*state*/)
+{
+ QuantaView *view = ViewManager::ref()->activeView();
+ if ( !view || !view->document())
+ return false;
+
+ unsigned int line, col;
+ Document *w = view->document();
+ w->viewCursorIf->cursorPositionReal(&line, &col);
+ NodeModifsSet* modifs = new NodeModifsSet();
+
+ QString space;
+ space.fill( ' ', col);
+
+ QString type = tag.attribute("type","");
+
+ if ( type == "tag" && view->hadLastFocus() == QuantaView::VPLFocus && toggable())
+ {
+ KafkaWidget* kafka_widget = KafkaDocument::ref()->getKafkaWidget();
+ QString tag_name = XMLTagName();
+
+ NodeSelectionInd selection;
+ selection.fillWithVPLCursorSelection();
+
+ Node* start_node = 0, *end_node = 0, *current_node = 0;
+ int start_offset = 0, end_offset = 0, current_offset = 0;
+ QString scope;
+ if(kafka_widget->hasSelection())
+ {
+ // get selection
+ start_node = kafkaCommon::getNodeFromLocation(selection.cursorNode());
+ end_node = kafkaCommon::getNodeFromLocation(selection.cursorNodeEndSel());
+ current_node = end_node;
+ start_offset = selection.cursorOffset();
+ end_offset = selection.cursorOffsetEndSel();
+ current_offset = end_offset;
+ }
+ else
+ {
+ current_node = kafkaCommon::getNodeFromLocation(selection.cursorNode());
+ Q_ASSERT(current_node);
+ if (current_node)
+ {
+ current_offset = selection.cursorOffset();
+
+ start_node = end_node = current_node;
+ start_offset = end_offset = current_offset;
+
+ QTag* tag_description = QuantaCommon::tagFromDTD(KafkaDocument::ref()->getCurrentDoc()->defaultDTD(), XMLTagName());
+ scope = tag_description->scope();
+ // Q_ASSERT(!scope.isNull());
+ if(scope.isNull())
+ scope = "word"; // FIXME temporary
+
+ if(scope.lower() == "word")
+ {
+ // Apply/deapply the tag in the word
+ if(kafkaCommon::isBetweenWords(current_node, current_offset))
+ {
+ kafkaCommon::getStartOfWord(start_node, start_offset);
+ kafkaCommon::getEndOfWord(end_node, end_offset);
+ }
+ }
+ else if(scope.lower() == "paragraph")
+ {
+ kafkaCommon::getStartOfParagraph(start_node, start_offset);
+ kafkaCommon::getEndOfParagraph(end_node, end_offset);
+ }
+ else if(reason != KAction::EmulatedActivation) // is between words: save the state and return
+ {
+ if(!toggled())
+ quantaApp->insertTagActionPoolItem(name());
+ else
+ quantaApp->removeTagActionPoolItem(name());
+
+ return true;
+ }
+ }
+ }
+ Q_ASSERT(start_node && end_node);
+
+/* kdDebug(23100) << "start node string: " << start_node->tag->tagStr() << endl;
+ kdDebug(23100) << "start node offset: " << start_offset << endl;
+ kdDebug(23100) << "start node string length: " << start_node->tag->tagStr().length() << endl; */
+ if (!start_node || !end_node)
+ return true; //FIXME: AndraS: don't crash
+ if(scope != "paragraph") {
+ start_node = kafkaCommon::getCorrectStartNode(start_node, start_offset);
+ end_node = kafkaCommon::getCorrectEndNode(end_node, end_offset);
+ if (!start_node || !end_node)
+ return true; //FIXME: AndraS: don't crash
+ }
+ NodeSelection cursor_holder;
+ cursor_holder.setCursorNode(current_node);
+ cursor_holder.setCursorOffset(current_offset);
+
+ int inside_tag = kafkaCommon::isInsideTag(start_node, end_node, tag_name);
+ if(inside_tag == -1)
+ {
+ applyTagInSelection(start_node, start_offset, end_node, end_offset, cursor_holder, modifs);
+ }
+ else if(inside_tag == 1)
+ {
+ QString attribute_name(tag.attribute("attribute_name", QString()));
+ QString attribute_value(tag.attribute("attribute_value", QString()));
+
+ // special case
+ if(!attribute_name.isEmpty() && !attribute_value.isEmpty())
+ {
+ Node* tag_parent = kafkaCommon::hasParent(start_node, end_node, tag_name);
+
+ Node* aux1 = start_node->previousSibling();
+ while(aux1->tag->type == Tag::Empty)
+ aux1 = aux1->previousSibling();
+ Node* aux2 = end_node->nextSibling();
+ while(aux2->tag->type == Tag::Empty)
+ aux2 = aux2->nextSibling();
+
+ if(aux1 == tag_parent && aux2 == tag_parent->getClosingNode())
+ {
+ if(tag_parent->tag->attributeValue(attribute_name, true) == attribute_value)
+ kafkaCommon::editNodeAttribute(tag_parent, attribute_name, QString(), modifs);
+ else
+ kafkaCommon::editNodeAttribute(tag_parent, attribute_name, attribute_value, modifs);
+ }
+ else
+ applyTagInSelection(start_node, start_offset, end_node, end_offset, cursor_holder, modifs);
+ }
+ else
+ deapplyTagInSelection(start_node, start_offset, end_node, end_offset, cursor_holder, modifs);
+ }
+ else
+ {
+ applyTagInMixedSelection(start_node, start_offset, end_node, end_offset, cursor_holder, modifs);
+ }
+ w->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif, &cursor_holder);
+ KafkaDocument::ref()->getKafkaWidget()->setCurrentNode(cursor_holder.cursorNode(), cursor_holder.cursorOffset());
+ return true;
+ }
+
+ if ( type == "tag" ) {
+ QDomElement otag = (tag.namedItem("tag")).toElement();
+ QDomElement xtag = (tag.namedItem("xtag")).toElement();
+
+ QString attr = otag.text();
+ if ( attr[0] == '<' )
+ attr.remove(0,1);
+ if ( attr.right(1) == ">" )
+ attr.remove( attr.length()-1, 1 );
+ attr = attr.stripWhiteSpace();
+ int i = 0;
+ while ( !attr[i].isSpace() && !attr[i].isNull() ) i++;
+ QString name = attr.left(i);
+ attr = attr.remove(0,i).stripWhiteSpace();
+
+ if (otag.attribute("useDialog","false") == "true" && QuantaCommon::isKnownTag(w->defaultDTD()->name, name))
+ {
+ view->insertNewTag(name, attr, xtag.attribute("inLine","true") == "true");
+ }
+ else
+ {
+ QString s1 = QuantaCommon::tagCase(name);
+ if (otag.text().left(1) == "<") s1 = "<"+s1;
+ if (!attr.isEmpty())
+ s1 += " "+QuantaCommon::attrCase(attr);
+ if (otag.text().right(1) == ">")
+ {
+ QTag *dtdTag = QuantaCommon::tagFromDTD(w->defaultDTD(), name);
+ if ( w->defaultDTD()->singleTagStyle == "xml" && dtdTag &&
+ (dtdTag->isSingle() || (!qConfig.closeOptionalTags && dtdTag->isOptional()))
+ )
+ {
+ s1.append(" /");
+ }
+
+ s1.append(">");
+ }
+
+ QString s2;
+ if ( xtag.attribute("use","false") == "true" )
+ {
+ if (qConfig.closeTags)
+ s2 = QuantaCommon::tagCase(xtag.text());
+ if ( xtag.attribute("inLine","true") == "true" )
+ {
+ /** FIXME this is quick and temporary */
+ view->insertOutputInTheNodeTree(s1, s2);
+ }
+ else
+ {
+ view->insertOutputInTheNodeTree(s1, s2);
+ }
+ }
+ else
+ view->insertOutputInTheNodeTree(s1, s2);
+ }
+ }
+
+ if (view->hadLastFocus() != QuantaView::VPLFocus)
+ {
+
+
+ if ( type == "text" )
+ w->insertTag( tag.namedItem("text").toElement().text() );
+
+ if ( type == "script" )
+ {
+ proc = new MyProcess();
+ proc->setWorkingDirectory(quantaApp->projectBaseURL().path());
+
+ QDomElement script = tag.namedItem("script").toElement();
+ QString command = script.text();
+
+
+ if ( !w->isUntitled() ) {
+ QString fname = w->url().url();
+ if ( w->url().protocol() == "file")
+ fname = w->url().path();
+ command.replace("%f", fname );
+ }
+
+ pid_t pid = ::getpid();
+ if (kapp->inherits("KUniqueApplication"))
+ {
+ command.replace("%pid", QString("unique %1").arg(pid));
+ } else
+ {
+ command.replace("%pid", QString("%1").arg(pid));
+ }
+ QString buffer;
+ QString inputType = script.attribute("input","none");
+
+ if ( inputType == "current" ) {
+ buffer = w->editIf->text();
+ } else
+ if ( inputType == "selected" && w->selectionIf) {
+ buffer = w->selectionIf->selection();
+ }
+ command.replace("%input", buffer);
+ command = command.stripWhiteSpace();
+ int pos = command.find(' ');
+ QString args;
+ if (pos != -1)
+ {
+ args = command.mid(pos+1);
+ command = command.left(pos);
+ }
+ if (command.startsWith("~"))
+ {
+ command = command.mid(1);
+ command.prepend(QDir::homeDirPath());
+ }
+
+ *proc << command.stripWhiteSpace();
+ args = args.stripWhiteSpace();
+ if (!args.isEmpty())
+ {
+ pos = 0;
+ while (pos != -1 )
+ {
+ pos = args.find("%scriptdir");
+ QString scriptname;
+ if (pos != -1)
+ {
+ int begin = args.findRev('"', pos);
+ int end = -1;
+ if (begin == -1)
+ {
+ begin = args.findRev('\'', pos);
+ if (begin != -1)
+ end = args.find('\'', pos);
+ } else
+ {
+ end = args.find('"', pos);
+ }
+ if (begin == -1 || end != -1)
+ {
+ begin = args.findRev(' ', pos);
+ if (begin == -1)
+ begin = 0;
+ end = args.find(' ', pos);
+ if (end == -1)
+ end = args.length();
+ }
+ scriptname = args.mid(begin, end - begin).stripWhiteSpace();
+ scriptname.replace("%scriptdir","scripts");
+ // kdDebug(24000) << "Script name is: |" << scriptname << "|" << endl;
+ scriptname = " " + locate("appdata", scriptname);
+ // kdDebug(24000) << "Script found at: " << scriptname << endl;
+ args.replace(begin, end - begin, scriptname);
+ // kdDebug(24000) << "Modified argument list: " << args << endl;
+ }
+ }
+ int pos = args.find("%projectbase");
+ if (pos != -1)
+ {
+ QString s;
+ if (Project::ref()->hasProject())
+ s = Project::ref()->projectBaseURL().url();
+ args.replace("%projectbase", s);
+ }
+ QStringList argsList1 = QStringList::split(' ', args);
+ QStringList argsList;
+ for (uint i = 0; i < argsList1.count(); i++)
+ {
+ if (argsList1[i] == "%userarguments")
+ {
+ for (uint j = 0; j < m_argsList.count(); j++)
+ {
+ argsList.append(m_argsList[j]);
+ }
+ } else
+ argsList.append(argsList1[i]);
+ }
+ m_argsList.clear();
+ *proc << argsList;
+ }
+ firstOutput = true;
+ firstError = true;
+
+ connect( proc, SIGNAL(receivedStdout( KProcess*,char*,int)), this,
+ SLOT( slotGetScriptOutput(KProcess*,char*,int)));
+ connect( proc, SIGNAL(receivedStderr( KProcess*,char*,int)), this,
+ SLOT( slotGetScriptError(KProcess*,char*,int)));
+ connect( proc, SIGNAL(processExited( KProcess*)), this,
+ SLOT( slotProcessExited(KProcess*)));
+
+
+
+ if (!m_useOutputFile)
+ scriptOutputDest = script.attribute("output","none");
+ else
+ scriptOutputDest = "file";
+ scriptErrorDest = script.attribute("error","none");
+ if (scriptOutputDest == "message")
+ {
+ emit showMessagesView();
+ }
+
+ if (m_useInputFile)
+ {
+ *proc << m_inputFileName;
+ }
+
+ if (proc->start(KProcess::NotifyOnExit, KProcess::All))
+ {
+ emit clearMessages();
+ emit showMessage(i18n("The \"%1\" script started.\n").arg(actionText()), false);
+ if (!m_useInputFile)
+ {
+ if ( inputType == "current" || inputType == "selected" )
+ {
+ proc->writeStdin( buffer.local8Bit(), buffer.length() );
+ }
+ }
+ proc->closeStdin();
+ } else
+ {
+ KMessageBox::error(m_parentMainWindow, i18n("<qt>There was an error running <b>%1</b>.<br>Check that you have the <i>%2</i> executable installed and it is accessible.</qt>").arg(command + " " + args).arg(command), i18n("Script Not Found"));
+ ViewManager::ref()->activeView()->setFocus();
+ if (loopStarted)
+ {
+ qApp->exit_loop();
+ loopStarted = false;
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+}
+#else
+ // hack to compile. moc doesn't check the "#ifdef" at the declaration and the compiler complains
+ // of no matching function.
+bool TagAction::slotActionActivated(KAction::ActivationReason /*reason*/, Qt::ButtonState /*state*/)
+{return true;}
+#endif
+
+bool TagAction::slotActionActivated()
+{
+ QuantaView *view = ViewManager::ref()->activeView();
+ if ( !view || !view->document())
+ return false;
+
+ QString space="";
+ QString output;
+ unsigned int line, col;
+
+ Document *w = view->document();
+ w->viewCursorIf->cursorPositionReal(&line, &col);
+ space.fill( ' ', col);
+
+ QString type = tag.attribute("type","");
+
+ if ( type == "tag" ) {
+ QDomElement otag = (tag.namedItem("tag")).toElement();
+ QDomElement xtag = (tag.namedItem("xtag")).toElement();
+
+ QString attr = otag.text();
+ if ( attr[0] == '<' )
+ attr.remove(0,1);
+ if ( attr.right(1) == ">" )
+ attr.remove( attr.length()-1, 1 );
+ attr = attr.stripWhiteSpace();
+ int i = 0;
+ while ( !attr[i].isSpace() && !attr[i].isNull() ) i++;
+ QString name = attr.left(i);
+ attr = attr.remove(0,i).stripWhiteSpace();
+
+ if (otag.attribute("useDialog","false") == "true" && QuantaCommon::isKnownTag(w->defaultDTD()->name, name))
+ {
+ view->insertNewTag(name, attr, xtag.attribute("inLine","true") == "true");
+ }
+ else
+ {
+ QString s1 = QuantaCommon::tagCase(name);
+ if (otag.text().left(1) == "<") s1 = "<"+s1;
+ if (!attr.isEmpty())
+ s1 += " "+QuantaCommon::attrCase(attr);
+ if (otag.text().right(1) == ">")
+ {
+ QTag *dtdTag = QuantaCommon::tagFromDTD(w->defaultDTD(), name);
+ if ( w->defaultDTD()->singleTagStyle == "xml" && dtdTag &&
+ (dtdTag->isSingle() || (!qConfig.closeOptionalTags && dtdTag->isOptional()))
+ )
+ {
+ s1.append(" /");
+ }
+
+ s1.append(">");
+ }
+
+ QString s2;
+ if ( xtag.attribute("use","false") == "true" )
+ {
+ if (qConfig.closeTags)
+ s2 = QuantaCommon::tagCase(xtag.text());
+ if ( xtag.attribute("inLine","true") == "true" )
+ {
+ /** FIXME this is quick and temporary */
+ view->insertOutputInTheNodeTree(s1, s2);
+ }
+ else
+ {
+ view->insertOutputInTheNodeTree(s1, s2);
+ }
+ }
+ else
+ view->insertOutputInTheNodeTree(s1, s2);
+ }
+ }
+
+ if (view->hadLastFocus() != QuantaView::VPLFocus)
+ {
+
+
+ if ( type == "text" )
+ w->insertTag( tag.namedItem("text").toElement().text() );
+
+ if ( type == "script" )
+ {
+ proc = new MyProcess();
+ proc->setWorkingDirectory(quantaApp->projectBaseURL().path());
+
+ QDomElement script = tag.namedItem("script").toElement();
+ QString command = script.text();
+
+
+ if ( !w->isUntitled() ) {
+ QString fname = w->url().url();
+ if ( w->url().protocol() == "file")
+ fname = w->url().path();
+ command.replace("%f", fname );
+ }
+
+ pid_t pid = ::getpid();
+ if (kapp->inherits("KUniqueApplication"))
+ {
+ command.replace("%pid", QString("unique %1").arg(pid));
+ } else
+ {
+ command.replace("%pid", QString("%1").arg(pid));
+ }
+ QString buffer;
+ QString inputType = script.attribute("input","none");
+
+ if ( inputType == "current" ) {
+ buffer = w->editIf->text();
+ } else
+ if ( inputType == "selected" && w->selectionIf) {
+ buffer = w->selectionIf->selection();
+ }
+ command.replace("%input", buffer);
+ command = command.stripWhiteSpace();
+ int pos = command.find(' ');
+ QString args;
+ if (pos != -1)
+ {
+ args = command.mid(pos+1);
+ command = command.left(pos);
+ }
+ if (command.startsWith("~"))
+ {
+ command = command.mid(1);
+ command.prepend(QDir::homeDirPath());
+ }
+
+ *proc << command.stripWhiteSpace();
+ args = args.stripWhiteSpace();
+ if (!args.isEmpty())
+ {
+ pos = 0;
+ while (pos != -1 )
+ {
+ pos = args.find("%scriptdir");
+ QString scriptname;
+ if (pos != -1)
+ {
+ int begin = args.findRev('"', pos);
+ int end = -1;
+ if (begin == -1)
+ {
+ begin = args.findRev('\'', pos);
+ if (begin != -1)
+ end = args.find('\'', pos);
+ } else
+ {
+ end = args.find('"', pos);
+ }
+ if (begin == -1 || end != -1)
+ {
+ begin = args.findRev(' ', pos);
+ if (begin == -1)
+ begin = 0;
+ end = args.find(' ', pos);
+ if (end == -1)
+ end = args.length();
+ }
+ scriptname = args.mid(begin, end - begin).stripWhiteSpace();
+ scriptname.replace("%scriptdir","scripts");
+ // kdDebug(24000) << "Script name is: |" << scriptname << "|" << endl;
+ scriptname = " " + locate("appdata", scriptname);
+ // kdDebug(24000) << "Script found at: " << scriptname << endl;
+ args.replace(begin, end - begin, scriptname);
+ // kdDebug(24000) << "Modified argument list: " << args << endl;
+ }
+ }
+ int pos = args.find("%projectbase");
+ if (pos != -1)
+ {
+ QString s;
+ if (Project::ref()->hasProject())
+ s = Project::ref()->projectBaseURL().url();
+ args.replace("%projectbase", s);
+ }
+ QStringList argsList1 = QStringList::split(' ', args);
+ QStringList argsList;
+ for (uint i = 0; i < argsList1.count(); i++)
+ {
+ if (argsList1[i] == "%userarguments")
+ {
+ for (uint j = 0; j < m_argsList.count(); j++)
+ {
+ argsList.append(m_argsList[j]);
+ }
+ } else
+ argsList.append(argsList1[i]);
+ }
+ m_argsList.clear();
+ *proc << argsList;
+ }
+ firstOutput = true;
+ firstError = true;
+
+ connect( proc, SIGNAL(receivedStdout( KProcess*,char*,int)), this,
+ SLOT( slotGetScriptOutput(KProcess*,char*,int)));
+ connect( proc, SIGNAL(receivedStderr( KProcess*,char*,int)), this,
+ SLOT( slotGetScriptError(KProcess*,char*,int)));
+ connect( proc, SIGNAL(processExited( KProcess*)), this,
+ SLOT( slotProcessExited(KProcess*)));
+
+
+
+ if (!m_useOutputFile)
+ scriptOutputDest = script.attribute("output","none");
+ else
+ scriptOutputDest = "file";
+ scriptErrorDest = script.attribute("error","none");
+ if (scriptOutputDest == "message")
+ {
+ emit showMessagesView();
+ }
+
+ if (m_useInputFile)
+ {
+ *proc << m_inputFileName;
+ }
+
+ if (proc->start(KProcess::NotifyOnExit, KProcess::All))
+ {
+ emit clearMessages();
+ emit showMessage(i18n("The \"%1\" script started.\n").arg(actionText()), false);
+ if (!m_useInputFile)
+ {
+ if ( inputType == "current" || inputType == "selected" )
+ {
+ proc->writeStdin( buffer.local8Bit(), buffer.length() );
+ }
+ }
+ proc->closeStdin();
+ } else
+ {
+ KMessageBox::error(m_parentMainWindow, i18n("<qt>There was an error running <b>%1</b>.<br>Check that you have the <i>%2</i> executable installed and it is accessible.</qt>").arg(command + " " + args).arg(command), i18n("Script Not Found"));
+ ViewManager::ref()->activeView()->setFocus();
+ if (loopStarted)
+ {
+ qApp->exit_loop();
+ loopStarted = false;
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void TagAction::slotGetScriptOutput( KProcess *, char *buffer, int buflen )
+{
+ QCString tmp( buffer, buflen + 1 );
+ QString text( QString::fromLocal8Bit(tmp) );
+// kdDebug(24000) << "Script output received: |" << text << "|" << endl;
+ Document *w = ViewManager::ref()->activeDocument();
+ if (!w)
+ {
+ kdDebug(24000) << "Document not found." << endl;
+ return;
+ }
+ if ( scriptOutputDest == "cursor" )
+ {
+ w->insertTag( text );
+ } else
+ if ( scriptOutputDest == "selection" )
+ {
+ if ( firstOutput )
+ {
+ int line = dynamic_cast<KTextEditor::SelectionInterfaceExt*>(w->doc())->selEndLine();
+ int col = dynamic_cast<KTextEditor::SelectionInterfaceExt*>(w->doc())->selEndCol();
+ w->viewCursorIf->setCursorPositionReal(line, col);
+ if (w->selectionIf)
+ w->selectionIf->removeSelectedText();
+ }
+ w->insertTag( text );
+ } else
+ if ( scriptOutputDest == "replace" )
+ {
+ if ( firstOutput )
+ w->editIf->clear();
+ w->insertTag( text );
+ } else
+ if ( scriptOutputDest == "new" )
+ {
+ if (firstOutput)
+ {
+ emit createNewFile();
+ w = ViewManager::ref()->activeDocument();
+ }
+ w->insertTag( text );
+ } else
+ if ( scriptOutputDest == "message" )
+ {
+ if ( firstOutput )
+ {
+ emit showMessagesView();
+ emit showMessage(i18n("The \"%1\" script output:\n").arg(actionText()), false);
+ }
+ emit showMessage(text, true);
+ } else
+ if ( scriptOutputDest == "file" && m_file)
+ {
+ if (!m_file->isOpen())
+ m_file->open(IO_ReadWrite);
+ m_file->writeBlock(buffer, buflen);
+ }
+
+ firstOutput = false;
+}
+
+void TagAction::slotGetScriptError( KProcess *, char *buffer, int buflen )
+{
+ Document *w = ViewManager::ref()->activeDocument();
+ QCString tmp( buffer, buflen + 1 );
+ QString text( QString::fromLocal8Bit(tmp) );
+
+ if ( scriptErrorDest == "merge" )
+ {
+ scriptErrorDest = scriptOutputDest;
+ firstError = firstOutput;
+ }
+ if ( scriptErrorDest == "cursor" )
+ w->insertTag( text );
+ else
+ if ( scriptErrorDest == "selection" )
+ {
+ if ( firstError )
+ {
+ int line = dynamic_cast<KTextEditor::SelectionInterfaceExt*>(w->doc())->selEndLine();
+ int col = dynamic_cast<KTextEditor::SelectionInterfaceExt*>(w->doc())->selEndCol();
+ w->viewCursorIf->setCursorPositionReal(line, col);
+ if (w->selectionIf)
+ w->selectionIf->removeSelectedText();
+ }
+ w->insertTag( text );
+ } else
+ if ( scriptErrorDest == "replace" )
+ {
+ if ( firstError )
+ w->editIf->clear();
+ w->insertTag( text );
+ } else
+ if ( scriptErrorDest == "new" )
+ {
+ if (firstError)
+ {
+ emit createNewFile();
+ w = ViewManager::ref()->activeDocument();
+ }
+ w->insertTag( text );
+ } else
+ if ( scriptErrorDest == "message" )
+ {
+ if ( firstError )
+ {
+ emit showMessagesView();
+ emit showMessage(i18n("The \"%1\" script output:\n").arg(actionText()), false);
+ }
+ emit showMessage(text, true);
+ }
+
+ firstError = false;
+}
+
+void TagAction::scriptDone()
+{
+ delete proc;
+ proc = 0;
+}
+
+void TagAction::setOutputFile(QFile* file)
+{
+ m_file = file;
+}
+
+void TagAction::setInputFileName(const QString& fileName)
+{
+ m_inputFileName = fileName;
+}
+
+QString TagAction::actionText()
+{
+ QString t = tag.attribute("text");
+ int pos = t.find('&');
+ if (pos < (int)t.length()-1 && t[pos+1] != '&')
+ return t.remove(pos, 1);
+ else
+ return t;
+}
+
+QString TagAction::XMLTagName() const
+{
+ if(tag.attribute("type","").lower() != "tag")
+ return QString();
+
+ QDomElement otag = (tag.namedItem("tag")).toElement();
+ QDomElement xtag = (tag.namedItem("xtag")).toElement();
+
+ QString attr = otag.text();
+ if ( attr[0] == '<' )
+ attr.remove(0,1);
+ if ( attr.right(1) == ">" )
+ attr.remove( attr.length()-1, 1 );
+ attr = attr.stripWhiteSpace();
+ int i = 0;
+ while ( !attr[i].isSpace() && !attr[i].isNull() )
+ ++i;
+ QString name = attr.left(i);
+
+ return name;
+}
+
+QString TagAction::openXMLTagString() const
+{
+ QString name = XMLTagName();
+
+ QDomElement otag = (tag.namedItem("tag")).toElement();
+ QDomElement xtag = (tag.namedItem("xtag")).toElement();
+
+ QString attr = otag.text();
+ if ( attr[0] == '<' )
+ attr.remove(0,1);
+ if ( attr.right(1) == ">" )
+ attr.remove( attr.length()-1, 1 );
+ attr = attr.stripWhiteSpace();
+ attr.remove(0, name.length());
+
+ QString s1 = QuantaCommon::tagCase(name);
+ if (otag.text().left(1) == "<") s1 = "<"+s1;
+ if (!attr.isEmpty())
+ s1 += " "+QuantaCommon::attrCase(attr);
+ if (otag.text().right(1) == ">")
+ {
+ Document* w = ViewManager::ref()->activeView()->document();
+ QTag *dtdTag = QuantaCommon::tagFromDTD(w->defaultDTD(), name);
+ if ( w->defaultDTD()->singleTagStyle == "xml" && dtdTag &&
+ (dtdTag->isSingle() || (!qConfig.closeOptionalTags && dtdTag->isOptional()))
+ )
+ {
+ s1.append(" /");
+ }
+
+ s1.append(">");
+ }
+
+ return s1;
+}
+
+QString TagAction::closeXMLTagString() const
+{
+ QString s2;
+ QDomElement xtag = (tag.namedItem("xtag")).toElement();
+ if ( xtag.attribute("use","false") == "true" )
+ {
+ if (qConfig.closeTags)
+ s2 = QuantaCommon::tagCase(xtag.text());
+ }
+ return s2;
+}
+
+void TagAction::slotActivated()
+{
+// if(m_toggle)
+ KToggleAction::slotActivated();
+//Andras: Disable toggle behavior. It is just too broken.
+ setChecked(false);
+/*
+ if(!m_toggle)
+ setChecked(!isChecked());
+*/
+}
+
+void TagAction::slotProcessExited(KProcess *process)
+{
+ if (loopStarted)
+ {
+ qApp->exit_loop();
+ loopStarted = false;
+ }
+ emit showMessage(i18n("The \"%1\" script has exited.").arg(actionText()), false);
+ delete process;
+}
+
+void TagAction::addArguments(const QStringList &arguments)
+{
+ m_argsList = arguments;
+}
+
+void TagAction::execute(bool blocking)
+{
+ m_useInputFile = false;
+ m_useOutputFile = false;
+ if (blocking)
+ {
+ m_useInputFile = !m_inputFileName.isEmpty();
+ m_useOutputFile = (m_file);
+ if (slotActionActivated())
+ {
+ //To avoid lock-ups, start a timer.
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), SLOT(slotTimeout()));
+ timer->start(180*1000, true);
+ QExtFileInfo internalFileInfo;
+ loopStarted = true;
+ m_killCount = 0;
+ internalFileInfo.enter_loop();
+ delete timer;
+ m_useInputFile = false;
+ m_useOutputFile = false;
+ }
+ } else
+ slotActionActivated();
+}
+
+/** Timeout occurred while waiting for some network function to return. */
+void TagAction::slotTimeout()
+{
+ if ((m_killCount == 0) && (KMessageBox::questionYesNo(m_parentMainWindow, i18n("<qt>The filtering action <b>%1</b> seems to be locked.<br>Do you want to terminate it?</qt>").arg(actionText()), i18n("Action Not Responding"), i18n("Terminate"), i18n("Keep Running")) == KMessageBox::Yes))
+ {
+ if (::kill(-proc->pid(), SIGTERM))
+ {
+ m_killCount++;
+ return;
+ }
+ }
+ if (m_killCount > 0)
+ {
+ ::kill(-proc->pid(), SIGKILL);
+ if (loopStarted)
+ {
+ qApp->exit_loop();
+ loopStarted = false;
+ }
+ return;
+ }
+ timer->start(180*1000, true);
+}
+
+void TagAction::applyTagInSelection(Node* start_node, int start_offset, Node* end_node, int end_offset,
+ NodeSelection& selection, NodeModifsSet* modifs) const
+{
+ QuantaView *view = ViewManager::ref()->activeView();
+ Document* w = view->document();
+
+ Q_ASSERT(view->hadLastFocus() == QuantaView::VPLFocus);
+ Q_ASSERT(toggable());
+
+ QString tag_name = XMLTagName();
+ Q_ASSERT(kafkaCommon::isInsideTag(start_node, end_node, tag_name) == -1);
+
+ QString open_tag = openXMLTagString();
+
+ //We build the node from the tag name
+ Node* node = kafkaCommon::createNode("", "", Tag::XmlTag, w);
+ node->tag->parse(open_tag, w);
+ node->tag->name = QuantaCommon::tagCase(node->tag->name);
+ node->tag->single = QuantaCommon::isSingleTag(w->defaultDTD()->name,
+ node->tag->name);
+
+ long cursor_offset = selection.cursorOffset();
+
+ Node* nodeCursor = start_node;
+ Node* nodeParent = start_node;
+ if (nodeParent->tag->type == Tag::Text)
+ nodeParent = nodeParent->parent;
+
+ //Checking if at least one parent of node can have a Text Node as child, otherwise
+ //it is impossible for the
+ //user to add this node. In that case, try to insert the Node in the closest parent accepting it.
+ //e.g. TR : a normal insertion would require to have the caret in the TABLE Node, but it is
+ //impossible
+ QTag* nodeQTag = QuantaCommon::tagFromDTD(w->defaultDTD(), node->tag->name);
+ if (!nodeQTag) return;
+
+ bool specialTagInsertion = false;
+ QPtrList<QTag> qTagList = nodeQTag->parents();
+ QTag* qTag = 0;
+ for (qTag = qTagList.first(); qTag; qTag = qTagList.next())
+ {
+ if (qTag->isChild("#text", false))
+ break;
+ if (qTag == qTagList.getLast())
+ specialTagInsertion = true;
+ }
+
+ bool nodeTreeModified = false;
+
+ if (specialTagInsertion) // Attention: not smartTagInsertion
+ {
+ //let's try to insert this node in the closest parent accepting it.
+ while (nodeParent)
+ {
+ QTag* nodeParentQTag = QuantaCommon::tagFromDTD(w->defaultDTD(), nodeParent->tag->name);
+ if (nodeParentQTag && nodeParentQTag->isChild(node))
+ {
+ nodeCursor = kafkaCommon::createMandatoryNodeSubtree(node, w);
+ start_offset = 0;
+ kafkaCommon::insertNodeSubtree(node, nodeParent, 0L, 0L, modifs);
+ nodeTreeModified = true;
+ break;
+ }
+ nodeParent = nodeParent->parent;
+ }
+ }
+ else if(!nodeQTag->isSingle())
+ {
+ //If some text is selected in kafka, surround the selection with the new Node.
+ if(!start_node|| !end_node)
+ return;
+ nodeTreeModified = kafkaCommon::DTDinsertRemoveNode(node, start_node, start_offset,
+ end_node, end_offset, w, &nodeCursor, cursor_offset, modifs);
+ }
+
+// w->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif);
+
+ // FIXME Set the cursor right: the selection can be inverted
+ if(KafkaDocument::ref()->getKafkaWidget()->hasSelection())
+ {
+ nodeCursor = end_node;
+ cursor_offset = end_node->tag->tagStr().length();
+ }
+
+ selection.setCursorNode(nodeCursor);
+ selection.setCursorOffset(cursor_offset);
+
+ //Now update the VPL cursor position
+// KafkaDocument::ref()->getKafkaWidget()->setCurrentNode(nodeCursor, cursor_offset);
+
+ if (!nodeTreeModified)
+ quantaApp->slotStatusMsg(i18n("Cannot insert the tag: invalid location."));
+}
+
+void TagAction::applyTagInMixedSelection(Node* start_node, int start_offset, Node* end_node, int end_offset,
+ NodeSelection& selection, NodeModifsSet* modifs) const
+{
+ Q_ASSERT(start_node != end_node);
+
+ QString const tag_name = XMLTagName();
+
+ // FIXME o pai pode ser do endNode. nao sei se esta merda eh precisa
+/* Node* tag_parent = kafkaCommon::hasParent(start_node, tag_name);
+ Q_ASSERT(tag_parent);*/
+
+ QuantaView *view = ViewManager::ref()->activeView();
+ Document* w = view->document();
+
+ // Set start and end nodes to the correct node
+ start_node = kafkaCommon::getCorrectStartNode(start_node, start_offset);
+ end_node = kafkaCommon::getCorrectEndNode(end_node, end_offset);
+
+ // look for commonParent
+ QValueList<int> commonParentStartChildLocation;
+ QValueList<int> commonParentEndChildLocation;
+
+ Node* commonParent = kafkaCommon::DTDGetCommonParent(start_node, end_node, commonParentStartChildLocation, commonParentEndChildLocation, 0);
+ if(!commonParent) return;
+
+ Node* cursor_node = selection.cursorNode();
+ long cursor_offset = selection.cursorOffset();
+ kafkaCommon::splitStartAndEndNodeSubtree(start_node, start_offset, end_node, end_offset, commonParent,
+ commonParentStartChildLocation, commonParentEndChildLocation,
+ selection, 0, modifs);
+
+ Q_ASSERT(start_node != end_node);
+
+// kafkaCommon::coutTree(baseNode, 3);
+
+ //We build the node from the tag name
+ QString const open_tag_string = openXMLTagString();
+ Node* new_node = kafkaCommon::createNode("", "", Tag::XmlTag, w);
+ new_node->tag->parse(open_tag_string, w);
+ new_node->tag->name = QuantaCommon::tagCase(new_node->tag->name);
+ new_node->tag->single = QuantaCommon::isSingleTag(w->defaultDTD()->name,
+ new_node->tag->name);
+
+ Q_ASSERT(new_node->tag->type == Tag::XmlTag);
+
+ Node* commonParentStartChild = kafkaCommon::getNodeFromLocation(commonParentStartChildLocation, commonParent);
+ Node* commonParentEndChild = kafkaCommon::getNodeFromLocation(commonParentEndChildLocation, commonParent);
+// if(!commonParentStartChild)
+ commonParentStartChild = kafkaCommon::getCommonParentChild(start_node, commonParent);
+/* if(!commonParentEndChild)
+ commonParentEndChild = kafkaCommon::getCommonParentChild(end_node, commonParent);*/
+
+ // insert the node, child of commonParent and commonParentStartChild as nextSibling
+ kafkaCommon::insertNode(new_node, commonParent, commonParentStartChild, commonParentStartChild, modifs);
+
+ // move commonParentStartChild and commonParentEndChild inside new_node
+ kafkaCommon::moveNode(commonParentStartChild, new_node, 0, selection, modifs, true, true);
+ if(commonParentEndChild)
+ kafkaCommon::moveNode(commonParentEndChild, new_node, 0, selection, modifs, true, true);
+
+ // FIXME Set the cursor right: the selection can be inverted
+ if(KafkaDocument::ref()->getKafkaWidget()->hasSelection())
+ {
+ /*Node* */cursor_node = end_node;
+ /*int */cursor_offset = end_node->tag->tagStr().length();
+ selection.setCursorNode(cursor_node);
+ selection.setCursorOffset(cursor_offset);
+ }
+ cursor_node = selection.cursorNode();
+ cursor_offset = selection.cursorOffset();
+
+ Q_ASSERT(new_node->getClosingNode());
+
+ // FIXME remove possible equal tags inside the main surrounding tag
+ kafkaCommon::mergeInlineNode(new_node, new_node->getClosingNode(), &cursor_node, cursor_offset, modifs);
+ selection.setCursorNode(cursor_node);
+ selection.setCursorOffset(cursor_offset);
+
+ //Now update the VPL cursor position
+// KafkaDocument::ref()->getKafkaWidget()->setCurrentNode(cursor_node, cursor_offset);
+}
+
+void TagAction::deapplyTagInSelection(Node* start_node, int start_offset, Node* end_node, int end_offset,
+ NodeSelection& selection, NodeModifsSet* modifs) const
+{
+// QuantaView *view = ViewManager::ref()->activeView();
+// Document* w = view->document();
+
+ QString const tag_name = XMLTagName();
+
+ // Set start and end nodes to the correct node
+ start_node = kafkaCommon::getCorrectStartNode(start_node, start_offset);
+ end_node = kafkaCommon::getCorrectEndNode(end_node, end_offset);
+
+ // look for commonParent
+ QValueList<int> commonParentStartChildLocation;
+ QValueList<int> commonParentEndChildLocation;
+
+ Node* commonParent = kafkaCommon::DTDGetCommonParent(start_node, end_node, commonParentStartChildLocation, commonParentEndChildLocation, 0);
+ if(!commonParent) return;
+
+/* Node* cursor_node = selection.cursorNode();
+ int cursor_offset = selection.cursorOffset();*/
+ kafkaCommon::splitStartAndEndNodeSubtree(start_node, start_offset, end_node, end_offset, commonParent,
+ commonParentStartChildLocation, commonParentEndChildLocation,
+ selection, /*cursor_node, cursor_offset, */0, modifs);
+
+// kafkaCommon::coutTree(baseNode, 3);
+
+ Node* tag_parent = kafkaCommon::hasParent(start_node, end_node, tag_name);
+ Q_ASSERT(tag_parent);
+
+ QString attribute_name(tag.attribute("attribute_name", QString()));
+ QString attribute_value(tag.attribute("attribute_value", QString()));
+
+ if(!attribute_name.isEmpty() && !attribute_value.isEmpty())
+ {
+ kafkaCommon::editNodeAttribute(tag_parent, attribute_name, QString(), modifs);
+ }
+
+ else
+ {
+ Node* common_parent_start_child = kafkaCommon::getCommonParentChild(start_node, tag_parent);
+ Node* common_parent_end_child = kafkaCommon::getCommonParentChild(end_node, tag_parent);
+
+ Node* parent_of_tag_parent = tag_parent->parent;
+ if(common_parent_end_child == common_parent_start_child)
+ common_parent_end_child = 0;
+ if(!common_parent_start_child)
+ common_parent_start_child = kafkaCommon::getCommonParentChild(start_node, commonParent);
+ kafkaCommon::moveNode(common_parent_start_child, parent_of_tag_parent, tag_parent, selection, modifs, true, true);
+
+ if(common_parent_end_child)
+ kafkaCommon::moveNode(common_parent_end_child, parent_of_tag_parent, tag_parent, selection, modifs, true, true);
+
+ // Remove tag_parent node subtree if empty
+ if(!tag_parent->hasChildNodes())
+ kafkaCommon::extractAndDeleteNode(tag_parent, modifs);
+
+ // FIXME Set the cursor right: the selection can be inverted
+ if(KafkaDocument::ref()->getKafkaWidget()->hasSelection())
+ {
+ Node* cursor_node = end_node;
+ int cursor_offset = end_node->tag->tagStr().length();
+ selection.setCursorNode(cursor_node);
+ selection.setCursorOffset(cursor_offset);
+ }
+ //Now update the VPL cursor position
+// KafkaDocument::ref()->getKafkaWidget()->setCurrentNode(cursor_node, cursor_offset);
+ }
+}
+
+// void TagAction::deapplyTagInMixedSelection(Node* start_node, int start_offset, Node* end_node, int end_offset, NodeModifsSet* modifs) const
+// {
+//
+// }
+
+
+#include "tagaction.moc"
+#include "myprocess.moc"
diff --git a/quanta/utility/tagaction.h b/quanta/utility/tagaction.h
new file mode 100644
index 00000000..addb35cf
--- /dev/null
+++ b/quanta/utility/tagaction.h
@@ -0,0 +1,137 @@
+/***************************************************************************
+ tagaction.h - description
+ -------------------
+ begin : ?
+ copyright : (C) ? Dmitry Poplavsky
+ (C) 2002-2005 Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef TAGACTION_H
+#define TAGACTION_H
+
+#include <kdeversion.h>
+#include <kaction.h>
+#include <kactioncollection.h>
+
+#include <qstring.h>
+#include <qdom.h>
+
+class KMainWindow;
+class QuantaView;
+class KProcess;
+class QDomElement;
+class QFile;
+class QTimer;
+class MessageOutput;
+class Node;
+class NodeModifsSet;
+class NodeSelection;
+
+/**
+ * An action for inserting an XML tag.
+ *
+ * @author Dmitry Poplavsky, dima@kde.org
+ * Andras Mantia, amantia@kde.org
+ * Paulo Moura Guedes, moura@kdewebdev.org
+ */
+
+class TagAction : public KToggleAction
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Create an insert from dom element.
+ * @param toggle If set to true, the class behaves like a KToggleAction;
+ * Else it behaves like a KAction. This avoids the multi-inheritance problem.
+ */
+ TagAction(QDomElement *element, KMainWindow *parentMainWindow, bool toggle = false);
+ virtual ~TagAction();
+
+ QDomElement data() const { return tag; }
+ void setModified(bool modified) { m_modified = modified;}
+ bool isModified() const {return m_modified;}
+ void setOutputFile(QFile* file);
+ void setInputFileName(const QString& fileName);
+ void addArguments(const QStringList& arguments);
+ bool toggable() const {return tag.attribute("toggable") == "true";}
+ bool toggled() const {return isChecked();}
+
+ /** Activates the action.
+ @param blocking in case of script actions, the script is run in blocking mode, if this argument is true
+ */
+ void execute(bool blocking);
+ QString type();
+ /**
+ * Remove accelerator from tag action name *
+ */
+ QString actionText();
+
+ QString XMLTagName() const;
+ QString openXMLTagString() const;
+ QString closeXMLTagString() const;
+
+signals:
+ void showMessage(const QString& msg, bool append);
+ void clearMessages();
+ void showMessagesView();
+ void createNewFile();
+
+public slots:
+ virtual void slotActivated();
+
+ /**
+ * We need this information in order to know if queued actions should be applied.
+ * It's public because it can be activated by other classes if there are any queued actions.
+ */
+ virtual bool slotActionActivated(KAction::ActivationReason reason, Qt::ButtonState state);
+
+protected slots:
+ virtual void slotGetScriptOutput( KProcess *, char *buffer, int buflen );
+ virtual void slotGetScriptError( KProcess *, char *buffer, int buflen );
+ virtual void scriptDone();
+ void slotTimeout();
+ void slotProcessExited(KProcess *);
+ virtual bool slotActionActivated();
+
+private:
+ void applyTagInSelection(Node* start_node, int start_offset, Node* end_node, int end_offset,
+ NodeSelection& selection, NodeModifsSet* modifs) const;
+ void applyTagInMixedSelection(Node* start_node, int start_offset, Node* end_node, int end_offset,
+ NodeSelection& selection, NodeModifsSet* modifs) const;
+ void deapplyTagInSelection(Node* start_node, int start_offset, Node* end_node, int end_offset,
+ NodeSelection& selection, NodeModifsSet* modifs) const;
+ void deapplyTagInMixedSelection(Node* start_node, int start_offset, Node* end_node, int end_offset,
+ NodeSelection& selection, NodeModifsSet* modifs) const;
+
+private:
+ KProcess *proc;
+ bool firstError;
+ bool firstOutput;
+ bool m_modified;
+ bool loopStarted;
+ bool m_useInputFile;
+ bool m_useOutputFile;
+ QString scriptOutputDest;
+ QString scriptErrorDest;
+ QTimer* timer;
+ QDomElement tag;
+ QFile* m_file;
+ KMainWindow *m_parentMainWindow;
+ QString m_inputFileName;
+ QStringList m_argsList;
+ uint m_killCount;
+ bool const m_toggle;
+};
+
+
+#endif // TAGACTION_H
diff --git a/quanta/utility/tagactionmanager.cpp b/quanta/utility/tagactionmanager.cpp
new file mode 100644
index 00000000..21183073
--- /dev/null
+++ b/quanta/utility/tagactionmanager.cpp
@@ -0,0 +1,83 @@
+/***************************************************************************
+ tagactionmanager.cpp
+ -------------------
+
+ copyright : (C) 2004 - Paulo Moura Guedes
+ email : moura@kdewebdev.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <kstaticdeleter.h>
+#include <kactioncollection.h>
+#include <kaction.h>
+#include <khtmlview.h>
+#include <klocale.h>
+#include <dom/dom_node.h>
+
+#include <qwidget.h>
+
+#include "tagactionmanager.h"
+#include "tagactionset.h"
+#include "resource.h"
+#include "wkafkapart.h"
+
+
+TagActionManager* TagActionManager::s_mSelf = 0;
+static KStaticDeleter<TagActionManager> staticDeleter;
+
+
+TagActionManager::TagActionManager()
+ : m_actionCollection(0)
+{
+ s_mSelf = this;
+ initActions(KafkaDocument::ref()->getKafkaWidget()->view());
+}
+
+TagActionManager::~TagActionManager()
+{}
+
+TagActionManager* TagActionManager::self()
+{
+ if (!s_mSelf)
+ {
+ staticDeleter.setObject(s_mSelf, new TagActionManager());
+ }
+
+ return s_mSelf;
+}
+
+void TagActionManager::initActions(QWidget* parent)
+{
+ Q_ASSERT(parent);
+
+ m_actionCollection = new KActionCollection(parent);
+
+ TagActionSet* general(new TagActionSet());
+ general->initActions(parent);
+ m_tagActionSets.append(general);
+
+ TableTagActionSet* table(new TableTagActionSet());
+ table->initActions(parent);
+ m_tagActionSets.append(table);
+}
+
+void TagActionManager::fillWithTagActions(QWidget* widget, DOM::Node const& node)
+{
+ TagActionSetAbstract* tagActionSet = 0;
+ for(tagActionSet = m_tagActionSets.first(); tagActionSet; tagActionSet = m_tagActionSets.next())
+ tagActionSet->fillWithTagActions(widget, node);
+}
+
+bool TagActionManager::canIndentDTD(QString const& dtd)
+{
+ return (dtd.contains("HTML", false) ||
+ dtd.contains("XML", false));
+}
diff --git a/quanta/utility/tagactionmanager.h b/quanta/utility/tagactionmanager.h
new file mode 100644
index 00000000..533c3b39
--- /dev/null
+++ b/quanta/utility/tagactionmanager.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+ tagactionmanager.h
+ -------------------
+
+ copyright : (C) 2004 - Paulo Moura Guedes
+ email : moura@kdewebdev.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef TAGACTIONMANAGER_H
+#define TAGACTIONMANAGER_H
+
+class KActionCollection;
+namespace DOM
+{
+class Node;
+}
+
+#include <qptrlist.h>
+class QWidget;
+
+class TagActionSetAbstract;
+class TagActionSet;
+class TableTagActionSet;
+
+
+/**
+ * @author Paulo Moura Guedes
+ * This class is a singleton.
+*/
+class TagActionManager
+{
+public:
+ static TagActionManager* self();
+ ~TagActionManager();
+
+ /**
+ * This method is used to fill context menus with apropriated actions for node.
+ * If you want to plug a single action to some widget use actionCollection().
+ * @param widget The widget in wich the actions will be pluged.
+ * @param node The context/current node.
+ */
+ void fillWithTagActions(QWidget* widget, DOM::Node const& node);
+
+ static bool canIndentDTD(QString const& dtd);
+
+ KActionCollection* actionCollection() const
+ {
+ return m_actionCollection;
+ }
+
+private:
+ TagActionManager();
+ TagActionManager(TagActionManager const&)
+ {}
+
+ void initActions(QWidget* parent);
+
+private:
+ static TagActionManager* s_mSelf;
+
+ KActionCollection* m_actionCollection;
+ QPtrList<TagActionSetAbstract> m_tagActionSets;
+};
+
+#endif
diff --git a/quanta/utility/tagactionset.cpp b/quanta/utility/tagactionset.cpp
new file mode 100644
index 00000000..691ad182
--- /dev/null
+++ b/quanta/utility/tagactionset.cpp
@@ -0,0 +1,1172 @@
+/***************************************************************************
+ tagactionset.cpp
+ -------------------
+
+ copyright : (C) 2004 - Paulo Moura Guedes
+ email : moura@kdewebdev.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kactioncollection.h>
+#include <kactionclasses.h>
+#include <dom/dom_node.h>
+#include <dom/dom_string.h>
+#include <klocale.h>
+
+#include <qwidget.h>
+
+#include "tagactionset.h"
+#include "tagactionmanager.h"
+#include "kafkacommon.h"
+#include "cursors.h"
+#include "undoredo.h"
+#include "wkafkapart.h"
+#include "node.h"
+#include "quantaview.h"
+#include "viewmanager.h"
+#include "tag.h"
+#include "quantacommon.h"
+#include "document.h"
+#include "resource.h"
+
+
+TagActionSetAbstract::TagActionSetAbstract(QObject *parent, const char *name)
+ : QObject(parent, name), m_currentNode(0)
+{}
+
+TagActionSetAbstract::~TagActionSetAbstract()
+{}
+
+Node* TagActionSetAbstract::parentTag(Node* node, QString const& tagName)
+{
+ Q_ASSERT(node);
+
+ Node* aux = node;
+ while(aux && aux->nodeName().lower() != tagName)
+ aux = aux->parent;
+
+ return aux;
+}
+
+Node* TagActionSetAbstract::firstChildTag(Node* startParentNode, QString const& tagName)
+{
+ Node* aux = startParentNode;
+ while(aux && aux->nodeName().lower() != tagName)
+ {
+ aux = aux->nextSibling();
+ if(!startParentNode->hasForChild(aux))
+ return 0;
+ }
+
+ return aux;
+}
+
+bool TagActionSetAbstract::fillWithTagActions(QWidget* /*widget*/, DOM::Node const& node)
+{
+ m_currentDomNode = node;
+ m_currentNode = KafkaDocument::ref()->getNode(m_currentDomNode);
+
+ return m_currentNode;
+}
+
+//_____________________________________________________________________________
+
+TagActionSet::TagActionSet(QObject *parent, const char *name)
+ : TagActionSetAbstract(parent, name), m_separator(0)
+{
+ m_separator = new KActionSeparator();
+}
+
+bool TagActionSet::isInTagContext() const
+{
+ return true;
+}
+
+void TagActionSet::initActionMenus(QWidget* /*widget*/)
+{
+}
+
+void TagActionSet::initActions(QWidget* /*parent*/)
+{
+ KActionCollection* ac(TagActionManager::self()->actionCollection());
+
+ QString actionName = "apply_source_indentation";
+ new KAction(i18n("Apply Source Indentation"), 0, this,
+ SLOT(slotApplySourceIndentation()),
+ ac, actionName);
+
+ actionName = "copy_div_element";
+ new KAction(i18n("Copy DIV Area"), 0, this,
+ SLOT(slotCopyDivElement()),
+ ac, actionName);
+
+ actionName = "cut_div_element";
+ new KAction(i18n("Cut DIV Area"), 0, this,
+ SLOT(slotCutDivElement()),
+ ac, actionName);
+}
+
+bool TagActionSet::fillWithTagActions(QWidget* widget, DOM::Node const& node)
+{
+ bool validNode = TagActionSetAbstract::fillWithTagActions(widget, node);
+
+ if(!validNode || !isInTagContext())
+ {
+ unplugAllActions(widget);
+ return false;
+ }
+
+ m_separator->unplugAll();
+
+ KActionCollection* ac(TagActionManager::self()->actionCollection());
+
+ KAction* copyDivAction = ac->action("copy_div_element");
+ Q_ASSERT(copyDivAction);
+ KAction* cutDivAction = ac->action("cut_div_element");
+ Q_ASSERT(cutDivAction);
+
+ if(/*!KafkaDocument::ref()->getKafkaWidget()->hasSelection() && */isInDivArea())
+ {
+ if(!copyDivAction->isPlugged(widget))
+ copyDivAction->plug(widget);
+
+ if(!cutDivAction->isPlugged(widget))
+ cutDivAction->plug(widget);
+
+ m_separator->plug(widget);
+ }
+ else
+ {
+ copyDivAction->unplug(widget);
+ cutDivAction->unplug(widget);
+ }
+
+// KAction* applySourceIndentationAction = ac->action("apply_source_indentation");
+// Q_ASSERT(applySourceIndentationAction);
+//
+// applySourceIndentationAction->unplug(widget); // to keep things in order
+// applySourceIndentationAction->plug(widget);
+//
+// m_separator->plug(widget);
+
+ return true;
+}
+
+void TagActionSet::unplugAllActions(QWidget* widget) const
+{
+ KActionCollection* ac(TagActionManager::self()->actionCollection());
+
+ m_separator->unplugAll();
+
+ KAction* applySourceIndentationAction = ac->action("apply_source_indentation");
+ Q_ASSERT(applySourceIndentationAction);
+ applySourceIndentationAction->unplug(widget);
+
+ KAction* copyDivAction = ac->action("copy_div_element");
+ Q_ASSERT(copyDivAction);
+ copyDivAction->unplug(widget);
+
+ KAction* cutDivAction = ac->action("cut_div_element");
+ Q_ASSERT(cutDivAction);
+ cutDivAction->unplug(widget);
+}
+
+void TagActionSet::slotApplySourceIndentation()
+{
+ QuantaView* view = ViewManager::ref()->activeView();
+ NodeModifsSet *modifs = new NodeModifsSet();
+
+ KConfig* config = kapp->config();
+ config->setGroup("Kate Document Defaults");
+ int indentationWidth = config->readNumEntry("Indentation Width", 4);
+
+ //Once the changes have been made, we will generate the "clean" string for Text Nodes only, and
+ //we will add the empty indentation Nodes.
+ int eLine, eCol;
+ Node* node = baseNode;
+ while(node)
+ {
+ if(/*!node->tag->cleanStrBuilt() && */node->tag->type == Tag::Text)
+ {
+ if(!node->insideSpecial)
+ {
+ node->tag->setStr(KafkaDocument::ref()->generateCodeFromNode(node, 0, 0, eLine, eCol, false));
+ node->tag->setCleanStrBuilt(true);
+ }
+ }
+ if(/*!node->tag->indentationDone() && */!node->insideSpecial)
+ {
+ kafkaCommon::fitIndentationNodes(kafkaCommon::getPrevNodeNE(node), node, modifs);
+ bool goUp = false;
+ kafkaCommon::fitIndentationNodes(node, kafkaCommon::getNextNodeNE(node, goUp), modifs);
+ kafkaCommon::applyIndentation(node, indentationWidth, 0, modifs, qConfig.inlineNodeIndentation);
+ }
+ node = node->nextSibling();
+ }
+
+ view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif);
+}
+
+bool TagActionSet::isInDivArea() const
+{
+ Q_ASSERT(m_currentNode);
+
+ return parentTag(m_currentNode, "div");
+}
+
+void TagActionSet::slotCopyDivElement()
+{
+ Q_ASSERT(m_currentNode);
+
+ Node* divNode = parentTag(m_currentNode, "div");
+ Q_ASSERT(divNode);
+
+ Node* divClosingNode = divNode->getClosingNode();
+ if(!divClosingNode)
+ {
+ kdError(25001) << "DIV element without closing node: " << divNode << endl;
+ return;
+ }
+
+ KafkaDocument::ref()->slotCopy(divNode, 0, divClosingNode, 0, QString());
+}
+
+void TagActionSet::slotCutDivElement()
+{
+ Q_ASSERT(m_currentNode);
+
+ Node* divNode = parentTag(m_currentNode, "div");
+ Q_ASSERT(divNode);
+
+ Node* divClosingNode = divNode->getClosingNode();
+ if(!divClosingNode)
+ {
+ kdError(25001) << "DIV element without closing node: " << divNode << endl;
+ return;
+ }
+
+ NodeSelectionInd selection_ind;
+ selection_ind.fillWithVPLCursorSelection();
+
+ int cursorOffset = selection_ind.cursorOffset();
+
+ KafkaDocument::ref()->slotCut(divNode, 0, divClosingNode, 0, &m_currentNode, cursorOffset, QString());
+
+}
+
+//_____________________________________________________________________________
+
+TableTagActionSet::TableTagActionSet(QObject *parent, const char *name)
+ : TagActionSetAbstract(parent, name), m_separator(0), m_tableActionMenu_0(0), m_insertActionMenu_1(0)
+{
+ m_separator = new KActionSeparator();
+}
+
+bool TableTagActionSet::isInTagContext() const
+{
+ return parentTag(m_currentNode, "table");
+}
+
+void TableTagActionSet::initActionMenus(QWidget* widget)
+{
+ Q_ASSERT(!m_tableActionMenu_0);
+
+ m_tableActionMenu_0 = new KActionMenu(i18n("Table..."), widget);
+ m_insertActionMenu_1 = new KActionMenu(i18n("Insert..."), m_tableActionMenu_0);
+ m_removeActionMenu_1 = new KActionMenu(i18n("Remove..."), m_tableActionMenu_0);
+}
+
+
+void TableTagActionSet::initActions(QWidget* parent)
+{
+ if(!m_tableActionMenu_0)
+ initActionMenus(parent);
+
+ KActionCollection* ac(TagActionManager::self()->actionCollection());
+
+ // Insert___________________________________________________________________________
+
+ QString actionName = "insert_table";
+ //m_actionNames += actionName;
+ new KAction(i18n("Table..."), 0, this,
+ SLOT(slotInsertTable()),
+ ac, actionName);
+
+ actionName = "insert_row_above";
+ //m_actionNames += actionName;
+ new KAction(i18n("Row Above"), 0, this,
+ SLOT(slotInsertRowAbove()),
+ ac, actionName);
+
+ actionName = "insert_row_below";
+ //m_actionNames += actionName;
+ new KAction(i18n("Row Below"), 0, this,
+ SLOT(slotInsertRowBelow()),
+ ac, actionName);
+
+ actionName = "insert_column_left";
+ //m_actionNames += actionName;
+ new KAction(i18n("Column Left"), 0, this,
+ SLOT(slotInsertColumnLeft()),
+ ac, actionName);
+
+ actionName = "insert_column_right";
+ //m_actionNames += actionName;
+ new KAction(i18n("Column Right"), 0, this,
+ SLOT(slotInsertColumnRight()),
+ ac, actionName);
+
+ // Remove___________________________________________________________________________
+
+ actionName = "remove_table";
+ //m_actionNames += actionName;
+ new KAction(i18n("Table"), 0, this,
+ SLOT(slotRemoveTable()),
+ ac, actionName);
+
+ actionName = "remove_rows";
+ //m_actionNames += actionName;
+ new KAction(i18n("Row(s)"), 0, this,
+ SLOT(slotRemoveRows()),
+ ac, actionName);
+
+ actionName = "remove_columns";
+ //m_actionNames += actionName;
+ new KAction(i18n("Column(s)"), 0, this,
+ SLOT(slotRemoveColumns()),
+ ac, actionName);
+
+ actionName = "remove_cells";
+ //m_actionNames += actionName;
+ new KAction(i18n("Cell(s)"), 0, this,
+ SLOT(slotRemoveCells()),
+ ac, actionName);
+
+ actionName = "remove_cells_content";
+ //m_actionNames += actionName;
+ new KAction(i18n("Cell(s) Content"), 0, this,
+ SLOT(slotRemoveCellsContent()),
+ ac, actionName);
+
+ // Merge___________________________________________________________________________
+
+ actionName = "merge_selected_cells";
+ //m_actionNames += actionName;
+ new KAction(i18n("Merge Selected Cells"), 0, this,
+ SLOT(slotMergeSelectedCells()),
+ ac, actionName);
+}
+
+bool TableTagActionSet::fillWithTagActions(QWidget* widget, DOM::Node const& node)
+{
+ bool validNode = TagActionSetAbstract::fillWithTagActions(widget, node);
+
+ if(!validNode || !isInTagContext(/*node*/))
+ {
+ unplugAllActions(widget);
+ return false;
+ }
+
+ m_separator->unplugAll();
+
+ KActionCollection* ac(TagActionManager::self()->actionCollection());
+
+ // Table
+ bool emptyTableActionMenu_0 = true;
+
+ // Insert _____________________________________________________________________
+
+ // Insert
+ bool emptyInsertActionMenu_1 = true;
+
+ // Insert Table
+ KAction* insertTableAction = ac->action("insert_table");
+ Q_ASSERT(insertTableAction);
+
+ m_insertActionMenu_1->remove(insertTableAction);
+ if(canInsertTable())
+ {
+ emptyTableActionMenu_0 = emptyInsertActionMenu_1 = false;
+ m_insertActionMenu_1->insert(insertTableAction);
+
+ m_insertActionMenu_1->insert(m_separator);
+ }
+ // Insert Row Above
+ KAction* insertRowAboveAction = ac->action("insert_row_above");
+ Q_ASSERT(insertRowAboveAction);
+
+ m_insertActionMenu_1->remove(insertRowAboveAction);
+ if(canInsertRowAbove())
+ {
+ emptyTableActionMenu_0 = emptyInsertActionMenu_1 = false;
+ m_insertActionMenu_1->insert(insertRowAboveAction);
+
+ //m_insertActionMenu_1->insert(m_separator);
+ }
+ // Insert Row Below
+ KAction* insertRowBelowAction = ac->action("insert_row_below");
+ Q_ASSERT(insertRowBelowAction);
+
+ m_insertActionMenu_1->remove(insertRowBelowAction);
+ if(canInsertRowBelow())
+ {
+ emptyTableActionMenu_0 = emptyInsertActionMenu_1 = false;
+ m_insertActionMenu_1->insert(insertRowBelowAction);
+
+ m_insertActionMenu_1->insert(m_separator);
+ }
+ // Insert Column Left
+ KAction* insertColumnLeftAction = ac->action("insert_column_left");
+ Q_ASSERT(insertColumnLeftAction);
+
+ m_insertActionMenu_1->remove(insertColumnLeftAction);
+ if(canInsertColumnLeft())
+ {
+ emptyTableActionMenu_0 = emptyInsertActionMenu_1 = false;
+ m_insertActionMenu_1->insert(insertColumnLeftAction);
+
+ //m_insertActionMenu_1->insert(m_separator);
+ }
+ // Insert Column Right
+ KAction* insertColumnRightAction = ac->action("insert_column_right");
+ Q_ASSERT(insertColumnRightAction);
+
+ m_insertActionMenu_1->remove(insertColumnRightAction);
+ if(canInsertColumnRight())
+ {
+ emptyTableActionMenu_0 = emptyInsertActionMenu_1 = false;
+ m_insertActionMenu_1->insert(insertColumnRightAction);
+
+ m_insertActionMenu_1->insert(m_separator);
+ }
+ // Remove _____________________________________________________________________
+
+ // Remove
+ bool emptyRemoveActionMenu_1 = true;
+
+ // Remove Table
+ KAction* removeTableAction = ac->action("remove_table");
+ Q_ASSERT(removeTableAction);
+
+ m_removeActionMenu_1->remove(removeTableAction);
+ if(canRemoveTable())
+ {
+ emptyTableActionMenu_0 = emptyRemoveActionMenu_1 = false;
+ m_removeActionMenu_1->insert(removeTableAction);
+
+ m_removeActionMenu_1->insert(m_separator);
+ }
+ // Remove Row(s)
+ KAction* removeRowsAction = ac->action("remove_rows");
+ Q_ASSERT(removeRowsAction);
+
+ m_removeActionMenu_1->remove(removeRowsAction);
+ if(canRemoveRows())
+ {
+ emptyTableActionMenu_0 = emptyRemoveActionMenu_1 = false;
+ m_removeActionMenu_1->insert(removeRowsAction);
+
+ //m_removeActionMenu_1->insert(m_separator);
+ }
+ // Remove Column(s)
+ KAction* removeColumnsAction = ac->action("remove_columns");
+ Q_ASSERT(removeColumnsAction);
+
+ m_removeActionMenu_1->remove(removeColumnsAction);
+ if(canRemoveColumns())
+ {
+ emptyTableActionMenu_0 = emptyRemoveActionMenu_1 = false;
+ m_removeActionMenu_1->insert(removeColumnsAction);
+
+ //m_removeActionMenu_1->insert(m_separator);
+ }
+/* // Remove Cell(s)
+ KAction* removeCellsAction = ac->action("remove_cells");
+ Q_ASSERT(removeCellsAction);
+
+ m_removeActionMenu_1->remove(removeCellsAction);
+ if(canRemoveCells())
+ {
+ emptyTableActionMenu_0 = emptyRemoveActionMenu_1 = false;
+ m_removeActionMenu_1->insert(removeCellsAction);
+
+ //m_removeActionMenu_1->insert(m_separator);
+ }*/
+ // Remove Cell(s) Content
+ KAction* removeCellsContentAction = ac->action("remove_cells_content");
+ Q_ASSERT(removeCellsContentAction);
+
+ m_removeActionMenu_1->remove(removeCellsContentAction);
+ if(canRemoveCellsContent())
+ {
+ emptyTableActionMenu_0 = emptyRemoveActionMenu_1 = false;
+ m_removeActionMenu_1->insert(removeCellsContentAction);
+
+ //m_removeActionMenu_1->insert(m_separator);
+ }
+ // Remove _____________________________________________________________________
+
+ // Merge
+// bool emptyRemoveActionMenu_1 = true;
+
+ // _____________________________________________________________________________
+
+ // Table
+ m_tableActionMenu_0->unplug(widget);
+ if(!emptyTableActionMenu_0)
+ {
+ m_tableActionMenu_0->plug(widget);
+
+ m_tableActionMenu_0->remove(m_insertActionMenu_1);
+ if(!emptyInsertActionMenu_1)
+ m_tableActionMenu_0->insert(m_insertActionMenu_1);
+
+ m_tableActionMenu_0->remove(m_removeActionMenu_1);
+ if(!emptyRemoveActionMenu_1)
+ m_tableActionMenu_0->insert(m_removeActionMenu_1);
+
+ m_tableActionMenu_0->insert(m_separator);
+ }
+ // Merge selected cells
+ KAction* mergeSelectedCellsAction = ac->action("merge_selected_cells");
+ Q_ASSERT(mergeSelectedCellsAction);
+
+ m_tableActionMenu_0->remove(mergeSelectedCellsAction);
+ if(canMergeSelectedCells())
+ {
+ emptyTableActionMenu_0 = false;
+ m_tableActionMenu_0->insert(mergeSelectedCellsAction);
+
+// m_removeActionMenu_1->insert(m_separator);
+ }
+
+ return true;
+}
+
+void TableTagActionSet::unplugAllActions(QWidget* widget) const
+{
+ m_separator->unplugAll();
+ m_tableActionMenu_0->unplug(widget);
+}
+
+// Insert _____________________________________________________________________
+
+bool TableTagActionSet::canInsertTable() const
+{
+ return false;
+ // return isInTagContext(currentDomNode()); // TODO Implement slotInsertTable
+}
+
+void TableTagActionSet::slotInsertTable()
+{
+ Q_ASSERT(m_currentNode);
+
+}
+
+bool TableTagActionSet::canInsertRowAbove() const
+{
+ return isInTagContext() && parentTag(m_currentNode, "tbody");
+}
+
+void TableTagActionSet::slotInsertRowAbove()
+{
+ Q_ASSERT(m_currentNode);
+
+ Node* nearRow = parentTag(m_currentNode, "tr");
+
+ if(!nearRow)
+ return;
+
+ Node* nodeParent= nearRow->parent;
+
+ QuantaView* view = ViewManager::ref()->activeView();
+ NodeModifsSet *modifs = new NodeModifsSet();
+ Node* nodeToInsert = buildEmptyRowSubtree();
+
+ kafkaCommon::insertNodeSubtree(nodeToInsert, nodeParent, nearRow, modifs);
+
+ view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif);
+
+// kafkaCommon::coutTree(baseNode, 3);
+}
+
+bool TableTagActionSet::canInsertRowBelow() const
+{
+ return isInTagContext();
+}
+
+void TableTagActionSet::slotInsertRowBelow()
+{
+ Q_ASSERT(m_currentNode);
+
+ Node* nearRow = 0;
+ Node* aux = parentTag(m_currentNode, "thead");
+ if(aux)
+ nearRow= firstChildTag(tableStart(), "tr");
+ else
+ nearRow = parentTag(m_currentNode, "tr");
+
+ if(!nearRow)
+ return;
+
+ Node* nodeParent= nearRow->parent;
+ Node* nextSibling = nearRow->SNext();
+
+ QuantaView* view = ViewManager::ref()->activeView();
+ NodeModifsSet *modifs = new NodeModifsSet();
+ Node* nodeToInsert = buildEmptyRowSubtree();
+
+ kafkaCommon::insertNodeSubtree(nodeToInsert, nodeParent, nextSibling, modifs);
+
+ view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif);
+
+// kafkaCommon::coutTree(baseNode, 3);
+}
+
+bool TableTagActionSet::canInsertColumnLeft() const
+{
+ return isInTagContext();
+}
+
+void TableTagActionSet::slotInsertColumnLeft()
+{
+ Q_ASSERT(m_currentNode);
+
+ QuantaView* view = ViewManager::ref()->activeView();
+ NodeModifsSet *modifs = new NodeModifsSet();
+
+ Node* nodeToInsertInBody = buildEmptyTBodyCellSubtree();
+ Node* nodeToInsertInHead = buildEmptyTHeadCellSubtree();
+ Q_ASSERT(nodeToInsertInBody);
+ Q_ASSERT(nodeToInsertInHead);
+
+ int const _currentColumnIndex = currentColumnIndex();
+
+ // thead
+ Node* trChild = firstChildTag(firstChildTag(tableStart(), "thead"), "tr");
+ while(trChild)
+ {
+ Node* thChild = firstChildTag(trChild, "th");
+ for(int i = 0; (i != _currentColumnIndex && thChild); ++i)
+ thChild = thChild->SNext();
+
+ kafkaCommon::insertNodeSubtree(nodeToInsertInHead, trChild, thChild, modifs);
+
+ nodeToInsertInHead = kafkaCommon::duplicateNodeSubtree(nodeToInsertInHead);
+
+ trChild = trChild->SNext();
+ }
+
+ // tbody
+ trChild = firstChildTag(firstChildTag(tableStart(), "tbody"), "tr");
+ while(trChild)
+ {
+ Node* tdChild = firstChildTag(trChild, "td");
+ for(int i = 0; (i != _currentColumnIndex && tdChild); ++i)
+ tdChild = tdChild->SNext();
+
+ kafkaCommon::insertNodeSubtree(nodeToInsertInBody, trChild, tdChild, modifs);
+
+ nodeToInsertInBody = kafkaCommon::duplicateNodeSubtree(nodeToInsertInBody);
+
+ trChild = trChild->SNext();
+ }
+
+ view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif);
+
+// kafkaCommon::coutTree(baseNode, 3);
+}
+
+bool TableTagActionSet::canInsertColumnRight() const
+{
+ return isInTagContext();
+}
+
+void TableTagActionSet::slotInsertColumnRight()
+{
+ Q_ASSERT(m_currentNode);
+
+ QuantaView* view = ViewManager::ref()->activeView();
+ NodeModifsSet *modifs = new NodeModifsSet();
+
+ Node* nodeToInsertInBody = buildEmptyTBodyCellSubtree();
+ Node* nodeToInsertInHead = buildEmptyTHeadCellSubtree();
+ Q_ASSERT(nodeToInsertInBody);
+ Q_ASSERT(nodeToInsertInHead);
+
+ int const _currentColumnIndex = currentColumnIndex();
+
+ // thead
+ Node* trChild = firstChildTag(firstChildTag(tableStart(), "thead"), "tr");
+ while(trChild)
+ {
+ Node* thChild = firstChildTag(trChild, "th");
+ for(int i = 0; (i != _currentColumnIndex + 1 && thChild); ++i)
+ thChild = thChild->SNext();
+
+ kafkaCommon::insertNodeSubtree(nodeToInsertInHead, trChild, thChild, modifs);
+
+ nodeToInsertInHead = kafkaCommon::duplicateNodeSubtree(nodeToInsertInHead);
+
+ trChild = trChild->SNext();
+ }
+
+ // tbody
+ trChild = firstChildTag(firstChildTag(tableStart(), "tbody"), "tr");
+ while(trChild)
+ {
+ Node* tdChild = firstChildTag(trChild, "td");
+ for(int i = 0; (i != _currentColumnIndex + 1 && tdChild); ++i)
+ tdChild = tdChild->SNext();
+
+ kafkaCommon::insertNodeSubtree(nodeToInsertInBody, trChild, tdChild, modifs);
+
+ nodeToInsertInBody = kafkaCommon::duplicateNodeSubtree(nodeToInsertInBody);
+
+ trChild = trChild->SNext();
+ }
+
+ view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif);
+
+// kafkaCommon::coutTree(baseNode, 3);
+}
+
+// Remove ________________________________________________________________
+
+bool TableTagActionSet::canRemoveTable() const
+{
+ return isInTagContext();
+}
+
+void TableTagActionSet::slotRemoveTable()
+{
+ Q_ASSERT(m_currentNode);
+
+ QuantaView* view = ViewManager::ref()->activeView();
+ NodeModifsSet *modifs = new NodeModifsSet();
+
+ Node* _tableStart = tableStart();
+
+ kafkaCommon::extractAndDeleteNode(_tableStart, modifs, true, true);
+
+ view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif);
+
+// kafkaCommon::coutTree(baseNode, 3);
+}
+
+bool TableTagActionSet::canRemoveRows() const
+{
+ return isInTagContext();
+}
+
+void TableTagActionSet::slotRemoveRows()
+{
+ Q_ASSERT(m_currentNode);
+
+ QuantaView* view = ViewManager::ref()->activeView();
+ NodeModifsSet *modifs = new NodeModifsSet();
+
+ NodeSelectionInd selection;
+ selection.fillWithVPLCursorSelection();
+
+ if(!selection.hasSelection())
+ {
+ Node* nearTr = parentTag(m_currentNode, "tr");
+ kafkaCommon::extractAndDeleteNode(nearTr, modifs, true, true);
+ }
+ else
+ {
+ Node* startSelection = kafkaCommon::getNodeFromLocation(selection.cursorNode());
+ Node* endSelection = kafkaCommon::getNodeFromLocation(selection.cursorNodeEndSel());
+
+ Node* startTr = parentTag(startSelection, "tr");
+ Node* endTr = parentTag(endSelection, "tr");
+
+ Node* iteratorNode = startTr;
+ bool loop(true);
+ while(iteratorNode && loop)
+ {
+ // the check has to be done before extract
+ if(iteratorNode == endTr)
+ loop = false;
+
+ Node* aux = iteratorNode;
+ iteratorNode = iteratorNode->SNext();
+
+ kafkaCommon::extractAndDeleteNode(aux, modifs, true, true);
+ }
+ }
+
+ view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif);
+
+// kafkaCommon::coutTree(baseNode, 3);
+}
+
+bool TableTagActionSet::canRemoveColumns() const
+{
+ return isInTagContext();
+}
+
+void TableTagActionSet::slotRemoveColumns()
+{
+ Q_ASSERT(m_currentNode);
+
+ QuantaView* view = ViewManager::ref()->activeView();
+ NodeModifsSet *modifs = new NodeModifsSet();
+
+ NodeSelectionInd selection;
+ selection.fillWithVPLCursorSelection();
+
+ if(!selection.hasSelection())
+ {
+ int const _currentColumnIndex = currentColumnIndex();
+ removeColumn(_currentColumnIndex, modifs);
+ }
+ else
+ {
+ Node* startSelection = kafkaCommon::getNodeFromLocation(selection.cursorNode());
+ Node* endSelection = kafkaCommon::getNodeFromLocation(selection.cursorNodeEndSel());
+
+ int startColumnIndex = columnIndex(startSelection);
+ int endColumnIndex = columnIndex(endSelection);
+ int numberOfColumnsSelected = endColumnIndex - startColumnIndex + 1;
+
+ if(startColumnIndex == -1 || endColumnIndex == -1)
+ return;
+
+ m_currentNode = parentTag(m_currentNode, "tbody"); // m_currentNode will become invalid
+ for(int i = 0; i != numberOfColumnsSelected; ++i)
+ removeColumn(startColumnIndex, modifs);
+ }
+
+ view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif);
+
+// kafkaCommon::coutTree(baseNode, 3);
+}
+
+bool TableTagActionSet::canRemoveCells() const
+{
+ return isInTagContext();
+}
+
+void TableTagActionSet::slotRemoveCells()
+{}
+
+bool TableTagActionSet::canRemoveCellsContent() const
+{
+ return isInTagContext();
+}
+
+void TableTagActionSet::slotRemoveCellsContent()
+{
+ Q_ASSERT(m_currentNode);
+
+ QuantaView* view = ViewManager::ref()->activeView();
+ NodeModifsSet *modifs = new NodeModifsSet();
+
+ NodeSelectionInd selection;
+ selection.fillWithVPLCursorSelection();
+
+ if(!selection.hasSelection())
+ {
+ Node* aux = m_currentNode;
+ m_currentNode = parentTag(m_currentNode, "tbody");
+
+ Node* nearTd = parentTag(aux, "td");
+ clearCellContents(nearTd, modifs);
+ }
+ else
+ {
+ Node* startSelection = kafkaCommon::getNodeFromLocation(selection.cursorNode());
+ Node* endSelection = kafkaCommon::getNodeFromLocation(selection.cursorNodeEndSel());
+
+ Node* startTd = parentTag(startSelection, "td");
+ Node* endTd = parentTag(endSelection, "td");
+
+ if(!startTd || !endTd)
+ return;
+
+ }
+
+ view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif);
+
+// kafkaCommon::coutTree(baseNode, 3);
+}
+
+// Merge ________________________________________________________________
+
+bool TableTagActionSet::canMergeSelectedCells() const
+{
+ if(!KafkaDocument::ref()->getKafkaWidget()->hasSelection())
+ return false;
+
+ NodeSelectionInd selection;
+ selection.fillWithVPLCursorSelection();
+ QValueList<int> start = selection.cursorNode();
+ QValueList<int> end = selection.cursorNodeEndSel();
+
+ return start != end;
+}
+
+void TableTagActionSet::slotMergeSelectedCells()
+{
+ Q_ASSERT(m_currentNode);
+
+ QuantaView* view = ViewManager::ref()->activeView();
+ NodeModifsSet *modifs = new NodeModifsSet();
+
+ NodeSelectionInd selection;
+ selection.fillWithVPLCursorSelection();
+
+ Q_ASSERT(selection.hasSelection());
+
+ Node* startSelection = kafkaCommon::getNodeFromLocation(selection.cursorNode());
+ Node* endSelection = kafkaCommon::getNodeFromLocation(selection.cursorNodeEndSel());
+
+ Node* startTd = parentTag(startSelection, "td");
+ Node* endTd = parentTag(endSelection, "td");
+
+ Node* nodeIterator = startTd->SNext();
+ Node* stopNode = endTd->SNext();
+ int count = 1;
+ while(nodeIterator && nodeIterator != stopNode)
+ {
+ Node* aux = nodeIterator;
+ nodeIterator = nodeIterator->SNext();
+
+ Node* child = aux->firstChild();
+ while(child)
+ {
+ Node* next = child->next;
+ kafkaCommon::moveNode(child, startTd, 0, modifs);
+ child = next;
+ }
+
+ kafkaCommon::extractAndDeleteNode(aux, modifs);
+
+ ++count;
+ }
+
+ if(count == 1)
+ return;
+
+ kafkaCommon::editNodeAttribute(startTd, "colspan", QString::number(count), modifs);
+ kafkaCommon::editNodeAttribute(startTd, "rowspan", "1", modifs);
+
+ view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif);
+
+// kafkaCommon::coutTree(baseNode, 3);
+}
+
+//_____________________________________________________________________________
+
+Node* TableTagActionSet::tableStart() const
+{
+ Q_ASSERT(isInTagContext());
+ Q_ASSERT(m_currentNode);
+
+ return parentTag(m_currentNode, "table");
+}
+
+int TableTagActionSet::numberOfColumns() const
+{
+ Node* _tableStart = tableStart();
+ if(!_tableStart)
+ return -1;
+
+ Node* firstTd = firstChildTag(_tableStart, "td");
+
+ if(!firstTd)
+ return -1;
+
+ int count(0);
+ Node* aux = firstTd;
+ while(aux)
+ {
+ ++count;
+ aux = aux->SNext();
+ }
+
+ kdDebug(23100) << "Number of columns: " << count << endl;
+ return count;
+}
+
+int TableTagActionSet::currentColumnIndex() const
+{
+ return columnIndex(m_currentNode);
+/* Node* nearTd = parentTag(m_currentNode, "td");
+ if(!nearTd)
+ return -1;
+
+ Node* _tableStart = tableStart();
+ if(!_tableStart)
+ return -1;
+
+ Node* firstTd = firstChildTag(parentTag(m_currentNode, "tr"), "td");
+ //Node* firstTd = firstChildTag(_tableStart, "td");
+ if(!firstTd)
+ return -1;
+
+ int count(0);
+ Node* aux = firstTd;
+ while(aux && aux != nearTd)
+ {
+ ++count;
+ aux = aux->SNext();
+ }
+
+ if(!aux)
+ count = -1;
+ return count;*/
+}
+
+int TableTagActionSet::columnIndex(Node* node) const
+{
+ Node* nearTd = parentTag(node, "td");
+ if(!nearTd)
+ return -1;
+
+ Node* _tableStart = tableStart();
+ if(!_tableStart)
+ return -1;
+
+ Node* firstTd = firstChildTag(parentTag(node, "tr"), "td");
+ if(!firstTd)
+ return -1;
+
+ int count(0);
+ Node* aux = firstTd;
+ while(aux && aux != nearTd)
+ {
+ ++count;
+ aux = aux->SNext();
+ }
+
+ if(!aux)
+ count = -1;
+ return count;
+}
+
+Node* TableTagActionSet::buildEmptyRowSubtree() const
+{
+ QuantaView* view = ViewManager::ref()->activeView();
+
+ Node* nodeToInsert = kafkaCommon::createNode("", "", Tag::XmlTag, view->document());
+ nodeToInsert->tag->parse("<tr>", view->document());
+ kafkaCommon::createMandatoryNodeSubtree(nodeToInsert, view->document());
+ // now we have: <tr><td></td></tr>
+
+ //Let's -> <tr><td><br></td></tr>
+ Node* brNode = kafkaCommon::createNode("", "", Tag::XmlTag, view->document());
+ brNode->tag->parse("<br>", view->document());
+ Node* tdNode = nodeToInsert->child;
+ kafkaCommon::insertNode(brNode, tdNode, 0, 0);
+
+ int _numberOfColumns = numberOfColumns();
+
+ if(_numberOfColumns == -1)
+ return 0;
+
+ for(int i = 1; i != _numberOfColumns; ++i)
+ {
+ Node* duplicatedTdSubtree = kafkaCommon::duplicateNodeSubtree(tdNode);
+ kafkaCommon::insertNodeSubtree(duplicatedTdSubtree, nodeToInsert, 0, 0);
+ }
+
+ kafkaCommon::coutTree(nodeToInsert, 3);
+
+ return nodeToInsert;
+}
+
+Node* TableTagActionSet::buildEmptyTBodyCellSubtree() const
+{
+ QuantaView* view = ViewManager::ref()->activeView();
+
+ // build tree -> <td><br></td>
+ Node* nodeToInsert = kafkaCommon::createNode("", "", Tag::XmlTag, view->document());
+ nodeToInsert->tag->parse("<td>", view->document());
+ Node* brNode = kafkaCommon::createNode("", "", Tag::XmlTag, view->document());
+ brNode->tag->parse("<br>", view->document());
+ kafkaCommon::insertNode(brNode, nodeToInsert, 0, 0);
+
+ return nodeToInsert;
+}
+
+Node* TableTagActionSet::buildEmptyTHeadCellSubtree() const
+{
+ QuantaView* view = ViewManager::ref()->activeView();
+
+ // build tree -> <td><br></td>
+ Node* nodeToInsert = kafkaCommon::createNode("", "", Tag::XmlTag, view->document());
+ nodeToInsert->tag->parse("<th>", view->document());
+ Node* brNode = kafkaCommon::createNode("", "", Tag::XmlTag, view->document());
+ brNode->tag->parse("<br>", view->document());
+ kafkaCommon::insertNode(brNode, nodeToInsert, 0, 0);
+
+ return nodeToInsert;
+}
+
+void TableTagActionSet::removeColumn(int _currentColumnIndex, NodeModifsSet* modifs)
+{
+ Q_ASSERT(m_currentNode);
+ Q_ASSERT(_currentColumnIndex >= 0);
+ Q_ASSERT(modifs);
+
+ // thead
+ Node* trChild = firstChildTag(firstChildTag(tableStart(), "thead"), "tr");
+ while(trChild)
+ {
+ Node* thChild = firstChildTag(trChild, "th");
+ for(int i = 0; (i != _currentColumnIndex && thChild); ++i)
+ thChild = thChild->SNext();
+
+ kafkaCommon::extractAndDeleteNode(thChild, modifs, true, true);
+
+ trChild = trChild->SNext();
+ }
+
+ // tbody
+ trChild = firstChildTag(firstChildTag(tableStart(), "tbody"), "tr");
+ while(trChild)
+ {
+ Node* tdChild = firstChildTag(trChild, "td");
+ for(int i = 0; (i != _currentColumnIndex && tdChild); ++i)
+ tdChild = tdChild->SNext();
+
+ kafkaCommon::extractAndDeleteNode(tdChild, modifs, true, true);
+
+ trChild = trChild->SNext();
+ }
+}
+
+void TableTagActionSet::clearCellContents(Node* tdNode, NodeModifsSet* modifs)
+{
+ if (!tdNode)
+ return;
+ Node* tdChild = tdNode->child;
+
+ if(!tdChild)
+ return;
+
+ while(tdChild)
+ {
+ Node* aux = tdChild;
+ tdChild = tdChild->next;
+
+ kafkaCommon::extractAndDeleteNode(aux, modifs, true, false);
+ }
+}
+
+//_____________________________________________________________________________
+
+#include "tagactionset.moc"
diff --git a/quanta/utility/tagactionset.h b/quanta/utility/tagactionset.h
new file mode 100644
index 00000000..6bb2448f
--- /dev/null
+++ b/quanta/utility/tagactionset.h
@@ -0,0 +1,161 @@
+/***************************************************************************
+ tagactionset.h
+ -------------------
+
+ copyright : (C) 2004 - Paulo Moura Guedes
+ email : moura@kdewebdev.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef TAGACTIONSET_H
+#define TAGACTIONSET_H
+
+namespace DOM
+{
+class Node;
+}
+class KActionSeparator;
+
+#include <qobject.h>
+class QWidget;
+class KActionSet;
+class KActionMenu;
+
+class Node;
+class NodeModifsSet;
+
+/**
+@author Paulo Moura Guedes
+*/
+class TagActionSetAbstract : public QObject
+{
+ Q_OBJECT
+public:
+ TagActionSetAbstract(QObject *parent = 0, const char *name = 0);
+ virtual ~TagActionSetAbstract();
+
+ DOM::Node const& currentDomNode() const {return m_currentDomNode;}
+
+ static Node* parentTag(Node* node, QString const& tagName);
+ static Node* firstChildTag(Node* node, QString const& tagName);
+
+ virtual bool isInTagContext(/*DOM::Node const& node*/) const = 0;
+ virtual void initActions(QWidget* parent) = 0;
+ virtual bool fillWithTagActions(QWidget* widget, DOM::Node const& node);
+ virtual void unplugAllActions(QWidget* widget) const = 0;
+
+protected:
+ virtual void initActionMenus(QWidget* widget) = 0;
+
+protected:
+ Node* m_currentNode;
+
+private:
+ DOM::Node m_currentDomNode;
+};
+
+
+class TagActionSet : public TagActionSetAbstract
+{
+ Q_OBJECT
+public:
+ TagActionSet(QObject *parent = 0, const char *name = 0);
+ virtual ~TagActionSet() {}
+
+ virtual bool isInTagContext() const;
+ virtual void initActions(QWidget* parent);
+ virtual bool fillWithTagActions(QWidget* widget, DOM::Node const& node);
+ virtual void unplugAllActions(QWidget* widget) const;
+
+public slots:
+ void slotApplySourceIndentation();
+ void slotCopyDivElement();
+ void slotCutDivElement();
+
+protected:
+ virtual void initActionMenus(QWidget* widget);
+
+private:
+ bool isInDivArea() const;
+
+private:
+ KActionSeparator* m_separator;
+};
+
+
+class TableTagActionSet : public TagActionSetAbstract
+{
+ Q_OBJECT
+public:
+ TableTagActionSet(QObject *parent = 0, const char *name = 0);
+ virtual ~TableTagActionSet()
+ {}
+
+ virtual bool isInTagContext(/*DOM::Node const& node*/) const;
+ virtual void initActions(QWidget* parent);
+ virtual bool fillWithTagActions(QWidget* widget, DOM::Node const& node);
+ virtual void unplugAllActions(QWidget* widget) const;
+
+public slots:
+ // Insert
+ void slotInsertTable();
+ void slotInsertRowAbove();
+ void slotInsertRowBelow();
+ void slotInsertColumnLeft();
+ void slotInsertColumnRight();
+ // Remove
+ void slotRemoveTable();
+ void slotRemoveRows();
+ void slotRemoveColumns();
+ void slotRemoveCells();
+ void slotRemoveCellsContent();
+ // Merge
+ void slotMergeSelectedCells();
+
+protected:
+ virtual void initActionMenus(QWidget* widget);
+
+private:
+ // Insert
+ bool canInsertTable() const;
+ bool canInsertRowAbove() const;
+ bool canInsertRowBelow() const;
+ bool canInsertColumnLeft() const;
+ bool canInsertColumnRight() const;
+ // Remove
+ bool canRemoveTable() const;
+ bool canRemoveRows() const;
+ bool canRemoveColumns() const;
+ bool canRemoveCells() const;
+ bool canRemoveCellsContent() const;
+ // Merge
+ bool canMergeSelectedCells() const;
+
+ Node* tableStart() const;
+ int numberOfColumns() const;
+ int currentColumnIndex() const;
+ int columnIndex(Node* node) const;
+ Node* buildEmptyRowSubtree() const;
+ Node* buildEmptyTBodyCellSubtree() const;
+ Node* buildEmptyTHeadCellSubtree() const;
+
+ void removeColumn(int index, NodeModifsSet* modifs);
+ void clearCellContents(Node* tdNode, NodeModifsSet* modifs);
+
+private:
+ KActionSeparator* m_separator;
+
+ KActionMenu* m_tableActionMenu_0;
+ KActionMenu* m_insertActionMenu_1;
+ KActionMenu* m_removeActionMenu_1;
+};
+
+#endif
diff --git a/quanta/utility/toolbartabwidget.cpp b/quanta/utility/toolbartabwidget.cpp
new file mode 100644
index 00000000..03c6e86b
--- /dev/null
+++ b/quanta/utility/toolbartabwidget.cpp
@@ -0,0 +1,351 @@
+/***************************************************************************
+ toolbartabwidget.cpp
+ ---------------------
+ copyright : (C) 2003 by Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+//qt includes
+#include <qevent.h>
+#include <qlayout.h>
+#include <qobjectlist.h>
+#include <qpoint.h>
+#include <qtabbar.h>
+#include <qwidgetstack.h>
+#include <qtabwidget.h>
+#include <qfontmetrics.h>
+
+//kde includes
+#include <kaction.h>
+#include <kaccelmanager.h>
+#include <kdeversion.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpopupmenu.h>
+#include <ktoolbar.h>
+#include <ktoolbarbutton.h>
+#include <kdebug.h>
+#include <kglobalsettings.h>
+
+//app includes
+#include "toolbartabwidget.h"
+
+ToolbarTabWidget::ToolbarTabWidget(QWidget * parent, const char * name, WFlags f)
+:QTabWidget(parent, name, f)
+{
+ m_popupMenu = new KPopupMenu(this);
+ m_popupMenu->insertTitle(i18n("Toolbar Menu"), 1);
+ m_popupMenu->insertItem(i18n("New Action..."), parent, SLOT(slotNewAction()));
+ m_popupMenu->insertSeparator();
+ m_popupMenu->insertItem(i18n("New Toolbar..."), parent, SLOT(slotAddToolbar()));
+ m_popupMenu->insertItem(i18n("Remove Toolbar"), this, SLOT(slotRemoveToolbar()));
+ m_popupMenu->insertItem(i18n("Rename Toolbar..."), this, SLOT(slotRenameToolbar()));
+ m_popupMenu->insertItem(SmallIconSet("configure_toolbars"), i18n("Configure Toolbars..."), this, SLOT(slotEditToolbar()));
+
+ connect(this, SIGNAL(removeToolbar(const QString&)),
+ parent, SLOT(slotRemoveToolbar(const QString&)));
+ connect(this, SIGNAL(renameToolbar(const QString&)),
+ parent, SLOT(slotRenameToolbar(const QString&)));
+ connect(this, SIGNAL(editToolbar(const QString&)),
+ parent, SLOT(slotConfigureToolbars(const QString&)));
+ connect(this, SIGNAL(newAction()),
+ parent, SLOT(slotNewAction()));
+ connect(this, SIGNAL(addToolbar()),
+ parent, SLOT(slotAddToolbar()));
+ KAcceleratorManager::setNoAccel(this);
+}
+
+void ToolbarTabWidget::insertTab(QWidget *child, const QString &label, const QString &id)
+{
+ if (child->inherits("KToolBar") && child->parentWidget())
+ {
+ QTabWidget::insertTab(child->parentWidget(), label);
+ toolbarList.insert(id, child);
+ }
+}
+
+QWidget* ToolbarTabWidget::page(int index)
+{
+ QWidget *w = QTabWidget::page(index);
+
+ for (QMap<QString, QWidget*>::Iterator it = toolbarList.begin(); it != toolbarList.end(); ++it)
+ {
+ if (it.data()->parentWidget() == w)
+ {
+ w = *it;
+ break;
+ }
+ }
+ return w;
+}
+
+QString ToolbarTabWidget::id(QWidget *w) const
+{
+ QString idStr;
+ for (QMap<QString, QWidget*>::ConstIterator it = toolbarList.constBegin(); it != toolbarList.constEnd(); ++it)
+ {
+ if (it.data()->parentWidget() == w)
+ {
+ idStr = it.key();
+ break;
+ }
+ }
+ return idStr;
+}
+
+QString ToolbarTabWidget::id(int index) const
+{
+ QWidget *w = QTabWidget::page(index);
+ QString idStr;
+ for (QMap<QString, QWidget*>::ConstIterator it = toolbarList.constBegin(); it != toolbarList.constEnd(); ++it)
+ {
+ if (it.data()->parentWidget() == w)
+ {
+ idStr = it.key();
+ break;
+ }
+ }
+ return idStr;
+}
+
+QWidget* ToolbarTabWidget::page(const QString& id)
+{
+ QWidget *w = toolbarList.find(id).data();
+ return w;
+}
+
+void ToolbarTabWidget::removePage(QWidget * w)
+{
+ QWidget *parent = w->parentWidget();
+ if (w->inherits("KToolBar") && parent)
+ {
+ QTabWidget::removePage(parent);
+ for (QMap<QString, QWidget*>::ConstIterator it = toolbarList.constBegin(); it != toolbarList.constEnd(); ++it)
+ {
+ if (it.data() == w)
+ {
+ toolbarList.remove(it.key());
+ break;
+ }
+ }
+ delete parent;
+ }
+}
+
+void ToolbarTabWidget::slotRemoveToolbar()
+{
+ emit removeToolbar(tabUnderMouse.lower());
+}
+
+void ToolbarTabWidget::slotRenameToolbar()
+{
+ emit renameToolbar(tabUnderMouse.lower());
+}
+
+void ToolbarTabWidget::slotEditToolbar()
+{
+ emit editToolbar(tabUnderMouseLabel + " <quanta>");
+}
+
+void ToolbarTabWidget::mousePressEvent ( QMouseEvent * e )
+{
+ if (e->button() == Qt::RightButton)
+ {
+ QPoint p = e->globalPos();
+ QTab *tab = 0L;
+ QWidget *pageW = 0L;
+ for (int i =0; i < tabBar()->count(); i++)
+ {
+ tab = tabBar()->tabAt(i);
+ pageW = page(i);
+ QRect r = tab->rect();
+ QPoint p1 = mapToGlobal(r.topLeft());
+ QPoint p2 = mapToGlobal(r.bottomRight());
+ if (QRect(p1, p2).contains(p))
+ break;
+ else
+ tab = 0L;
+ }
+ tabUnderMouseLabel = tab ? tab->text() : label(currentPageIndex());
+ if (!pageW)
+ pageW = currentPage();
+ for (QMap<QString, QWidget*>::Iterator it = toolbarList.begin(); it != toolbarList.end(); ++it)
+ {
+ if (it.data()->parentWidget() == pageW)
+ {
+ tabUnderMouse = it.key();
+ break;
+ }
+ }
+ m_popupMenu->changeTitle(1, i18n("Toolbar Menu") + " - " + i18n(tabUnderMouseLabel.utf8()));
+ m_popupMenu->popup(p);
+ }
+}
+
+
+void ToolbarTabWidget::resizeEvent(QResizeEvent *e)
+{
+ QWidget::resizeEvent(e);
+ QWidget *tb;
+ for (QMap<QString, QWidget*>::Iterator it = toolbarList.begin(); it != toolbarList.end(); ++it)
+ {
+ tb = it.data();
+ tb->resize(QSize(width(), tb->height()));
+ }
+ int i = currentPageIndex();
+ if (i > 0)
+ {
+ setCurrentPage(i -1);
+ } else
+ if (i+1 < count())
+ {
+ setCurrentPage(i + 1);
+ }
+ setCurrentPage(i);
+}
+
+int ToolbarTabWidget::tabHeight() const
+{
+ int height = tabBar()->height();
+ if (height < 2)
+ {
+ height = QFontMetrics(KGlobalSettings::generalFont()).height() + 12;
+ }
+ return height;
+}
+
+
+QuantaToolBar::QuantaToolBar(QWidget *parent, const char *name, bool honor_style, bool readConfig)
+:KToolBar (parent, name=0, honor_style, readConfig)
+{
+ m_popupMenu = new KPopupMenu(this);
+ m_toolbarTab = dynamic_cast<ToolbarTabWidget*>(parent->parentWidget());
+ currentActionName = "";
+ m_iconTextMenu = new KPopupMenu(this);
+ m_iconTextMenu->setCheckable(true);
+ m_iconTextMenu->insertItem(i18n("Icons Only"), 0);
+ m_iconTextMenu->insertItem(i18n("Text Only"), 1);
+ m_iconTextMenu->insertItem(i18n("Text Alongside Icons"), 2);
+ m_iconTextMenu->insertItem(i18n("Text Under Icons"), 3);
+ connect(m_iconTextMenu, SIGNAL(activated(int)), SLOT(slotIconTextChanged(int)));
+ connect(m_iconTextMenu, SIGNAL(aboutToShow()), SLOT(slotIconTextMenuAboutToShow()));
+ setIconText(ToolbarTabWidget::ref()->iconText(), false);
+}
+
+void QuantaToolBar::slotIconTextMenuAboutToShow()
+{
+ m_iconTextMenu->setItemChecked(0, false);
+ m_iconTextMenu->setItemChecked(1, false);
+ m_iconTextMenu->setItemChecked(2, false);
+ m_iconTextMenu->setItemChecked(3, false);
+ switch (ToolbarTabWidget::ref()->iconText())
+ {
+ case IconOnly: m_iconTextMenu->setItemChecked(0, true);
+ break;
+ case TextOnly: m_iconTextMenu->setItemChecked(1, true);
+ break;
+ case IconTextRight: m_iconTextMenu->setItemChecked(2, true);
+ break;
+ case IconTextBottom: m_iconTextMenu->setItemChecked(3, true);
+ break;
+ }
+}
+
+void QuantaToolBar::slotIconTextChanged(int id)
+{
+ ToolbarTabWidget *toolbarTab = ToolbarTabWidget::ref();
+ int width = toolbarTab->width();
+ int bigHeight = iconSize() + QFontMetrics(KGlobalSettings::toolBarFont()).height() + 10;
+ int normalHeight = iconSize() + 10;
+ for (int i = 0; i < toolbarTab->count(); i++)
+ {
+ QuantaToolBar *tb = static_cast<QuantaToolBar*>(toolbarTab->page(i));
+ switch (id)
+ {
+ case 0: tb->setIconText(IconOnly);
+ tb->setGeometry(0,0, width, normalHeight);
+ break;
+ case 1: tb->setIconText(TextOnly);
+ tb->setGeometry(0,0, width, normalHeight);
+ break;
+ case 2: tb->setIconText(IconTextRight);
+ tb->setGeometry(0,0, width, normalHeight);
+ break;
+ case 3: tb->setIconText(IconTextBottom);
+ tb->setGeometry(0,0, width, bigHeight);
+ break;
+ }
+ }
+ toolbarTab->setIconText(iconText());
+ if (id == 3)
+ {
+ toolbarTab->setFixedHeight(toolbarTab->tabHeight() + height() + 3);
+ } else
+ {
+ toolbarTab->setFixedHeight(toolbarTab->tabHeight() + height() + 3);
+ }
+}
+
+void QuantaToolBar::mousePressEvent(QMouseEvent *e)
+{
+ if (e->button() == Qt::RightButton)
+ {
+ m_popupMenu->clear();
+ QPoint p = e->globalPos();
+ if (m_toolbarTab)
+ {
+ m_toolbarTab->tabUnderMouse = m_toolbarTab->id(m_toolbarTab->currentPageIndex());
+ m_toolbarTab->tabUnderMouseLabel = m_toolbarTab->label(m_toolbarTab->currentPageIndex());
+ m_popupMenu->insertTitle(i18n("Toolbar Menu") + " - "
+ + i18n(m_toolbarTab->tabUnderMouseLabel.utf8()));
+ m_popupMenu->insertItem(i18n("New Action..."), m_toolbarTab, SIGNAL(newAction()));
+ QObjectList* childrenList = queryList("KToolBarButton");
+ for (uint i = 0; i < childrenList->count(); i++)
+ {
+ KToolBarButton *w = static_cast<KToolBarButton*>(childrenList->at(i));
+ QPoint p1 = w->parentWidget()->mapToGlobal(w->pos());
+ QPoint p2 = QPoint(p1.x() + w->width(), p1.y()+w->height());
+ if (QRect(p1, p2).contains(p))
+ {
+ currentActionName = w->textLabel();
+ QString actionName = currentActionName;
+ m_popupMenu->insertItem(i18n("Remove Action - %1").arg(actionName.replace('&',"&&")), this, SLOT(slotRemoveAction()));
+ m_popupMenu->insertItem(i18n("Edit Action - %1").arg(actionName), this, SLOT(slotEditAction()));
+ break;
+ }
+ }
+ m_popupMenu->insertSeparator();
+ m_popupMenu->insertItem(i18n("New Toolbar..."), m_toolbarTab, SIGNAL(addToolbar()));
+ m_popupMenu->insertItem(i18n("Remove Toolbar"), m_toolbarTab, SLOT(slotRemoveToolbar()));
+ m_popupMenu->insertItem(i18n("Rename Toolbar..."), m_toolbarTab, SLOT(slotRenameToolbar()));
+ m_popupMenu->insertSeparator();
+ m_popupMenu->insertItem( i18n("Text Position"), m_iconTextMenu);
+ m_popupMenu->insertItem(SmallIconSet("configure_toolbars"), i18n("Configure Toolbars..."), m_toolbarTab, SLOT(slotEditToolbar()));
+ }
+ m_popupMenu->popup(p);
+ }
+}
+
+void QuantaToolBar::slotEditAction()
+{
+ emit editAction(currentActionName);
+}
+
+void QuantaToolBar::slotRemoveAction()
+{
+ if ( KMessageBox::warningContinueCancel(this, i18n("<qt>Are you sure you want to remove the <b>%1</b> action?</qt>").arg(currentActionName),QString::null,KStdGuiItem::del()) == KMessageBox::Continue )
+ {
+ emit removeAction(m_toolbarTab->tabUnderMouse, currentActionName);
+ }
+}
+
+
+#include "toolbartabwidget.moc"
diff --git a/quanta/utility/toolbartabwidget.h b/quanta/utility/toolbartabwidget.h
new file mode 100644
index 00000000..aa800ae6
--- /dev/null
+++ b/quanta/utility/toolbartabwidget.h
@@ -0,0 +1,111 @@
+/***************************************************************************
+ toolbartabwidget.h
+ ---------------------
+ copyright : (C) 2003 by Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+#ifndef TOOLBARTABWIDGET_H
+#define TOOLBARTABWIDGET_H
+
+#include <qwidget.h>
+#include <qmap.h>
+
+class QTabWidget;
+class KPopupMenu;
+class QWidgetStack;
+class QTabBar;
+class KToolBar;
+
+class ToolbarTabWidget: public QTabWidget
+{
+ Q_OBJECT
+public:
+ QWidgetStack *m_widgetStack;
+
+ static ToolbarTabWidget* const ref(QWidget *parent = 0L, const char *name = 0L)
+ {
+ static ToolbarTabWidget *m_ref;
+ if (!m_ref) m_ref = new ToolbarTabWidget (parent, name);
+ return m_ref;
+ }
+ virtual ~ToolbarTabWidget(){};
+
+ virtual void insertTab(QWidget *child, const QString &label, const QString &id);
+ virtual QWidget* page(int index);
+ virtual QWidget* page(const QString& id);
+ int tabHeight() const;
+ QString id(QWidget *w) const;
+ QString id(int index) const;
+ KToolBar::IconText iconText() const {return m_iconText;}
+ void setIconText(KToolBar::IconText mode) {m_iconText = mode; emit iconTextModeChanged();}
+
+public slots:
+ virtual void removePage(QWidget * w );
+ virtual void resizeEvent(QResizeEvent *);
+
+private slots:
+ void slotRemoveToolbar();
+ void slotRenameToolbar();
+ void slotEditToolbar();
+
+signals:
+ void removeToolbar(const QString&);
+ void renameToolbar(const QString&);
+ void editToolbar(const QString&);
+ void newAction();
+ void addToolbar();
+ void iconTextModeChanged();
+
+public:
+ QString tabUnderMouse;
+ QString tabUnderMouseLabel;
+
+protected:
+ virtual void mousePressEvent ( QMouseEvent * e );
+
+ KPopupMenu *m_popupMenu;
+ QTabBar *m_tabBar;
+ QMap<QString, QWidget*> toolbarList;
+
+private:
+ ToolbarTabWidget(QWidget * parent = 0, const char * name = 0, WFlags f = 0);
+ KToolBar::IconText m_iconText;
+
+};
+
+class QuantaToolBar: public KToolBar
+{
+ Q_OBJECT
+
+public:
+ QuantaToolBar (QWidget *parent, const char *name=0, bool honor_style=FALSE, bool readConfig=TRUE);
+ virtual ~QuantaToolBar() {};
+
+private slots:
+ void slotEditAction();
+ void slotRemoveAction();
+ void slotIconTextChanged(int id);
+ void slotIconTextMenuAboutToShow();
+
+signals:
+ void removeAction(const QString&, const QString&);
+ void editAction(const QString&);
+
+protected:
+ virtual void mousePressEvent ( QMouseEvent * e );
+
+ KPopupMenu *m_popupMenu;
+ KPopupMenu *m_iconTextMenu;
+ ToolbarTabWidget *m_toolbarTab;
+ QString currentActionName;
+};
+
+#endif
diff --git a/quanta/utility/toolbarxmlgui.cpp b/quanta/utility/toolbarxmlgui.cpp
new file mode 100644
index 00000000..1d7d1558
--- /dev/null
+++ b/quanta/utility/toolbarxmlgui.cpp
@@ -0,0 +1,27 @@
+/***************************************************************************
+ toolbarxmlgui.cpp - description
+ -------------------
+ begin : Sat Jul 20 2002
+ copyright : (C) 2002 by Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+#include "toolbarxmlgui.h"
+
+ToolbarXMLGUI::ToolbarXMLGUI(const QString& xmlFile)
+ : KXMLGUIClient()
+{
+ setLocalXMLFile(xmlFile);
+ setXMLFile(xmlFile, false);
+}
+
+
+ToolbarXMLGUI::~ToolbarXMLGUI(){
+}
diff --git a/quanta/utility/toolbarxmlgui.h b/quanta/utility/toolbarxmlgui.h
new file mode 100644
index 00000000..74ac04cf
--- /dev/null
+++ b/quanta/utility/toolbarxmlgui.h
@@ -0,0 +1,32 @@
+/***************************************************************************
+ toolbarxmlgui.h - description
+ -------------------
+ begin : Sat Jul 20 2002
+ copyright : (C) 2002 by Andras Mantia <amantia@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef TOOLBARXMLGUI_H
+#define TOOLBARXMLGUI_H
+
+#include <kxmlguiclient.h>
+
+/**
+ *@author Andras Mantia
+ */
+
+class ToolbarXMLGUI : public KXMLGUIClient {
+public:
+ ToolbarXMLGUI(const QString& xmlFile);
+ ~ToolbarXMLGUI();
+};
+
+#endif