1
/***************************************************************************
2
* Copyright (C) 2003 by Jens Dagerbo *
3
* jens.dagerbo@swipnet.se *
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 <qwhatsthis.h>
15
#include <qtextstream.h>
19
#include <kiconloader.h>
21
#include <kdevgenericfactory.h>
22
#include <ktexteditor/markinterface.h>
23
#include <ktexteditor/editinterface.h>
24
#include <ktexteditor/document.h>
26
#include <kdialogbase.h>
28
#include <kdevpartcontroller.h>
30
#include <kdevmainwindow.h>
33
#include "bookmarks_widget.h"
34
#include "bookmarks_part.h"
35
#include "bookmarks_settings.h"
36
#include "bookmarks_config.h"
38
#include <configwidgetproxy.h>
39
#include <kdevplugininfo.h>
41
#define BOOKMARKSETTINGSPAGE 1
43
typedef KDevGenericFactory<BookmarksPart> BookmarksFactory;
44
static const KDevPluginInfo data("kdevbookmarks");
45
K_EXPORT_COMPONENT_FACTORY( libkdevbookmarks, BookmarksFactory( data ) )
47
BookmarksPart::BookmarksPart(QObject *parent, const char *name, const QStringList& )
48
: KDevPlugin(&data, parent, name ? name : "BookmarksPart" )
50
setInstance(BookmarksFactory::instance());
52
_widget = new BookmarksWidget(this);
54
_widget->setCaption(i18n("Bookmarks"));
55
_widget->setIcon(SmallIcon( info()->icon() ));
57
_marksChangeTimer = new QTimer( this );
59
QWhatsThis::add(_widget, i18n("<b>Bookmarks</b><p>"
60
"The bookmark viewer shows all the source bookmarks in the project."));
62
mainWindow()->embedSelectView(_widget, i18n("Bookmarks"), i18n("Source bookmarks"));
64
_editorMap.setAutoDelete( true );
65
_settingMarks = false;
67
connect( partController(), SIGNAL( partAdded( KParts::Part * ) ), this, SLOT( partAdded( KParts::Part * ) ) );
69
_configProxy = new ConfigWidgetProxy( core() );
70
_configProxy->createProjectConfigPage( i18n("Bookmarks"), BOOKMARKSETTINGSPAGE, info()->icon() );
71
connect( _configProxy, SIGNAL(insertConfigWidget(const KDialogBase*, QWidget*, unsigned int )),
72
this, SLOT(insertConfigWidget(const KDialogBase*, QWidget*, unsigned int )) );
74
connect( _widget, SIGNAL( removeAllBookmarksForURL( const KURL & ) ),
75
this, SLOT( removeAllBookmarksForURL( const KURL & ) ) );
76
connect( _widget, SIGNAL( removeBookmarkForURL( const KURL &, int ) ),
77
this, SLOT( removeBookmarkForURL( const KURL &, int ) ) );
79
connect( _marksChangeTimer, SIGNAL( timeout() ), this, SLOT( marksChanged() ) );
81
_config = new BookmarksConfig;
82
_config->readConfig();
84
storeBookmarksForAllURLs();
85
updateContextStringForAll();
86
_widget->update( _editorMap );
89
BookmarksPart::~BookmarksPart()
92
mainWindow()->removeView( _widget );
99
void BookmarksPart::partAdded( KParts::Part * part )
101
//kdDebug(0) << "BookmarksPart::partAdded()" << endl;
103
if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( part ) )
105
if ( setBookmarksForURL( ro_part ) )
107
updateContextStringForURL( ro_part );
108
if ( EditorData * data = _editorMap.find( ro_part->url().path() ) )
110
_widget->updateURL( data );
113
// connect to this editor
114
KTextEditor::Document * doc = static_cast<KTextEditor::Document*>( ro_part );
115
connect( doc, SIGNAL( marksChanged() ), this, SLOT( marksEvent() ) );
117
// workaround for a katepart oddity where it drops all bookmarks on 'reload'
118
connect( doc, SIGNAL( completed() ), this, SLOT( reload() ) );
123
void BookmarksPart::reload()
125
//kdDebug(0) << "BookmarksPart::reload()" << endl;
127
QObject * senderobj = const_cast<QObject*>( sender() );
128
if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( senderobj ) )
130
if ( partIsSane( ro_part ) )
132
setBookmarksForURL( ro_part );
137
void BookmarksPart::marksEvent()
139
//kdDebug(0) << "BookmarksPart::marksEvent()" << endl;
141
if ( ! _settingMarks )
143
QObject * senderobj = const_cast<QObject*>( sender() );
144
KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( senderobj );
146
if ( partIsSane( ro_part ) && !_dirtyParts.contains( ro_part ) )
148
_dirtyParts.push_back( ro_part );
149
_marksChangeTimer->start( 1000, true );
154
void BookmarksPart::marksChanged()
156
//kdDebug(0) << "BookmarksPart::marksChanged()" << endl;
158
QValueListIterator<KParts::ReadOnlyPart*> it = _dirtyParts.begin();
159
while ( it != _dirtyParts.end() )
161
KParts::ReadOnlyPart * ro_part = *it;
162
if ( partIsSane( ro_part ) )
164
if ( dynamic_cast<KTextEditor::MarkInterface*>( ro_part ) )
166
if ( EditorData * data = storeBookmarksForURL( ro_part ) )
168
updateContextStringForURL( ro_part );
169
_widget->updateURL( data );
173
_widget->removeURL( ro_part->url() );
182
void BookmarksPart::restorePartialProjectSession( const QDomElement * el )
184
//kdDebug(0) << "BookmarksPart::restorePartialProjectSession()" << endl;
188
QDomElement bookmarksList = el->namedItem( "bookmarks" ).toElement();
189
if ( bookmarksList.isNull() ) return;
191
QDomElement bookmark = bookmarksList.firstChild().toElement();
192
while ( ! bookmark.isNull() )
194
QString path = bookmark.attribute( "url" );
195
if ( path != QString::null )
197
EditorData * data = new EditorData;
198
data->url.setPath( path );
200
QDomElement mark = bookmark.firstChild().toElement();
201
while ( ! mark.isNull() )
203
QString line = mark.attribute( "line" );
204
if ( line != QString::null )
206
data->marks.append( qMakePair( line.toInt(), QString() ) );
208
mark = mark.nextSibling().toElement();
211
if ( ! data->marks.isEmpty() )
213
_editorMap.insert( data->url.path(), data );
220
bookmark = bookmark.nextSibling().toElement();
222
setBookmarksForAllURLs();
223
updateContextStringForAll();
224
_widget->update( _editorMap );
227
void BookmarksPart::savePartialProjectSession( QDomElement * el )
229
//kdDebug(0) << "BookmarksPart::savePartialProjectSession()" << endl;
233
QDomDocument domDoc = el->ownerDocument();
234
if ( domDoc.isNull() ) return;
236
QDomElement bookmarksList = domDoc.createElement( "bookmarks" );
238
QDictIterator<EditorData> it( _editorMap );
239
while ( it.current() )
241
QDomElement bookmark = domDoc.createElement( "bookmark" );
242
bookmark.setAttribute( "url", it.current()->url.path() );
243
bookmarksList.appendChild( bookmark );
245
QValueListIterator< QPair<int,QString> > it2 = it.current()->marks.begin();
246
while ( it2 != it.current()->marks.end() )
248
QDomElement line = domDoc.createElement( "mark" );
249
line.setAttribute( "line", (*it2).first );
250
bookmark.appendChild( line );
256
if ( ! bookmarksList.isNull() )
258
el->appendChild( bookmarksList );
262
void BookmarksPart::removeAllBookmarksForURL( KURL const & url )
264
//kdDebug(0) << "BookmarksPart::removeAllBookmarksForURL()" << endl;
266
_editorMap.remove( url.path() );
268
setBookmarksForURL( partForURL( url ) );
269
_widget->removeURL( url );
272
void BookmarksPart::removeBookmarkForURL( KURL const & url, int line )
274
//kdDebug(0) << "BookmarksPart::removeBookmarkForURL()" << endl;
276
if ( EditorData * data = _editorMap.find( url.path() ) )
278
QValueListIterator< QPair<int,QString> > it = data->marks.begin();
279
while ( it != data->marks.end() )
281
if ( (*it).first == line )
283
data->marks.remove( it );
289
if ( data->marks.isEmpty() )
291
removeAllBookmarksForURL( url );
295
setBookmarksForURL( partForURL( url ) );
296
_widget->updateURL( data );
301
void BookmarksPart::updateContextStringForURL( KParts::ReadOnlyPart * ro_part )
303
if ( ! ro_part ) return;
305
KTextEditor::EditInterface * ed =
306
dynamic_cast<KTextEditor::EditInterface *>( ro_part );
308
EditorData * data = _editorMap.find( ro_part->url().path() );
310
if ( ! ( data && ed ) ) return;
312
QValueListIterator< QPair<int,QString> > it = data->marks.begin();
313
while ( it != data->marks.end() )
315
(*it).second = ed->textLine( (*it).first );
320
void BookmarksPart::updateContextStringForURL( KURL const & url )
322
updateContextStringForURL( partForURL( url ) );
325
void BookmarksPart::updateContextStringForAll()
327
QDictIterator<EditorData> it( _editorMap );
328
while ( it.current() )
330
if ( ! it.current()->marks.isEmpty() )
332
updateContextStringForURL( it.current()->url );
338
bool BookmarksPart::setBookmarksForURL( KParts::ReadOnlyPart * ro_part )
340
if ( KTextEditor::MarkInterface * mi = dynamic_cast<KTextEditor::MarkInterface *>(ro_part) )
342
clearBookmarksForURL( ro_part );
344
_settingMarks = true;
346
if ( EditorData * data = _editorMap.find( ro_part->url().path() ) )
348
// we've seen this one before, apply stored bookmarks
350
QValueListIterator< QPair<int,QString> > it = data->marks.begin();
351
while ( it != data->marks.end() )
353
mi->addMark( (*it).first, KTextEditor::MarkInterface::markType01 );
357
_settingMarks = false;
359
// true == this is a MarkInterface
365
// Note: This method is only a convenience method to clear the bookmark marks,
366
// the way a hypothetical KTextEditor::MarkInterface::clearMarks( uint markType )
368
bool BookmarksPart::clearBookmarksForURL( KParts::ReadOnlyPart * ro_part )
370
if ( KTextEditor::MarkInterface * mi = dynamic_cast<KTextEditor::MarkInterface *>(ro_part) )
372
_settingMarks = true;
374
QPtrList<KTextEditor::Mark> marks = mi->marks();
375
QPtrListIterator<KTextEditor::Mark> it( marks );
376
while ( it.current() )
378
if ( it.current()->type & KTextEditor::MarkInterface::markType01 )
380
mi->removeMark( it.current()->line, KTextEditor::MarkInterface::markType01 );
385
_settingMarks = false;
387
// true == this is a MarkInterface
393
EditorData * BookmarksPart::storeBookmarksForURL( KParts::ReadOnlyPart * ro_part )
395
//kdDebug(0) << "BookmarksPart::storeBookmarksForURL()" << endl;
397
if ( KTextEditor::MarkInterface * mi = dynamic_cast<KTextEditor::MarkInterface *>( ro_part ) )
399
EditorData * data = new EditorData;
400
data->url = ro_part->url();
402
// removing previous data for this url, if any
403
_editorMap.remove( data->url.path() );
405
QPtrList<KTextEditor::Mark> marks = mi->marks();
406
QPtrListIterator<KTextEditor::Mark> it( marks );
407
while ( it.current() )
409
if ( it.current()->type & KTextEditor::MarkInterface::markType01 )
411
int line = it.current()->line;
412
data->marks.append( qMakePair( line, QString() ) );
417
if ( ! data->marks.isEmpty() )
419
_editorMap.insert( data->url.path(), data );
431
void BookmarksPart::setBookmarksForAllURLs()
433
if( const QPtrList<KParts::Part> * partlist = partController()->parts() )
435
QPtrListIterator<KParts::Part> it( *partlist );
436
while ( KParts::Part* part = it.current() )
438
if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( part ) )
440
setBookmarksForURL( ro_part );
447
void BookmarksPart::storeBookmarksForAllURLs()
449
if( const QPtrList<KParts::Part> * partlist = partController()->parts() )
451
QPtrListIterator<KParts::Part> it( *partlist );
452
while ( KParts::Part* part = it.current() )
454
if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( part ) )
456
storeBookmarksForURL( ro_part );
463
// reimplemented from PartController::partForURL to avoid linking
464
KParts::ReadOnlyPart * BookmarksPart::partForURL( KURL const & url )
466
QPtrListIterator<KParts::Part> it( *partController()->parts() );
467
while( it.current() )
469
KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(it.current());
470
if (ro_part && url == ro_part->url())
479
bool BookmarksPart::partIsSane( KParts::ReadOnlyPart * ro_part )
481
return ( ro_part != 0 ) &&
482
partController()->parts()->contains( ro_part) &&
483
!ro_part->url().path().isEmpty();
486
void BookmarksPart::insertConfigWidget( const KDialogBase * dlg, QWidget * page, unsigned int pagenumber )
488
kdDebug() << k_funcinfo << endl;
490
if ( pagenumber == BOOKMARKSETTINGSPAGE )
492
BookmarkSettings * w = new BookmarkSettings( this, page );
493
connect( dlg, SIGNAL(okClicked()), w, SLOT(slotAccept()) );
497
////////////////////////////////////////////
499
QStringList BookmarksPart::getContextFromStream( QTextStream & istream, unsigned int line, unsigned int context )
501
kdDebug() << k_funcinfo << endl;
503
int startline = context > line ? 0 : line - context;
504
int endline = line + context;
508
while ( !istream.atEnd() )
510
QString templine = istream.readLine();
511
if ( (n >= startline) && ( n <= endline ) )
518
// maybe pad empty lines to the tail
525
// maybe pad empty lines to the head
526
while( list.count() < ( context * 2 + 1) )
534
QStringList BookmarksPart::getContext( KURL const & url, unsigned int line, unsigned int context )
536
// if the file is open - get the line from the editor buffer
537
if ( KTextEditor::EditInterface * ei = dynamic_cast<KTextEditor::EditInterface*>( partForURL( url ) ) )
539
kdDebug() << "the file is open - get the line from the editor buffer" << endl;
541
QString ibuffer = ei->text();
542
QTextStream istream( &ibuffer, IO_ReadOnly );
543
return getContextFromStream( istream, line, context );
545
else if ( url.isLocalFile() ) // else the file is not open - get the line from the file on disk
547
kdDebug() << "the file is not open - get the line from the file on disk" << endl;
549
QFile file( url.path() );
552
if ( file.open( IO_ReadOnly ) )
554
QTextStream istream( &file );
555
return getContextFromStream( istream, line, context );
558
return QStringList( i18n("Could not find file") );
561
BookmarksConfig * BookmarksPart::config( )
566
#include "bookmarks_part.moc"
568
// kate: space-indent off; indent-width 4; tab-width 4; show-tabs off;