diff options
Diffstat (limited to 'parts/texttools/texttoolswidget.cpp')
-rw-r--r-- | parts/texttools/texttoolswidget.cpp | 400 |
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 * + * bernd@kdevelop.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 "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" |