KDevelop API Documentation

texttoolswidget.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2002 by Bernd Gehrmann                                  *
00003  *   bernd@kdevelop.org                                                    *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
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     //    connect( this, SIGNAL(doubleClicked(QListViewItem*)),
00074     //             this, SLOT(slotItemPressed(int,QListViewItem*)) );
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             // PHP and other similar stuff
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             // Processing instructions like !DOCTYPE
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     //    firstChild()->setOpen(true);
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; // lie
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"
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Feb 22 09:22:42 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003