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.
401 lines
12 KiB
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 <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 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").tqarg(tag).tqarg(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)
|
|
: KListView(parent, name)
|
|
{
|
|
setResizeMode(TQListView::LastColumn);
|
|
setSorting(-1);
|
|
header()->hide();
|
|
addColumn(TQString());
|
|
|
|
m_part = part;
|
|
|
|
m_timer = new TQTimer(this);
|
|
connect( this, TQT_SIGNAL(mouseButtonPressed(int, TQListViewItem*, const TQPoint&, int)),
|
|
this, TQT_SLOT(slotItemPressed(int,TQListViewItem*)) );
|
|
// connect( this, TQT_SIGNAL(doubleClicked(TQListViewItem*)),
|
|
// this, TQT_SLOT(slotItemPressed(int,TQListViewItem*)) );
|
|
connect( this, TQT_SIGNAL(returnPressed(TQListViewItem*)),
|
|
this, TQT_SLOT(slotReturnPressed(TQListViewItem*)) );
|
|
connect( this, TQT_SIGNAL(contextMenu(KListView*, TQListViewItem*, const TQPoint&)),
|
|
this, TQT_SLOT(slotContextMenu(KListView*, 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 == Qt::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(Qt::LeftButton, item);
|
|
}
|
|
|
|
|
|
void TextToolsWidget::slotContextMenu(KListView *, TQListViewItem *item, const TQPoint &)
|
|
{
|
|
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 = TQString();
|
|
}
|
|
|
|
|
|
void TextToolsWidget::setMode(Mode mode, KParts::Part *part)
|
|
{
|
|
connect( part, TQT_SIGNAL(textChanged()),
|
|
this, TQT_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, TQT_SIGNAL(timeout()),
|
|
this, TQT_SLOT(parseXML()) );
|
|
break;
|
|
case Docbook:
|
|
m_relevantTags << "chapter" << "sect1" << "sect2"
|
|
<< "para" << "formalpara";
|
|
connect( m_timer, TQT_SIGNAL(timeout()),
|
|
this, TQT_SLOT(parseXML()) );
|
|
break;
|
|
case LaTeX:
|
|
connect( m_timer, TQT_SIGNAL(timeout()),
|
|
this, TQT_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"
|