1
/***************************************************************************
2
* Copyright (C) 2002 by Bernd Gehrmann *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License as published by *
7
* the Free Software Foundation; either version 2 of the License, or *
8
* (at your option) any later version. *
10
***************************************************************************/
12
#include "texttoolswidget.h"
19
#include <kparts/part.h>
20
#include <kpopupmenu.h>
21
#include <ktexteditor/viewcursorinterface.h>
22
#include <ktexteditor/selectioninterface.h>
23
#include <ktexteditor/editinterface.h>
25
#include "kdevmainwindow.h"
26
#include "kdevpartcontroller.h"
27
#include "texttoolspart.h"
30
class TextStructItem : public QListViewItem
33
TextStructItem(QListView *parent)
34
: QListViewItem(parent)
36
TextStructItem(QListViewItem *parent)
37
: QListViewItem(parent)
39
QListViewItem *item = this;
40
while (item->nextSibling())
41
item = item->nextSibling();
46
QString text(int) const
48
return extra.isNull()? tag : QString("%1: %2").arg(tag).arg(extra);
50
TextStructItem *parentStructItem()
51
{ return static_cast<TextStructItem*>(parent()); }
60
TextToolsWidget::TextToolsWidget(TextToolsPart *part, QWidget *parent, const char *name)
61
: KListView(parent, name)
63
setResizeMode(QListView::LastColumn);
66
addColumn(QString::null);
70
m_timer = new QTimer(this);
71
connect( this, SIGNAL(mouseButtonPressed(int, QListViewItem*, const QPoint&, int)),
72
this, SLOT(slotItemPressed(int,QListViewItem*)) );
73
// connect( this, SIGNAL(doubleClicked(QListViewItem*)),
74
// this, SLOT(slotItemPressed(int,QListViewItem*)) );
75
connect( this, SIGNAL(returnPressed(QListViewItem*)),
76
this, SLOT(slotReturnPressed(QListViewItem*)) );
77
connect( this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)),
78
this, SLOT(slotContextMenu(KListView*, QListViewItem*, const QPoint&)) );
82
TextToolsWidget::~TextToolsWidget()
86
void TextToolsWidget::slotItemPressed(int button, QListViewItem *item)
91
TextStructItem *tsitem = static_cast<TextStructItem*>(item);
92
int searchedPos = tsitem->pos;
93
int searchedEndpos = tsitem->endpos;
94
kdDebug(9030) << "Searched pos " << searchedPos << ", " << searchedEndpos << endl;
101
int len = m_cachedText.length();
104
if (pos == searchedPos) {
108
if (pos == searchedEndpos)
110
QChar ch = m_cachedText[pos];
121
= dynamic_cast<KParts::Part*>(m_part->partController()->activePart());
122
QWidget *view = m_part->partController()->activeWidget();
124
KTextEditor::ViewCursorInterface *cursorIface
125
= dynamic_cast<KTextEditor::ViewCursorInterface*>(view);
127
kdDebug(9030) << "set cursor " << line << ", " << col << endl;
128
cursorIface->setCursorPosition(line, col);
131
if (button == MidButton) {
132
KTextEditor::SelectionInterface *selectionIface
133
= dynamic_cast<KTextEditor::SelectionInterface*>(rwpart);
134
if (selectionIface) {
135
kdDebug(9030) << "set selection " << line << ", " << col
136
<< ", " << endline << ", " << endcol << endl;
137
selectionIface->setSelection((int)line, (int)col, (int)endline, (int)endcol+1);
141
m_part->mainWindow()->lowerView(this);
145
void TextToolsWidget::slotReturnPressed(QListViewItem *item)
147
slotItemPressed(LeftButton, item);
151
void TextToolsWidget::slotContextMenu(KListView *, QListViewItem *item, const QPoint &)
157
KPopupMenu popup(i18n("Text Structure"), this);
163
void TextToolsWidget::stop()
165
disconnect( m_timer );
166
m_relevantTags.clear();
168
m_cachedText = QString::null;
172
void TextToolsWidget::setMode(Mode mode, KParts::Part *part)
174
connect( part, SIGNAL(textChanged()),
175
this, SLOT(startTimer()) );
176
m_editIface = dynamic_cast<KTextEditor::EditInterface*>(part);
180
m_relevantTags << "h1" << "h2" << "h3" << "h4"
182
m_emptyTags << "br" << "hr" << "img" << "input" << "p" << "meta";
184
connect( m_timer, SIGNAL(timeout()),
185
this, SLOT(parseXML()) );
188
m_relevantTags << "chapter" << "sect1" << "sect2"
189
<< "para" << "formalpara";
190
connect( m_timer, SIGNAL(timeout()),
191
this, SLOT(parseXML()) );
194
connect( m_timer, SIGNAL(timeout()),
195
this, SLOT(parseLaTeX()) );
200
m_timer->start(0, true);
204
void TextToolsWidget::startTimer()
206
kdDebug(9030) << "Starting parse timer" << endl;
207
m_timer->start(1000, true);
211
void TextToolsWidget::parseXML()
213
kdDebug(9030) << "Starting to parse XML" << endl;
215
QString text = m_editIface->text();
218
TextStructItem *currentItem = new TextStructItem(this);
219
currentItem->tag = "Root";
220
currentItem->pos = -1;
221
currentItem->endpos = -1;
223
int len = text.length();
224
for (int pos=0; pos+1 < len; ++pos) {
225
QChar ch1 = text[pos];
226
QChar ch2 = text[pos+1];
228
if (ch1 == '<' && ch2 == '?') {
230
// PHP and other similar stuff
233
bool foundspace = false;
234
while (endpos+1 < len) {
235
QChar ch3 = text[endpos];
236
QChar ch4 = text[endpos+1];
237
if ((ch3 == ' ' || ch3 == '\t' || ch3 == '\n') && !foundspace) {
238
tag = text.mid(pos+2, endpos-pos-2).lower();
240
} else if (ch3 == '?' && ch4 == '>') {
242
tag = text.mid(pos+2, endpos-pos-2).lower();
248
TextStructItem *item = new TextStructItem(currentItem);
249
item->tag = "<?" + tag + "?>";
251
item->endpos = endpos+1;
255
} else if (ch1 == '<' && ch2 == '!') {
257
// Processing instructions like !DOCTYPE
260
bool foundspace = false;
261
while (endpos+1 < len) {
262
QChar ch3 = text[endpos];
263
if ((ch3 == ' ' || ch3 == '\t' || ch3 == '\n') && !foundspace) {
264
tag = text.mid(pos+2, endpos-pos-2).lower();
266
} else if (ch3 == '>') {
268
tag = text.mid(pos+2, endpos-pos-2).lower();
274
TextStructItem *item = new TextStructItem(currentItem);
275
item->tag = "<!" + tag + ">";
277
item->endpos = endpos+1;
281
} else if (ch1 == '<' && ch2 == '/') {
285
while (endpos < len) {
286
QChar ch3 = text[endpos];
288
tag = text.mid(pos+2, endpos-pos-2).lower();
294
if (!m_relevantTags.contains(tag)) {
299
TextStructItem *closingItem = currentItem;
300
while (closingItem->parent() && closingItem->tag != tag)
301
closingItem = closingItem->parentStructItem();
302
if (closingItem->parent()) {
303
closingItem->endpos = endpos;
304
currentItem = closingItem->parentStructItem();
306
kdDebug(9030) << "found no opening tag " << tag << "." << endl;
311
} else if (ch1 == '<') {
315
bool foundspace = false;
316
while (endpos < len) {
317
QChar ch3 = text[endpos];
318
if ((ch3 == ' ' || ch3 == '\t' || ch3 == '\n') && !foundspace) {
319
tag = text.mid(pos+1, endpos-pos-1).lower();
321
} else if (ch3 == '>') {
323
tag = text.mid(pos+1, endpos-pos-1).lower();
330
if (!m_relevantTags.contains(tag)) {
335
TextStructItem *item = new TextStructItem(currentItem);
340
if (m_emptyTags.contains(tag))
341
item->endpos = endpos;
349
// firstChild()->setOpen(true);
350
QListViewItemIterator it(this);
351
for (; it.current(); ++it)
352
it.current()->setOpen(true);
356
void TextToolsWidget::parseLaTeX()
358
kdDebug(9030) << "Starting to parse LaTeX" << endl;
360
QString text = m_editIface->text();
363
TextStructItem *currentItem = new TextStructItem(this);
364
currentItem->tag = "Root";
365
currentItem->pos = -1;
366
currentItem->endpos = -1;
368
QString hierarchyLevels = "Root,chapter,section,subsection,subsubsection";
369
QRegExp re("\n[ \t]*s*\\\\(chapter|section|subsection|subsubsection)\\{([^}]*)\\}");
373
pos = re.search(text, pos);
376
QString tag = re.cap(1);
377
QString title = re.cap(2);
378
kdDebug(9030) << "Match with " << tag << " and title " << title << endl;
379
int level = hierarchyLevels.find(tag);
380
while (currentItem->parent() && level <= hierarchyLevels.find(currentItem->tag))
381
currentItem = currentItem->parentStructItem();
383
TextStructItem *item = new TextStructItem(currentItem);
387
item->endpos = pos+re.matchedLength()-1; // lie
389
if (level > hierarchyLevels.find(currentItem->tag))
392
pos = pos+re.matchedLength();
395
QListViewItemIterator it(this);
396
for (; it.current(); ++it)
397
it.current()->setOpen(true);
400
#include "texttoolswidget.moc"