00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
#include "texttoolswidget.h"
00013
00014
#include <qheader.h>
00015
#include <qregexp.h>
00016
#include <qtimer.h>
00017
#include <kdebug.h>
00018
#include <klocale.h>
00019
#include <kparts/part.h>
00020
#include <kpopupmenu.h>
00021
#include <ktexteditor/viewcursorinterface.h>
00022
#include <ktexteditor/selectioninterface.h>
00023
#include <ktexteditor/editinterface.h>
00024
00025
#include "kdevmainwindow.h"
00026
#include "kdevpartcontroller.h"
00027
#include "texttoolspart.h"
00028
00029
00030 class TextStructItem :
public QListViewItem
00031 {
00032
public:
00033 TextStructItem(
QListView *parent)
00034 :
QListViewItem(parent)
00035 {}
00036 TextStructItem(
QListViewItem *parent)
00037 :
QListViewItem(parent)
00038 {
00039
QListViewItem *item =
this;
00040
while (item->nextSibling())
00041 item = item->nextSibling();
00042
if (item !=
this)
00043 moveItem(item);
00044 }
00045
00046 QString text(
int)
const
00047
{
00048
return extra.isNull()?
tag :
QString(
"%1: %2").arg(
tag).arg(
extra);
00049 }
00050 TextStructItem *
parentStructItem()
00051 {
return static_cast<TextStructItem*>(parent()); }
00052
00053 QString tag;
00054 QString extra;
00055 int pos;
00056 int endpos;
00057 };
00058
00059
00060 TextToolsWidget::TextToolsWidget(
TextToolsPart *part,
QWidget *parent,
const char *name)
00061 :
KListView(parent, name)
00062 {
00063 setResizeMode(QListView::LastColumn);
00064 setSorting(-1);
00065 header()->hide();
00066 addColumn(QString::null);
00067
00068
m_part = part;
00069
00070
m_timer =
new QTimer(
this);
00071 connect(
this, SIGNAL(mouseButtonPressed(
int,
QListViewItem*,
const QPoint&,
int)),
00072
this, SLOT(
slotItemPressed(
int,
QListViewItem*)) );
00073
00074
00075 connect(
this, SIGNAL(returnPressed(
QListViewItem*)),
00076
this, SLOT(
slotReturnPressed(
QListViewItem*)) );
00077 connect(
this, SIGNAL(contextMenu(
KListView*,
QListViewItem*,
const QPoint&)),
00078
this, SLOT(
slotContextMenu(
KListView*,
QListViewItem*,
const QPoint&)) );
00079 }
00080
00081
00082 TextToolsWidget::~TextToolsWidget()
00083 {}
00084
00085
00086 void TextToolsWidget::slotItemPressed(
int button,
QListViewItem *item)
00087 {
00088
if (!item)
00089
return;
00090
00091
TextStructItem *tsitem = static_cast<TextStructItem*>(item);
00092
int searchedPos = tsitem->
pos;
00093
int searchedEndpos = tsitem->
endpos;
00094
kdDebug(9030) <<
"Searched pos " << searchedPos <<
", " << searchedEndpos <<
endl;
00095
00096
int endline = 0;
00097
int endcol = 0;
00098
int line = 0;
00099
int col = 0;
00100
00101
int len =
m_cachedText.length();
00102
int pos = 0;
00103
while (pos <
len) {
00104
if (pos == searchedPos) {
00105 line = endline;
00106 col = endcol;
00107 }
00108
if (pos == searchedEndpos)
00109
break;
00110
QChar ch =
m_cachedText[pos];
00111
if (ch ==
'\n') {
00112 ++endline;
00113 endcol = 0;
00114 }
else {
00115 ++endcol;
00116 }
00117 ++pos;
00118 }
00119
00120
KParts::Part *rwpart
00121 = dynamic_cast<KParts::Part*>(
m_part->
partController()->
activePart());
00122
QWidget *view =
m_part->
partController()->
activeWidget();
00123
00124
KTextEditor::ViewCursorInterface *cursorIface
00125 = dynamic_cast<KTextEditor::ViewCursorInterface*>(view);
00126
if (cursorIface) {
00127
kdDebug(9030) <<
"set cursor " << line <<
", " << col <<
endl;
00128 cursorIface->
setCursorPosition(line, col);
00129 }
00130
00131
if (button == MidButton) {
00132
KTextEditor::SelectionInterface *selectionIface
00133 = dynamic_cast<KTextEditor::SelectionInterface*>(rwpart);
00134
if (selectionIface) {
00135
kdDebug(9030) <<
"set selection " << line <<
", " << col
00136 <<
", " << endline <<
", " << endcol <<
endl;
00137 selectionIface->
setSelection((
int)line, (
int)col, (
int)endline, (
int)endcol+1);
00138 }
00139 }
00140
00141
m_part->
mainWindow()->
lowerView(
this);
00142 }
00143
00144
00145 void TextToolsWidget::slotReturnPressed(
QListViewItem *item)
00146 {
00147
slotItemPressed(LeftButton, item);
00148 }
00149
00150
00151 void TextToolsWidget::slotContextMenu(
KListView *,
QListViewItem *item,
const QPoint &)
00152 {
00153
if (!item)
00154
return;
00155
00156
#if 0
00157
KPopupMenu popup(i18n(
"Text Structure"),
this);
00158 popup.exec(p);
00159
#endif
00160
}
00161
00162
00163 void TextToolsWidget::stop()
00164 {
00165 disconnect(
m_timer );
00166
m_relevantTags.clear();
00167
m_emptyTags.clear();
00168
m_cachedText = QString::null;
00169 }
00170
00171
00172 void TextToolsWidget::setMode(Mode mode,
KParts::Part *part)
00173 {
00174 connect( part, SIGNAL(textChanged()),
00175
this, SLOT(
startTimer()) );
00176
m_editIface = dynamic_cast<KTextEditor::EditInterface*>(part);
00177
00178
switch (mode) {
00179
case HTML:
00180
m_relevantTags <<
"h1" <<
"h2" <<
"h3" <<
"h4"
00181 <<
"table" <<
"tr";
00182
m_emptyTags <<
"br" <<
"hr" <<
"img" <<
"input" <<
"p" <<
"meta";
00183
00184 connect(
m_timer, SIGNAL(timeout()),
00185
this, SLOT(
parseXML()) );
00186
break;
00187
case Docbook:
00188
m_relevantTags <<
"chapter" <<
"sect1" <<
"sect2"
00189 <<
"para" <<
"formalpara";
00190 connect(
m_timer, SIGNAL(timeout()),
00191
this, SLOT(
parseXML()) );
00192
break;
00193
case LaTeX:
00194 connect(
m_timer, SIGNAL(timeout()),
00195
this, SLOT(
parseLaTeX()) );
00196
break;
00197
default: ;
00198 }
00199
00200
m_timer->start(0,
true);
00201 }
00202
00203
00204 void TextToolsWidget::startTimer()
00205 {
00206
kdDebug(9030) <<
"Starting parse timer" <<
endl;
00207
m_timer->start(1000,
true);
00208 }
00209
00210
00211 void TextToolsWidget::parseXML()
00212 {
00213
kdDebug(9030) <<
"Starting to parse XML" <<
endl;
00214 clear();
00215
QString text =
m_editIface->
text();
00216
m_cachedText =
text;
00217
00218
TextStructItem *currentItem =
new TextStructItem(
this);
00219 currentItem->
tag =
"Root";
00220 currentItem->
pos = -1;
00221 currentItem->
endpos = -1;
00222
00223
int len =
text.length();
00224
for (
int pos=0; pos+1 <
len; ++pos) {
00225
QChar ch1 =
text[pos];
00226
QChar ch2 =
text[pos+1];
00227
00228
if (ch1 ==
'<' && ch2 ==
'?') {
00229
00230
00231
QString tag;
00232
int endpos = pos+2;
00233
bool foundspace =
false;
00234
while (endpos+1 <
len) {
00235
QChar ch3 =
text[endpos];
00236
QChar ch4 =
text[endpos+1];
00237
if ((ch3 ==
' ' || ch3 ==
'\t' || ch3 ==
'\n') && !foundspace) {
00238 tag =
text.mid(pos+2, endpos-pos-2).lower();
00239 foundspace =
true;
00240 }
else if (ch3 ==
'?' && ch4 ==
'>') {
00241
if (!foundspace)
00242 tag =
text.mid(pos+2, endpos-pos-2).lower();
00243
break;
00244 }
00245 ++endpos;
00246 }
00247
00248 TextStructItem *item =
new TextStructItem(currentItem);
00249 item->
tag =
"<?" + tag +
"?>";
00250 item->
pos = pos;
00251 item->
endpos = endpos+1;
00252
00253 pos = endpos+1;
00254
00255 }
else if (ch1 ==
'<' && ch2 ==
'!') {
00256
00257
00258
QString tag;
00259
int endpos = pos+2;
00260
bool foundspace =
false;
00261
while (endpos+1 <
len) {
00262
QChar ch3 =
text[endpos];
00263
if ((ch3 ==
' ' || ch3 ==
'\t' || ch3 ==
'\n') && !foundspace) {
00264 tag =
text.mid(pos+2, endpos-pos-2).lower();
00265 foundspace =
true;
00266 }
else if (ch3 ==
'>') {
00267
if (!foundspace)
00268 tag =
text.mid(pos+2, endpos-pos-2).lower();
00269
break;
00270 }
00271 ++endpos;
00272 }
00273
00274 TextStructItem *item =
new TextStructItem(currentItem);
00275 item->
tag =
"<!" + tag +
">";
00276 item->
pos = pos;
00277 item->
endpos = endpos+1;
00278
00279 pos = endpos+1;
00280
00281 }
else if (ch1 ==
'<' && ch2 ==
'/') {
00282
00283
QString tag;
00284
int endpos = pos+2;
00285
while (endpos <
len) {
00286
QChar ch3 =
text[endpos];
00287
if (ch3 ==
'>') {
00288 tag =
text.mid(pos+2, endpos-pos-2).lower();
00289
break;
00290 }
00291 ++endpos;
00292 }
00293
00294
if (!
m_relevantTags.contains(tag)) {
00295 pos = endpos;
00296
continue;
00297 }
00298
00299 TextStructItem *closingItem = currentItem;
00300
while (closingItem->parent() && closingItem->
tag != tag)
00301 closingItem = closingItem->
parentStructItem();
00302
if (closingItem->parent()) {
00303 closingItem->
endpos = endpos;
00304 currentItem = closingItem->
parentStructItem();
00305 }
else {
00306
kdDebug(9030) <<
"found no opening tag " << tag <<
"." <<
endl;
00307 }
00308
00309 pos = endpos;
00310
00311 }
else if (ch1 ==
'<') {
00312
00313
QString tag;
00314
int endpos = pos+1;
00315
bool foundspace =
false;
00316
while (endpos <
len) {
00317
QChar ch3 =
text[endpos];
00318
if ((ch3 ==
' ' || ch3 ==
'\t' || ch3 ==
'\n') && !foundspace) {
00319 tag =
text.mid(pos+1, endpos-pos-1).lower();
00320 foundspace =
true;
00321 }
else if (ch3 ==
'>') {
00322
if (!foundspace) {
00323 tag =
text.mid(pos+1, endpos-pos-1).lower();
00324 }
00325
break;
00326 }
00327 ++endpos;
00328 }
00329
00330
if (!
m_relevantTags.contains(tag)) {
00331 pos = endpos;
00332
continue;
00333 }
00334
00335 TextStructItem *item =
new TextStructItem(currentItem);
00336 item->
tag = tag;
00337 item->
pos = pos;
00338 item->
endpos = -1;
00339
00340
if (
m_emptyTags.contains(tag))
00341 item->
endpos = endpos;
00342
else
00343 currentItem = item;
00344 pos = endpos;
00345
00346 }
00347 }
00348
00349
00350
QListViewItemIterator it(
this);
00351
for (; it.current(); ++it)
00352 it.current()->setOpen(
true);
00353 }
00354
00355
00356 void TextToolsWidget::parseLaTeX()
00357 {
00358
kdDebug(9030) <<
"Starting to parse LaTeX" <<
endl;
00359 clear();
00360
QString text =
m_editIface->
text();
00361
m_cachedText =
text;
00362
00363
TextStructItem *currentItem =
new TextStructItem(
this);
00364 currentItem->
tag =
"Root";
00365 currentItem->
pos = -1;
00366 currentItem->
endpos = -1;
00367
00368
QString hierarchyLevels =
"Root,chapter,section,subsection,subsubsection";
00369
QRegExp re(
"\n[ \t]*s*\\\\(chapter|section|subsection|subsubsection)\\{([^}]*)\\}");
00370
00371
int pos=0;
00372
for (;;) {
00373 pos = re.search(
text, pos);
00374
if (pos == -1)
00375
break;
00376
QString tag = re.cap(1);
00377
QString title = re.cap(2);
00378
kdDebug(9030) <<
"Match with " << tag <<
" and title " << title <<
endl;
00379
int level = hierarchyLevels.find(tag);
00380
while (currentItem->parent() && level <= hierarchyLevels.find(currentItem->
tag))
00381 currentItem = currentItem->
parentStructItem();
00382
00383 TextStructItem *item =
new TextStructItem(currentItem);
00384 item->
tag = tag;
00385 item->
extra = title;
00386 item->
pos = pos+1;
00387 item->
endpos = pos+re.matchedLength()-1;
00388
00389
if (level > hierarchyLevels.find(currentItem->
tag))
00390 currentItem = item;
00391
00392 pos = pos+re.matchedLength();
00393 }
00394
00395
QListViewItemIterator it(
this);
00396
for (; it.current(); ++it)
00397 it.current()->setOpen(
true);
00398 }
00399
00400
#include "texttoolswidget.moc"