summaryrefslogtreecommitdiffstats
path: root/parts/texttools/texttoolswidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'parts/texttools/texttoolswidget.cpp')
-rw-r--r--parts/texttools/texttoolswidget.cpp400
1 files changed, 400 insertions, 0 deletions
diff --git a/parts/texttools/texttoolswidget.cpp b/parts/texttools/texttoolswidget.cpp
new file mode 100644
index 00000000..ff85d0f0
--- /dev/null
+++ b/parts/texttools/texttoolswidget.cpp
@@ -0,0 +1,400 @@
+/***************************************************************************
+ * Copyright (C) 2002 by Bernd Gehrmann *
+ * *
+ * 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 "texttoolswidget.h"
+
+#include <qheader.h>
+#include <qregexp.h>
+#include <qtimer.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kparts/part.h>
+#include <kpopupmenu.h>
+#include <ktexteditor/viewcursorinterface.h>
+#include <ktexteditor/selectioninterface.h>
+#include <ktexteditor/editinterface.h>
+
+#include "kdevmainwindow.h"
+#include "kdevpartcontroller.h"
+#include "texttoolspart.h"
+
+
+class TextStructItem : public QListViewItem
+{
+public:
+ TextStructItem(QListView *parent)
+ : QListViewItem(parent)
+ {}
+ TextStructItem(QListViewItem *parent)
+ : QListViewItem(parent)
+ {
+ QListViewItem *item = this;
+ while (item->nextSibling())
+ item = item->nextSibling();
+ if (item != this)
+ moveItem(item);
+ }
+
+ QString text(int) const
+ {
+ return extra.isNull()? tag : QString("%1: %2").arg(tag).arg(extra);
+ }
+ TextStructItem *parentStructItem()
+ { return static_cast<TextStructItem*>(parent()); }
+
+ QString tag;
+ QString extra;
+ int pos;
+ int endpos;
+};
+
+
+TextToolsWidget::TextToolsWidget(TextToolsPart *part, QWidget *parent, const char *name)
+ : KListView(parent, name)
+{
+ setResizeMode(QListView::LastColumn);
+ setSorting(-1);
+ header()->hide();
+ addColumn(QString::null);
+
+ m_part = part;
+
+ m_timer = new QTimer(this);
+ connect( this, SIGNAL(mouseButtonPressed(int, QListViewItem*, const QPoint&, int)),
+ this, SLOT(slotItemPressed(int,QListViewItem*)) );
+ // connect( this, SIGNAL(doubleClicked(QListViewItem*)),
+ // this, SLOT(slotItemPressed(int,QListViewItem*)) );
+ connect( this, SIGNAL(returnPressed(QListViewItem*)),
+ this, SLOT(slotReturnPressed(QListViewItem*)) );
+ connect( this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)),
+ this, SLOT(slotContextMenu(KListView*, QListViewItem*, const QPoint&)) );
+}
+
+
+TextToolsWidget::~TextToolsWidget()
+{}
+
+
+void TextToolsWidget::slotItemPressed(int button, QListViewItem *item)
+{
+ if (!item)
+ return;
+
+ TextStructItem *tsitem = static_cast<TextStructItem*>(item);
+ int searchedPos = tsitem->pos;
+ int searchedEndpos = tsitem->endpos;
+ kdDebug(9030) << "Searched pos " << searchedPos << ", " << searchedEndpos << endl;
+
+ int endline = 0;
+ int endcol = 0;
+ int line = 0;
+ int col = 0;
+
+ int len = m_cachedText.length();
+ int pos = 0;
+ while (pos < len) {
+ if (pos == searchedPos) {
+ line = endline;
+ col = endcol;
+ }
+ if (pos == searchedEndpos)
+ break;
+ QChar ch = m_cachedText[pos];
+ if (ch == '\n') {
+ ++endline;
+ endcol = 0;
+ } else {
+ ++endcol;
+ }
+ ++pos;
+ }
+
+ KParts::Part *rwpart
+ = dynamic_cast<KParts::Part*>(m_part->partController()->activePart());
+ QWidget *view = m_part->partController()->activeWidget();
+
+ KTextEditor::ViewCursorInterface *cursorIface
+ = dynamic_cast<KTextEditor::ViewCursorInterface*>(view);
+ if (cursorIface) {
+ kdDebug(9030) << "set cursor " << line << ", " << col << endl;
+ cursorIface->setCursorPosition(line, col);
+ }
+
+ if (button == MidButton) {
+ KTextEditor::SelectionInterface *selectionIface
+ = dynamic_cast<KTextEditor::SelectionInterface*>(rwpart);
+ if (selectionIface) {
+ kdDebug(9030) << "set selection " << line << ", " << col
+ << ", " << endline << ", " << endcol << endl;
+ selectionIface->setSelection((int)line, (int)col, (int)endline, (int)endcol+1);
+ }
+ }
+
+ m_part->mainWindow()->lowerView(this);
+}
+
+
+void TextToolsWidget::slotReturnPressed(QListViewItem *item)
+{
+ slotItemPressed(LeftButton, item);
+}
+
+
+void TextToolsWidget::slotContextMenu(KListView *, QListViewItem *item, const QPoint &)
+{
+ if (!item)
+ return;
+
+#if 0
+ KPopupMenu popup(i18n("Text Structure"), this);
+ popup.exec(p);
+#endif
+}
+
+
+void TextToolsWidget::stop()
+{
+ disconnect( m_timer );
+ m_relevantTags.clear();
+ m_emptyTags.clear();
+ m_cachedText = QString::null;
+}
+
+
+void TextToolsWidget::setMode(Mode mode, KParts::Part *part)
+{
+ connect( part, SIGNAL(textChanged()),
+ this, SLOT(startTimer()) );
+ m_editIface = dynamic_cast<KTextEditor::EditInterface*>(part);
+
+ switch (mode) {
+ case HTML:
+ m_relevantTags << "h1" << "h2" << "h3" << "h4"
+ << "table" << "tr";
+ m_emptyTags << "br" << "hr" << "img" << "input" << "p" << "meta";
+
+ connect( m_timer, SIGNAL(timeout()),
+ this, SLOT(parseXML()) );
+ break;
+ case Docbook:
+ m_relevantTags << "chapter" << "sect1" << "sect2"
+ << "para" << "formalpara";
+ connect( m_timer, SIGNAL(timeout()),
+ this, SLOT(parseXML()) );
+ break;
+ case LaTeX:
+ connect( m_timer, SIGNAL(timeout()),
+ this, SLOT(parseLaTeX()) );
+ break;
+ default: ;
+ }
+
+ m_timer->start(0, true);
+}
+
+
+void TextToolsWidget::startTimer()
+{
+ kdDebug(9030) << "Starting parse timer" << endl;
+ m_timer->start(1000, true);
+}
+
+
+void TextToolsWidget::parseXML()
+{
+ kdDebug(9030) << "Starting to parse XML" << endl;
+ clear();
+ QString text = m_editIface->text();
+ m_cachedText = text;
+
+ TextStructItem *currentItem = new TextStructItem(this);
+ currentItem->tag = "Root";
+ currentItem->pos = -1;
+ currentItem->endpos = -1;
+
+ int len = text.length();
+ for (int pos=0; pos+1 < len; ++pos) {
+ QChar ch1 = text[pos];
+ QChar ch2 = text[pos+1];
+
+ if (ch1 == '<' && ch2 == '?') {
+
+ // PHP and other similar stuff
+ QString tag;
+ int endpos = pos+2;
+ bool foundspace = false;
+ while (endpos+1 < len) {
+ QChar ch3 = text[endpos];
+ QChar ch4 = text[endpos+1];
+ if ((ch3 == ' ' || ch3 == '\t' || ch3 == '\n') && !foundspace) {
+ tag = text.mid(pos+2, endpos-pos-2).lower();
+ foundspace = true;
+ } else if (ch3 == '?' && ch4 == '>') {
+ if (!foundspace)
+ tag = text.mid(pos+2, endpos-pos-2).lower();
+ break;
+ }
+ ++endpos;
+ }
+
+ TextStructItem *item = new TextStructItem(currentItem);
+ item->tag = "<?" + tag + "?>";
+ item->pos = pos;
+ item->endpos = endpos+1;
+
+ pos = endpos+1;
+
+ } else if (ch1 == '<' && ch2 == '!') {
+
+ // Processing instructions like !DOCTYPE
+ QString tag;
+ int endpos = pos+2;
+ bool foundspace = false;
+ while (endpos+1 < len) {
+ QChar ch3 = text[endpos];
+ if ((ch3 == ' ' || ch3 == '\t' || ch3 == '\n') && !foundspace) {
+ tag = text.mid(pos+2, endpos-pos-2).lower();
+ foundspace = true;
+ } else if (ch3 == '>') {
+ if (!foundspace)
+ tag = text.mid(pos+2, endpos-pos-2).lower();
+ break;
+ }
+ ++endpos;
+ }
+
+ TextStructItem *item = new TextStructItem(currentItem);
+ item->tag = "<!" + tag + ">";
+ item->pos = pos;
+ item->endpos = endpos+1;
+
+ pos = endpos+1;
+
+ } else if (ch1 == '<' && ch2 == '/') {
+
+ QString tag;
+ int endpos = pos+2;
+ while (endpos < len) {
+ QChar ch3 = text[endpos];
+ if (ch3 == '>') {
+ tag = text.mid(pos+2, endpos-pos-2).lower();
+ break;
+ }
+ ++endpos;
+ }
+
+ if (!m_relevantTags.contains(tag)) {
+ pos = endpos;
+ continue;
+ }
+
+ TextStructItem *closingItem = currentItem;
+ while (closingItem->parent() && closingItem->tag != tag)
+ closingItem = closingItem->parentStructItem();
+ if (closingItem->parent()) {
+ closingItem->endpos = endpos;
+ currentItem = closingItem->parentStructItem();
+ } else {
+ kdDebug(9030) << "found no opening tag " << tag << "." << endl;
+ }
+
+ pos = endpos;
+
+ } else if (ch1 == '<') {
+
+ QString tag;
+ int endpos = pos+1;
+ bool foundspace = false;
+ while (endpos < len) {
+ QChar ch3 = text[endpos];
+ if ((ch3 == ' ' || ch3 == '\t' || ch3 == '\n') && !foundspace) {
+ tag = text.mid(pos+1, endpos-pos-1).lower();
+ foundspace = true;
+ } else if (ch3 == '>') {
+ if (!foundspace) {
+ tag = text.mid(pos+1, endpos-pos-1).lower();
+ }
+ break;
+ }
+ ++endpos;
+ }
+
+ if (!m_relevantTags.contains(tag)) {
+ pos = endpos;
+ continue;
+ }
+
+ TextStructItem *item = new TextStructItem(currentItem);
+ item->tag = tag;
+ item->pos = pos;
+ item->endpos = -1;
+
+ if (m_emptyTags.contains(tag))
+ item->endpos = endpos;
+ else
+ currentItem = item;
+ pos = endpos;
+
+ }
+ }
+
+ // firstChild()->setOpen(true);
+ QListViewItemIterator it(this);
+ for (; it.current(); ++it)
+ it.current()->setOpen(true);
+}
+
+
+void TextToolsWidget::parseLaTeX()
+{
+ kdDebug(9030) << "Starting to parse LaTeX" << endl;
+ clear();
+ QString text = m_editIface->text();
+ m_cachedText = text;
+
+ TextStructItem *currentItem = new TextStructItem(this);
+ currentItem->tag = "Root";
+ currentItem->pos = -1;
+ currentItem->endpos = -1;
+
+ QString hierarchyLevels = "Root,chapter,section,subsection,subsubsection";
+ QRegExp re("\n[ \t]*s*\\\\(chapter|section|subsection|subsubsection)\\{([^}]*)\\}");
+
+ int pos=0;
+ for (;;) {
+ pos = re.search(text, pos);
+ if (pos == -1)
+ break;
+ QString tag = re.cap(1);
+ QString title = re.cap(2);
+ kdDebug(9030) << "Match with " << tag << " and title " << title << endl;
+ int level = hierarchyLevels.find(tag);
+ while (currentItem->parent() && level <= hierarchyLevels.find(currentItem->tag))
+ currentItem = currentItem->parentStructItem();
+
+ TextStructItem *item = new TextStructItem(currentItem);
+ item->tag = tag;
+ item->extra = title;
+ item->pos = pos+1;
+ item->endpos = pos+re.matchedLength()-1; // lie
+
+ if (level > hierarchyLevels.find(currentItem->tag))
+ currentItem = item;
+
+ pos = pos+re.matchedLength();
+ }
+
+ QListViewItemIterator it(this);
+ for (; it.current(); ++it)
+ it.current()->setOpen(true);
+}
+
+#include "texttoolswidget.moc"