You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdevelop/parts/texttools/texttoolswidget.cpp

401 lines
12 KiB

/***************************************************************************
* 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 <tqheader.h>
#include <tqregexp.h>
#include <tqtimer.h>
#include <kdebug.h>
#include <tdelocale.h>
#include <tdeparts/part.h>
#include <tdepopupmenu.h>
#include <tdetexteditor/viewcursorinterface.h>
#include <tdetexteditor/selectioninterface.h>
#include <tdetexteditor/editinterface.h>
#include "kdevmainwindow.h"
#include "kdevpartcontroller.h"
#include "texttoolspart.h"
class TextStructItem : public TQListViewItem
{
public:
TextStructItem(TQListView *parent)
: TQListViewItem(parent)
{}
TextStructItem(TQListViewItem *parent)
: TQListViewItem(parent)
{
TQListViewItem *item = this;
while (item->nextSibling())
item = item->nextSibling();
if (item != this)
moveItem(item);
}
TQString text(int) const
{
return extra.isNull()? tag : TQString("%1: %2").arg(tag).arg(extra);
}
TextStructItem *parentStructItem()
{ return static_cast<TextStructItem*>(parent()); }
TQString tag;
TQString extra;
int pos;
int endpos;
};
TextToolsWidget::TextToolsWidget(TextToolsPart *part, TQWidget *parent, const char *name)
: TDEListView(parent, name)
{
setResizeMode(TQListView::LastColumn);
setSorting(-1);
header()->hide();
addColumn(TQString());
m_part = part;
m_timer = new TQTimer(this);
connect( this, TQ_SIGNAL(mouseButtonPressed(int, TQListViewItem*, const TQPoint&, int)),
this, TQ_SLOT(slotItemPressed(int,TQListViewItem*)) );
// connect( this, TQ_SIGNAL(doubleClicked(TQListViewItem*)),
// this, TQ_SLOT(slotItemPressed(int,TQListViewItem*)) );
connect( this, TQ_SIGNAL(returnPressed(TQListViewItem*)),
this, TQ_SLOT(slotReturnPressed(TQListViewItem*)) );
connect( this, TQ_SIGNAL(contextMenu(TDEListView*, TQListViewItem*, const TQPoint&)),
this, TQ_SLOT(slotContextMenu(TDEListView*, TQListViewItem*, const TQPoint&)) );
}
TextToolsWidget::~TextToolsWidget()
{}
void TextToolsWidget::slotItemPressed(int button, TQListViewItem *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;
TQChar ch = m_cachedText[pos];
if (ch == '\n') {
++endline;
endcol = 0;
} else {
++endcol;
}
++pos;
}
KParts::Part *rwpart
= dynamic_cast<KParts::Part*>(m_part->partController()->activePart());
TQWidget *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 == TQt::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(TQListViewItem *item)
{
slotItemPressed(TQt::LeftButton, item);
}
void TextToolsWidget::slotContextMenu(TDEListView *, TQListViewItem *item, const TQPoint &)
{
if (!item)
return;
#if 0
TDEPopupMenu popup(i18n("Text Structure"), this);
popup.exec(p);
#endif
}
void TextToolsWidget::stop()
{
disconnect( m_timer );
m_relevantTags.clear();
m_emptyTags.clear();
m_cachedText = TQString();
}
void TextToolsWidget::setMode(Mode mode, KParts::Part *part)
{
connect( part, TQ_SIGNAL(textChanged()),
this, TQ_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, TQ_SIGNAL(timeout()),
this, TQ_SLOT(parseXML()) );
break;
case Docbook:
m_relevantTags << "chapter" << "sect1" << "sect2"
<< "para" << "formalpara";
connect( m_timer, TQ_SIGNAL(timeout()),
this, TQ_SLOT(parseXML()) );
break;
case LaTeX:
connect( m_timer, TQ_SIGNAL(timeout()),
this, TQ_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();
TQString 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) {
TQChar ch1 = text[pos];
TQChar ch2 = text[pos+1];
if (ch1 == '<' && ch2 == '?') {
// PHP and other similar stuff
TQString tag;
int endpos = pos+2;
bool foundspace = false;
while (endpos+1 < len) {
TQChar ch3 = text[endpos];
TQChar 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
TQString tag;
int endpos = pos+2;
bool foundspace = false;
while (endpos+1 < len) {
TQChar 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 == '/') {
TQString tag;
int endpos = pos+2;
while (endpos < len) {
TQChar 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 == '<') {
TQString tag;
int endpos = pos+1;
bool foundspace = false;
while (endpos < len) {
TQChar 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);
TQListViewItemIterator it(this);
for (; it.current(); ++it)
it.current()->setOpen(true);
}
void TextToolsWidget::parseLaTeX()
{
kdDebug(9030) << "Starting to parse LaTeX" << endl;
clear();
TQString text = m_editIface->text();
m_cachedText = text;
TextStructItem *currentItem = new TextStructItem(this);
currentItem->tag = "Root";
currentItem->pos = -1;
currentItem->endpos = -1;
TQString hierarchyLevels = "Root,chapter,section,subsection,subsubsection";
TQRegExp re("\n[ \t]*s*\\\\(chapter|section|subsection|subsubsection)\\{([^}]*)\\}");
int pos=0;
for (;;) {
pos = re.search(text, pos);
if (pos == -1)
break;
TQString tag = re.cap(1);
TQString 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();
}
TQListViewItemIterator it(this);
for (; it.current(); ++it)
it.current()->setOpen(true);
}
#include "texttoolswidget.moc"