00001
00002
00003
00004
00005
00006
00007
00008
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
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
00113 KTextEditor::Document * doc = static_cast<KTextEditor::Document*>( ro_part );
00114 connect( doc, SIGNAL( marksChanged() ), this, SLOT( marksEvent() ) );
00115
00116
00117 connect( doc, SIGNAL( completed() ), this, SLOT( reload() ) );
00118 }
00119 }
00120 }
00121
00122 void BookmarksPart::reload()
00123 {
00124
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
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
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
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
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
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
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
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
00359 return true;
00360 }
00361 return false;
00362 }
00363
00364
00365
00366
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
00387 return true;
00388 }
00389 return false;
00390 }
00391
00392 EditorData * BookmarksPart::storeBookmarksForURL( KParts::ReadOnlyPart * ro_part )
00393 {
00394
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
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
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
00518 while( n < endline )
00519 {
00520 list.append( " " );
00521 n++;
00522 }
00523
00524
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
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() )
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