KDevelop API Documentation

bookmarks_part.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2003 by Jens Dagerbo                                    *
00003  *   jens.dagerbo@swipnet.se                                               *
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 <qwhatsthis.h>
00013 #include <qvbox.h>
00014 #include <qtimer.h>
00015 #include <qtextstream.h>
00016 #include <qfile.h>
00017 
00018 #include <kdebug.h>
00019 #include <kiconloader.h>
00020 #include <klocale.h>
00021 #include <kdevgenericfactory.h>
00022 #include <ktexteditor/markinterface.h>
00023 #include <ktexteditor/editinterface.h>
00024 #include <ktexteditor/document.h>
00025 #include <kaction.h>
00026 #include <kdialogbase.h>
00027 
00028 #include <kdevpartcontroller.h>
00029 #include <kdevcore.h>
00030 #include <kdevmainwindow.h>
00031 #include "domutil.h"
00032 
00033 #include "bookmarks_widget.h"
00034 #include "bookmarks_part.h"
00035 #include "bookmarks_settings.h"
00036 #include "bookmarks_config.h"
00037 
00038 #include <configwidgetproxy.h>
00039 
00040 #define BOOKMARKSETTINGSPAGE 1
00041 
00042 typedef KDevGenericFactory<BookmarksPart> BookmarksFactory;
00043 static const KAboutData data("kdevbookmarks", I18N_NOOP("Bookmarks"), "1.0");
00044 K_EXPORT_COMPONENT_FACTORY( libkdevbookmarks, BookmarksFactory( &data ) )
00045 
00046 BookmarksPart::BookmarksPart(QObject *parent, const char *name, const QStringList& )
00047     : KDevPlugin("bookmarks", "bookmark", parent, name ? name : "BookmarksPart" )
00048 {
00049     setInstance(BookmarksFactory::instance());
00050 
00051     _widget = new BookmarksWidget(this);
00052 
00053     _widget->setCaption(i18n("Bookmarks"));
00054     _widget->setIcon(SmallIcon( icon() ));
00055 
00056     _marksChangeTimer = new QTimer( this );
00057 
00058     QWhatsThis::add(_widget, i18n("<b>Bookmarks</b><p>"
00059             "The bookmark viewer shows all the source bookmarks in the project."));
00060 
00061     mainWindow()->embedSelectView(_widget, i18n("Bookmarks"), i18n("Source bookmarks"));
00062 
00063     _editorMap.setAutoDelete( true );
00064     _settingMarks = false;
00065 
00066     connect( partController(), SIGNAL( partAdded( KParts::Part * ) ), this, SLOT( partAdded( KParts::Part * ) ) );
00067 
00068     _configProxy = new ConfigWidgetProxy( core() );
00069     _configProxy->createProjectConfigPage( i18n("Bookmarks"), BOOKMARKSETTINGSPAGE, icon() );
00070     connect( _configProxy, SIGNAL(insertConfigWidget(const KDialogBase*, QWidget*, unsigned int )),
00071         this, SLOT(insertConfigWidget(const KDialogBase*, QWidget*, unsigned int )) );
00072 
00073     connect( _widget, SIGNAL( removeAllBookmarksForURL( const KURL & ) ),
00074         this, SLOT( removeAllBookmarksForURL( const KURL & ) ) );
00075     connect( _widget, SIGNAL( removeBookmarkForURL( const KURL &, int ) ),
00076         this, SLOT( removeBookmarkForURL( const KURL &, int ) ) );
00077 
00078     connect( _marksChangeTimer, SIGNAL( timeout() ), this, SLOT( marksChanged() ) );
00079 
00080     _config = new BookmarksConfig;
00081     _config->readConfig();
00082 
00083     storeBookmarksForAllURLs();
00084     updateContextStringForAll();
00085     _widget->update( _editorMap );
00086 }
00087 
00088 BookmarksPart::~BookmarksPart()
00089 {
00090     if( _widget ) {
00091         mainWindow()->removeView( _widget );
00092         delete _widget;
00093     }
00094     delete _config;
00095     delete _configProxy;
00096 }
00097 
00098 void BookmarksPart::partAdded( KParts::Part * part )
00099 {
00100     //kdDebug(0) << "BookmarksPart::partAdded()" << endl;
00101 
00102     if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( part ) )
00103     {
00104         if ( setBookmarksForURL( ro_part ) )
00105         {
00106             updateContextStringForURL( ro_part );
00107             if ( EditorData * data = _editorMap.find( ro_part->url().path() ) )
00108             {
00109                 _widget->updateURL( data );
00110             }
00111 
00112             // connect to this editor
00113             KTextEditor::Document * doc = static_cast<KTextEditor::Document*>( ro_part );
00114             connect( doc, SIGNAL( marksChanged() ), this, SLOT( marksEvent() ) );
00115 
00116             // workaround for a katepart oddity where it drops all bookmarks on 'reload'
00117             connect( doc, SIGNAL( completed() ), this, SLOT( reload() ) );
00118         }
00119     }
00120 }
00121 
00122 void BookmarksPart::reload()
00123 {
00124     //kdDebug(0) << "BookmarksPart::reload()" << endl;
00125 
00126     QObject * senderobj = const_cast<QObject*>( sender() );
00127     if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( senderobj ) )
00128     {
00129         if ( partIsSane( ro_part ) )
00130         {
00131             setBookmarksForURL( ro_part );
00132         }
00133     }
00134 }
00135 
00136 void BookmarksPart::marksEvent()
00137 {
00138     //kdDebug(0) << "BookmarksPart::marksEvent()" << endl;
00139 
00140     if ( ! _settingMarks )
00141     {
00142         QObject * senderobj = const_cast<QObject*>( sender() );
00143         KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( senderobj );
00144 
00145         if ( partIsSane( ro_part ) && !_dirtyParts.contains( ro_part ) )
00146         {
00147             _dirtyParts.push_back( ro_part );
00148             _marksChangeTimer->start( 1000, true );
00149         }
00150     }
00151 }
00152 
00153 void BookmarksPart::marksChanged()
00154 {
00155     //kdDebug(0) << "BookmarksPart::marksChanged()" << endl;
00156 
00157     QValueListIterator<KParts::ReadOnlyPart*> it = _dirtyParts.begin();
00158     while ( it != _dirtyParts.end() )
00159     {
00160         KParts::ReadOnlyPart * ro_part = *it;
00161         if ( partIsSane( ro_part ) )
00162         {
00163             if ( dynamic_cast<KTextEditor::MarkInterface*>( ro_part ) )
00164             {
00165                 if ( EditorData * data = storeBookmarksForURL( ro_part ) )
00166                 {
00167                     updateContextStringForURL( ro_part );
00168                     _widget->updateURL( data );
00169                 }
00170                 else
00171                 {
00172                     _widget->removeURL( ro_part->url() );
00173                 }
00174             }
00175         }
00176         ++it;
00177     }
00178     _dirtyParts.clear();
00179 }
00180 
00181 void BookmarksPart::restorePartialProjectSession( const QDomElement * el )
00182 {
00183     //kdDebug(0) << "BookmarksPart::restorePartialProjectSession()" << endl;
00184 
00185     if ( ! el ) return;
00186 
00187     QDomElement bookmarksList = el->namedItem( "bookmarks" ).toElement();
00188     if ( bookmarksList.isNull() ) return;
00189 
00190     QDomElement bookmark = bookmarksList.firstChild().toElement();
00191     while ( ! bookmark.isNull() )
00192     {
00193         QString path = bookmark.attribute( "url" );
00194         if ( path != QString::null )
00195         {
00196             EditorData * data = new EditorData;
00197             data->url.setPath( path );
00198 
00199             QDomElement mark = bookmark.firstChild().toElement();
00200             while ( ! mark.isNull() )
00201             {
00202                 QString line = mark.attribute( "line" );
00203                 if ( line != QString::null )
00204                 {
00205                     data->marks.append( qMakePair( line.toInt(), QString() ) );
00206                 }
00207                 mark = mark.nextSibling().toElement();
00208             }
00209 
00210             if ( ! data->marks.isEmpty() )
00211             {
00212                 _editorMap.insert( data->url.path(), data );
00213             }
00214             else
00215             {
00216                 delete data;
00217             }
00218         }
00219         bookmark = bookmark.nextSibling().toElement();
00220     }
00221     setBookmarksForAllURLs();
00222     updateContextStringForAll();
00223     _widget->update( _editorMap );
00224 }
00225 
00226 void BookmarksPart::savePartialProjectSession( QDomElement * el )
00227 {
00228     //kdDebug(0) << "BookmarksPart::savePartialProjectSession()" << endl;
00229 
00230     if ( ! el ) return;
00231 
00232     QDomDocument domDoc = el->ownerDocument();
00233     if ( domDoc.isNull() ) return;
00234 
00235     QDomElement bookmarksList = domDoc.createElement( "bookmarks" );
00236 
00237     QDictIterator<EditorData> it( _editorMap );
00238     while ( it.current() )
00239     {
00240         QDomElement bookmark = domDoc.createElement( "bookmark" );
00241         bookmark.setAttribute( "url", it.current()->url.path() );
00242         bookmarksList.appendChild( bookmark );
00243 
00244         QValueListIterator< QPair<int,QString> > it2 = it.current()->marks.begin();
00245         while ( it2 != it.current()->marks.end() )
00246         {
00247             QDomElement line = domDoc.createElement( "mark" );
00248             line.setAttribute( "line", (*it2).first );
00249             bookmark.appendChild( line );
00250             ++it2;
00251         }
00252         ++it;
00253     }
00254 
00255     if ( ! bookmarksList.isNull() )
00256     {
00257         el->appendChild( bookmarksList );
00258     }
00259 }
00260 
00261 void BookmarksPart::removeAllBookmarksForURL( KURL const & url )
00262 {
00263     //kdDebug(0) << "BookmarksPart::removeAllBookmarksForURL()" << endl;
00264 
00265     _editorMap.remove( url.path() );
00266 
00267     setBookmarksForURL( partForURL( url ) );
00268     _widget->removeURL( url );
00269 }
00270 
00271 void BookmarksPart::removeBookmarkForURL( KURL const & url, int line )
00272 {
00273     //kdDebug(0) << "BookmarksPart::removeBookmarkForURL()" << endl;
00274 
00275     if ( EditorData * data = _editorMap.find( url.path() ) )
00276     {
00277         QValueListIterator< QPair<int,QString> > it = data->marks.begin();
00278         while ( it != data->marks.end() )
00279         {
00280             if ( (*it).first == line )
00281             {
00282                 data->marks.remove( it );
00283                 break;
00284             }
00285             ++it;
00286         }
00287 
00288         if ( data->marks.isEmpty() )
00289         {
00290             removeAllBookmarksForURL( url );
00291         }
00292         else
00293         {
00294             setBookmarksForURL( partForURL( url ) );
00295             _widget->updateURL( data );
00296         }
00297     }
00298 }
00299 
00300 void BookmarksPart::updateContextStringForURL( KParts::ReadOnlyPart * ro_part )
00301 {
00302     if ( ! ro_part ) return;
00303 
00304     KTextEditor::EditInterface * ed =
00305         dynamic_cast<KTextEditor::EditInterface *>( ro_part );
00306 
00307     EditorData * data = _editorMap.find( ro_part->url().path() );
00308 
00309     if ( ! ( data && ed ) ) return;
00310 
00311     QValueListIterator< QPair<int,QString> > it = data->marks.begin();
00312     while ( it != data->marks.end() )
00313     {
00314         (*it).second = ed->textLine( (*it).first );
00315         ++it;
00316     }
00317 }
00318 
00319 void BookmarksPart::updateContextStringForURL( KURL const & url )
00320 {
00321     updateContextStringForURL( partForURL( url ) );
00322 }
00323 
00324 void BookmarksPart::updateContextStringForAll()
00325 {
00326     QDictIterator<EditorData> it( _editorMap );
00327     while ( it.current() )
00328     {
00329         if ( ! it.current()->marks.isEmpty() )
00330         {
00331             updateContextStringForURL( it.current()->url );
00332         }
00333         ++it;
00334     }
00335 }
00336 
00337 bool BookmarksPart::setBookmarksForURL( KParts::ReadOnlyPart * ro_part )
00338 {
00339     if ( KTextEditor::MarkInterface * mi = dynamic_cast<KTextEditor::MarkInterface *>(ro_part) )
00340     {
00341         clearBookmarksForURL( ro_part );
00342 
00343         _settingMarks = true;
00344 
00345         if ( EditorData * data = _editorMap.find( ro_part->url().path() ) )
00346         {
00347             // we've seen this one before, apply stored bookmarks
00348 
00349             QValueListIterator< QPair<int,QString> > it = data->marks.begin();
00350             while ( it != data->marks.end() )
00351             {
00352                 mi->addMark( (*it).first, KTextEditor::MarkInterface::markType01 );
00353                 ++it;
00354             }
00355         }
00356         _settingMarks = false;
00357 
00358         // true == this is a MarkInterface
00359         return true;
00360     }
00361     return false;
00362 }
00363 
00364 // Note: This method is only a convenience method to clear the bookmark marks,
00365 // the way a hypothetical KTextEditor::MarkInterface::clearMarks( uint markType )
00366 // would work.
00367 bool BookmarksPart::clearBookmarksForURL( KParts::ReadOnlyPart * ro_part )
00368 {
00369     if ( KTextEditor::MarkInterface * mi = dynamic_cast<KTextEditor::MarkInterface *>(ro_part) )
00370     {
00371         _settingMarks = true;
00372 
00373         QPtrList<KTextEditor::Mark> marks = mi->marks();
00374         QPtrListIterator<KTextEditor::Mark> it( marks );
00375         while ( it.current() )
00376         {
00377             if ( it.current()->type & KTextEditor::MarkInterface::markType01 )
00378             {
00379                 mi->removeMark( it.current()->line, KTextEditor::MarkInterface::markType01 );
00380             }
00381             ++it;
00382         }
00383 
00384         _settingMarks = false;
00385 
00386         // true == this is a MarkInterface
00387         return true;
00388     }
00389     return false;
00390 }
00391 
00392 EditorData * BookmarksPart::storeBookmarksForURL( KParts::ReadOnlyPart * ro_part )
00393 {
00394     //kdDebug(0) << "BookmarksPart::storeBookmarksForURL()" << endl;
00395 
00396     if ( KTextEditor::MarkInterface * mi = dynamic_cast<KTextEditor::MarkInterface *>( ro_part ) )
00397     {
00398         EditorData * data = new EditorData;
00399         data->url = ro_part->url();
00400 
00401         // removing previous data for this url, if any
00402         _editorMap.remove( data->url.path() );
00403 
00404         QPtrList<KTextEditor::Mark> marks = mi->marks();
00405         QPtrListIterator<KTextEditor::Mark> it( marks );
00406         while ( it.current() )
00407         {
00408             if ( it.current()->type & KTextEditor::MarkInterface::markType01 )
00409             {
00410                 int line = it.current()->line;
00411                 data->marks.append( qMakePair( line, QString() ) );
00412             }
00413             ++it;
00414         }
00415 
00416         if ( ! data->marks.isEmpty() )
00417         {
00418             _editorMap.insert( data->url.path(), data );
00419         }
00420         else
00421         {
00422             delete data;
00423             data = 0;
00424         }
00425         return data;
00426     }
00427     return 0;
00428 }
00429 
00430 void BookmarksPart::setBookmarksForAllURLs()
00431 {
00432     if( const QPtrList<KParts::Part> * partlist = partController()->parts() )
00433     {
00434         QPtrListIterator<KParts::Part> it( *partlist );
00435         while ( KParts::Part* part = it.current() )
00436         {
00437             if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( part ) )
00438             {
00439                 setBookmarksForURL( ro_part );
00440             }
00441             ++it;
00442         }
00443     }
00444 }
00445 
00446 void BookmarksPart::storeBookmarksForAllURLs()
00447 {
00448     if( const QPtrList<KParts::Part> * partlist = partController()->parts() )
00449     {
00450         QPtrListIterator<KParts::Part> it( *partlist );
00451         while ( KParts::Part* part = it.current() )
00452         {
00453             if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( part ) )
00454             {
00455                 storeBookmarksForURL( ro_part );
00456             }
00457             ++it;
00458         }
00459     }
00460 }
00461 
00462 // reimplemented from PartController::partForURL to avoid linking
00463 KParts::ReadOnlyPart * BookmarksPart::partForURL( KURL const & url )
00464 {
00465     QPtrListIterator<KParts::Part> it( *partController()->parts() );
00466     while( it.current() )
00467     {
00468         KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(it.current());
00469         if (ro_part && url == ro_part->url())
00470         {
00471             return ro_part;
00472         }
00473         ++it;
00474     }
00475     return 0;
00476 }
00477 
00478 bool BookmarksPart::partIsSane( KParts::ReadOnlyPart * ro_part )
00479 {
00480     return ( ro_part != 0 ) &&
00481             partController()->parts()->contains( ro_part) &&
00482             !ro_part->url().path().isEmpty();
00483 }
00484 
00485 void BookmarksPart::insertConfigWidget( const KDialogBase * dlg, QWidget * page, unsigned int pagenumber )
00486 {
00487     kdDebug() << k_funcinfo << endl;
00488 
00489     if ( pagenumber == BOOKMARKSETTINGSPAGE )
00490     {
00491         BookmarkSettings * w = new BookmarkSettings( this, page );
00492         connect( dlg, SIGNAL(okClicked()), w, SLOT(slotAccept()) );
00493     }
00494 }
00495 
00497 
00498 QStringList BookmarksPart::getContextFromStream( QTextStream & istream, unsigned int line, unsigned int context )
00499 {
00500     kdDebug() << k_funcinfo << endl;
00501 
00502     int startline = context > line ? 0 : line - context;
00503     int endline = line + context;
00504 
00505     int n = 0;
00506     QStringList list;
00507     while ( !istream.atEnd() )
00508     {
00509         QString templine = istream.readLine();
00510         if ( (n >= startline) && ( n <= endline ) )
00511         {
00512             list << templine;
00513         }
00514         n++;
00515     }
00516 
00517     // maybe pad empty lines to the tail
00518     while( n < endline )
00519     {
00520         list.append( " " );
00521         n++;
00522     }
00523 
00524     // maybe pad empty lines to the head
00525     while( list.count() < ( context * 2 + 1) )
00526     {
00527         list.prepend( " " );
00528     }
00529 
00530     return list;
00531 }
00532 
00533 QStringList BookmarksPart::getContext( KURL const & url, unsigned int line, unsigned int context )
00534 {
00535     // if the file is open - get the line from the editor buffer
00536     if ( KTextEditor::EditInterface * ei = dynamic_cast<KTextEditor::EditInterface*>( partForURL( url ) ) )
00537     {
00538         kdDebug() << "the file is open - get the line from the editor buffer" << endl;
00539 
00540         QString ibuffer = ei->text();
00541         QTextStream istream( &ibuffer, IO_ReadOnly );
00542         return getContextFromStream( istream, line, context );
00543     }
00544     else if ( url.isLocalFile() ) // else the file is not open - get the line from the file on disk
00545     {
00546         kdDebug() << "the file is not open - get the line from the file on disk" << endl;
00547 
00548         QFile file( url.path() );
00549         QString buffer;
00550 
00551         if ( file.open( IO_ReadOnly ) )
00552         {
00553             QTextStream istream( &file );
00554             return getContextFromStream( istream, line, context );
00555         }
00556     }
00557     return QStringList( i18n("Could not find file") );
00558 }
00559 
00560 BookmarksConfig * BookmarksPart::config( )
00561 {
00562     return _config;
00563 }
00564 
00565 #include "bookmarks_part.moc"
00566 
00567 // kate: space-indent off; indent-width 4; tab-width 4; show-tabs off;
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:37 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003