summaryrefslogtreecommitdiffstats
path: root/parts/bookmarks/bookmarks_part.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'parts/bookmarks/bookmarks_part.cpp')
-rw-r--r--parts/bookmarks/bookmarks_part.cpp568
1 files changed, 568 insertions, 0 deletions
diff --git a/parts/bookmarks/bookmarks_part.cpp b/parts/bookmarks/bookmarks_part.cpp
new file mode 100644
index 00000000..f23863af
--- /dev/null
+++ b/parts/bookmarks/bookmarks_part.cpp
@@ -0,0 +1,568 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Jens Dagerbo *
+ * jens.dagerbo@swipnet.se *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qwhatsthis.h>
+#include <qvbox.h>
+#include <qtimer.h>
+#include <qtextstream.h>
+#include <qfile.h>
+
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kdevgenericfactory.h>
+#include <ktexteditor/markinterface.h>
+#include <ktexteditor/editinterface.h>
+#include <ktexteditor/document.h>
+#include <kaction.h>
+#include <kdialogbase.h>
+
+#include <kdevpartcontroller.h>
+#include <kdevcore.h>
+#include <kdevmainwindow.h>
+#include "domutil.h"
+
+#include "bookmarks_widget.h"
+#include "bookmarks_part.h"
+#include "bookmarks_settings.h"
+#include "bookmarks_config.h"
+
+#include <configwidgetproxy.h>
+#include <kdevplugininfo.h>
+
+#define BOOKMARKSETTINGSPAGE 1
+
+typedef KDevGenericFactory<BookmarksPart> BookmarksFactory;
+static const KDevPluginInfo data("kdevbookmarks");
+K_EXPORT_COMPONENT_FACTORY( libkdevbookmarks, BookmarksFactory( data ) )
+
+BookmarksPart::BookmarksPart(QObject *parent, const char *name, const QStringList& )
+ : KDevPlugin(&data, parent, name ? name : "BookmarksPart" )
+{
+ setInstance(BookmarksFactory::instance());
+
+ _widget = new BookmarksWidget(this);
+
+ _widget->setCaption(i18n("Bookmarks"));
+ _widget->setIcon(SmallIcon( info()->icon() ));
+
+ _marksChangeTimer = new QTimer( this );
+
+ QWhatsThis::add(_widget, i18n("<b>Bookmarks</b><p>"
+ "The bookmark viewer shows all the source bookmarks in the project."));
+
+ mainWindow()->embedSelectView(_widget, i18n("Bookmarks"), i18n("Source bookmarks"));
+
+ _editorMap.setAutoDelete( true );
+ _settingMarks = false;
+
+ connect( partController(), SIGNAL( partAdded( KParts::Part * ) ), this, SLOT( partAdded( KParts::Part * ) ) );
+
+ _configProxy = new ConfigWidgetProxy( core() );
+ _configProxy->createProjectConfigPage( i18n("Bookmarks"), BOOKMARKSETTINGSPAGE, info()->icon() );
+ connect( _configProxy, SIGNAL(insertConfigWidget(const KDialogBase*, QWidget*, unsigned int )),
+ this, SLOT(insertConfigWidget(const KDialogBase*, QWidget*, unsigned int )) );
+
+ connect( _widget, SIGNAL( removeAllBookmarksForURL( const KURL & ) ),
+ this, SLOT( removeAllBookmarksForURL( const KURL & ) ) );
+ connect( _widget, SIGNAL( removeBookmarkForURL( const KURL &, int ) ),
+ this, SLOT( removeBookmarkForURL( const KURL &, int ) ) );
+
+ connect( _marksChangeTimer, SIGNAL( timeout() ), this, SLOT( marksChanged() ) );
+
+ _config = new BookmarksConfig;
+ _config->readConfig();
+
+ storeBookmarksForAllURLs();
+ updateContextStringForAll();
+ _widget->update( _editorMap );
+}
+
+BookmarksPart::~BookmarksPart()
+{
+ if( _widget ) {
+ mainWindow()->removeView( _widget );
+ delete _widget;
+ }
+ delete _config;
+ delete _configProxy;
+}
+
+void BookmarksPart::partAdded( KParts::Part * part )
+{
+ //kdDebug(0) << "BookmarksPart::partAdded()" << endl;
+
+ if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( part ) )
+ {
+ if ( setBookmarksForURL( ro_part ) )
+ {
+ updateContextStringForURL( ro_part );
+ if ( EditorData * data = _editorMap.find( ro_part->url().path() ) )
+ {
+ _widget->updateURL( data );
+ }
+
+ // connect to this editor
+ KTextEditor::Document * doc = static_cast<KTextEditor::Document*>( ro_part );
+ connect( doc, SIGNAL( marksChanged() ), this, SLOT( marksEvent() ) );
+
+ // workaround for a katepart oddity where it drops all bookmarks on 'reload'
+ connect( doc, SIGNAL( completed() ), this, SLOT( reload() ) );
+ }
+ }
+}
+
+void BookmarksPart::reload()
+{
+ //kdDebug(0) << "BookmarksPart::reload()" << endl;
+
+ QObject * senderobj = const_cast<QObject*>( sender() );
+ if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( senderobj ) )
+ {
+ if ( partIsSane( ro_part ) )
+ {
+ setBookmarksForURL( ro_part );
+ }
+ }
+}
+
+void BookmarksPart::marksEvent()
+{
+ //kdDebug(0) << "BookmarksPart::marksEvent()" << endl;
+
+ if ( ! _settingMarks )
+ {
+ QObject * senderobj = const_cast<QObject*>( sender() );
+ KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( senderobj );
+
+ if ( partIsSane( ro_part ) && !_dirtyParts.contains( ro_part ) )
+ {
+ _dirtyParts.push_back( ro_part );
+ _marksChangeTimer->start( 1000, true );
+ }
+ }
+}
+
+void BookmarksPart::marksChanged()
+{
+ //kdDebug(0) << "BookmarksPart::marksChanged()" << endl;
+
+ QValueListIterator<KParts::ReadOnlyPart*> it = _dirtyParts.begin();
+ while ( it != _dirtyParts.end() )
+ {
+ KParts::ReadOnlyPart * ro_part = *it;
+ if ( partIsSane( ro_part ) )
+ {
+ if ( dynamic_cast<KTextEditor::MarkInterface*>( ro_part ) )
+ {
+ if ( EditorData * data = storeBookmarksForURL( ro_part ) )
+ {
+ updateContextStringForURL( ro_part );
+ _widget->updateURL( data );
+ }
+ else
+ {
+ _widget->removeURL( ro_part->url() );
+ }
+ }
+ }
+ ++it;
+ }
+ _dirtyParts.clear();
+}
+
+void BookmarksPart::restorePartialProjectSession( const QDomElement * el )
+{
+ //kdDebug(0) << "BookmarksPart::restorePartialProjectSession()" << endl;
+
+ if ( ! el ) return;
+
+ QDomElement bookmarksList = el->namedItem( "bookmarks" ).toElement();
+ if ( bookmarksList.isNull() ) return;
+
+ QDomElement bookmark = bookmarksList.firstChild().toElement();
+ while ( ! bookmark.isNull() )
+ {
+ QString path = bookmark.attribute( "url" );
+ if ( path != QString::null )
+ {
+ EditorData * data = new EditorData;
+ data->url.setPath( path );
+
+ QDomElement mark = bookmark.firstChild().toElement();
+ while ( ! mark.isNull() )
+ {
+ QString line = mark.attribute( "line" );
+ if ( line != QString::null )
+ {
+ data->marks.append( qMakePair( line.toInt(), QString() ) );
+ }
+ mark = mark.nextSibling().toElement();
+ }
+
+ if ( ! data->marks.isEmpty() )
+ {
+ _editorMap.insert( data->url.path(), data );
+ }
+ else
+ {
+ delete data;
+ }
+ }
+ bookmark = bookmark.nextSibling().toElement();
+ }
+ setBookmarksForAllURLs();
+ updateContextStringForAll();
+ _widget->update( _editorMap );
+}
+
+void BookmarksPart::savePartialProjectSession( QDomElement * el )
+{
+ //kdDebug(0) << "BookmarksPart::savePartialProjectSession()" << endl;
+
+ if ( ! el ) return;
+
+ QDomDocument domDoc = el->ownerDocument();
+ if ( domDoc.isNull() ) return;
+
+ QDomElement bookmarksList = domDoc.createElement( "bookmarks" );
+
+ QDictIterator<EditorData> it( _editorMap );
+ while ( it.current() )
+ {
+ QDomElement bookmark = domDoc.createElement( "bookmark" );
+ bookmark.setAttribute( "url", it.current()->url.path() );
+ bookmarksList.appendChild( bookmark );
+
+ QValueListIterator< QPair<int,QString> > it2 = it.current()->marks.begin();
+ while ( it2 != it.current()->marks.end() )
+ {
+ QDomElement line = domDoc.createElement( "mark" );
+ line.setAttribute( "line", (*it2).first );
+ bookmark.appendChild( line );
+ ++it2;
+ }
+ ++it;
+ }
+
+ if ( ! bookmarksList.isNull() )
+ {
+ el->appendChild( bookmarksList );
+ }
+}
+
+void BookmarksPart::removeAllBookmarksForURL( KURL const & url )
+{
+ //kdDebug(0) << "BookmarksPart::removeAllBookmarksForURL()" << endl;
+
+ _editorMap.remove( url.path() );
+
+ setBookmarksForURL( partForURL( url ) );
+ _widget->removeURL( url );
+}
+
+void BookmarksPart::removeBookmarkForURL( KURL const & url, int line )
+{
+ //kdDebug(0) << "BookmarksPart::removeBookmarkForURL()" << endl;
+
+ if ( EditorData * data = _editorMap.find( url.path() ) )
+ {
+ QValueListIterator< QPair<int,QString> > it = data->marks.begin();
+ while ( it != data->marks.end() )
+ {
+ if ( (*it).first == line )
+ {
+ data->marks.remove( it );
+ break;
+ }
+ ++it;
+ }
+
+ if ( data->marks.isEmpty() )
+ {
+ removeAllBookmarksForURL( url );
+ }
+ else
+ {
+ setBookmarksForURL( partForURL( url ) );
+ _widget->updateURL( data );
+ }
+ }
+}
+
+void BookmarksPart::updateContextStringForURL( KParts::ReadOnlyPart * ro_part )
+{
+ if ( ! ro_part ) return;
+
+ KTextEditor::EditInterface * ed =
+ dynamic_cast<KTextEditor::EditInterface *>( ro_part );
+
+ EditorData * data = _editorMap.find( ro_part->url().path() );
+
+ if ( ! ( data && ed ) ) return;
+
+ QValueListIterator< QPair<int,QString> > it = data->marks.begin();
+ while ( it != data->marks.end() )
+ {
+ (*it).second = ed->textLine( (*it).first );
+ ++it;
+ }
+}
+
+void BookmarksPart::updateContextStringForURL( KURL const & url )
+{
+ updateContextStringForURL( partForURL( url ) );
+}
+
+void BookmarksPart::updateContextStringForAll()
+{
+ QDictIterator<EditorData> it( _editorMap );
+ while ( it.current() )
+ {
+ if ( ! it.current()->marks.isEmpty() )
+ {
+ updateContextStringForURL( it.current()->url );
+ }
+ ++it;
+ }
+}
+
+bool BookmarksPart::setBookmarksForURL( KParts::ReadOnlyPart * ro_part )
+{
+ if ( KTextEditor::MarkInterface * mi = dynamic_cast<KTextEditor::MarkInterface *>(ro_part) )
+ {
+ clearBookmarksForURL( ro_part );
+
+ _settingMarks = true;
+
+ if ( EditorData * data = _editorMap.find( ro_part->url().path() ) )
+ {
+ // we've seen this one before, apply stored bookmarks
+
+ QValueListIterator< QPair<int,QString> > it = data->marks.begin();
+ while ( it != data->marks.end() )
+ {
+ mi->addMark( (*it).first, KTextEditor::MarkInterface::markType01 );
+ ++it;
+ }
+ }
+ _settingMarks = false;
+
+ // true == this is a MarkInterface
+ return true;
+ }
+ return false;
+}
+
+// Note: This method is only a convenience method to clear the bookmark marks,
+// the way a hypothetical KTextEditor::MarkInterface::clearMarks( uint markType )
+// would work.
+bool BookmarksPart::clearBookmarksForURL( KParts::ReadOnlyPart * ro_part )
+{
+ if ( KTextEditor::MarkInterface * mi = dynamic_cast<KTextEditor::MarkInterface *>(ro_part) )
+ {
+ _settingMarks = true;
+
+ QPtrList<KTextEditor::Mark> marks = mi->marks();
+ QPtrListIterator<KTextEditor::Mark> it( marks );
+ while ( it.current() )
+ {
+ if ( it.current()->type & KTextEditor::MarkInterface::markType01 )
+ {
+ mi->removeMark( it.current()->line, KTextEditor::MarkInterface::markType01 );
+ }
+ ++it;
+ }
+
+ _settingMarks = false;
+
+ // true == this is a MarkInterface
+ return true;
+ }
+ return false;
+}
+
+EditorData * BookmarksPart::storeBookmarksForURL( KParts::ReadOnlyPart * ro_part )
+{
+ //kdDebug(0) << "BookmarksPart::storeBookmarksForURL()" << endl;
+
+ if ( KTextEditor::MarkInterface * mi = dynamic_cast<KTextEditor::MarkInterface *>( ro_part ) )
+ {
+ EditorData * data = new EditorData;
+ data->url = ro_part->url();
+
+ // removing previous data for this url, if any
+ _editorMap.remove( data->url.path() );
+
+ QPtrList<KTextEditor::Mark> marks = mi->marks();
+ QPtrListIterator<KTextEditor::Mark> it( marks );
+ while ( it.current() )
+ {
+ if ( it.current()->type & KTextEditor::MarkInterface::markType01 )
+ {
+ int line = it.current()->line;
+ data->marks.append( qMakePair( line, QString() ) );
+ }
+ ++it;
+ }
+
+ if ( ! data->marks.isEmpty() )
+ {
+ _editorMap.insert( data->url.path(), data );
+ }
+ else
+ {
+ delete data;
+ data = 0;
+ }
+ return data;
+ }
+ return 0;
+}
+
+void BookmarksPart::setBookmarksForAllURLs()
+{
+ if( const QPtrList<KParts::Part> * partlist = partController()->parts() )
+ {
+ QPtrListIterator<KParts::Part> it( *partlist );
+ while ( KParts::Part* part = it.current() )
+ {
+ if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( part ) )
+ {
+ setBookmarksForURL( ro_part );
+ }
+ ++it;
+ }
+ }
+}
+
+void BookmarksPart::storeBookmarksForAllURLs()
+{
+ if( const QPtrList<KParts::Part> * partlist = partController()->parts() )
+ {
+ QPtrListIterator<KParts::Part> it( *partlist );
+ while ( KParts::Part* part = it.current() )
+ {
+ if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart *>( part ) )
+ {
+ storeBookmarksForURL( ro_part );
+ }
+ ++it;
+ }
+ }
+}
+
+// reimplemented from PartController::partForURL to avoid linking
+KParts::ReadOnlyPart * BookmarksPart::partForURL( KURL const & url )
+{
+ QPtrListIterator<KParts::Part> it( *partController()->parts() );
+ while( it.current() )
+ {
+ KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(it.current());
+ if (ro_part && url == ro_part->url())
+ {
+ return ro_part;
+ }
+ ++it;
+ }
+ return 0;
+}
+
+bool BookmarksPart::partIsSane( KParts::ReadOnlyPart * ro_part )
+{
+ return ( ro_part != 0 ) &&
+ partController()->parts()->contains( ro_part) &&
+ !ro_part->url().path().isEmpty();
+}
+
+void BookmarksPart::insertConfigWidget( const KDialogBase * dlg, QWidget * page, unsigned int pagenumber )
+{
+ kdDebug() << k_funcinfo << endl;
+
+ if ( pagenumber == BOOKMARKSETTINGSPAGE )
+ {
+ BookmarkSettings * w = new BookmarkSettings( this, page );
+ connect( dlg, SIGNAL(okClicked()), w, SLOT(slotAccept()) );
+ }
+}
+
+////////////////////////////////////////////
+
+QStringList BookmarksPart::getContextFromStream( QTextStream & istream, unsigned int line, unsigned int context )
+{
+ kdDebug() << k_funcinfo << endl;
+
+ int startline = context > line ? 0 : line - context;
+ int endline = line + context;
+
+ int n = 0;
+ QStringList list;
+ while ( !istream.atEnd() )
+ {
+ QString templine = istream.readLine();
+ if ( (n >= startline) && ( n <= endline ) )
+ {
+ list << templine;
+ }
+ n++;
+ }
+
+ // maybe pad empty lines to the tail
+ while( n < endline )
+ {
+ list.append( " " );
+ n++;
+ }
+
+ // maybe pad empty lines to the head
+ while( list.count() < ( context * 2 + 1) )
+ {
+ list.prepend( " " );
+ }
+
+ return list;
+}
+
+QStringList BookmarksPart::getContext( KURL const & url, unsigned int line, unsigned int context )
+{
+ // if the file is open - get the line from the editor buffer
+ if ( KTextEditor::EditInterface * ei = dynamic_cast<KTextEditor::EditInterface*>( partForURL( url ) ) )
+ {
+ kdDebug() << "the file is open - get the line from the editor buffer" << endl;
+
+ QString ibuffer = ei->text();
+ QTextStream istream( &ibuffer, IO_ReadOnly );
+ return getContextFromStream( istream, line, context );
+ }
+ else if ( url.isLocalFile() ) // else the file is not open - get the line from the file on disk
+ {
+ kdDebug() << "the file is not open - get the line from the file on disk" << endl;
+
+ QFile file( url.path() );
+ QString buffer;
+
+ if ( file.open( IO_ReadOnly ) )
+ {
+ QTextStream istream( &file );
+ return getContextFromStream( istream, line, context );
+ }
+ }
+ return QStringList( i18n("Could not find file") );
+}
+
+BookmarksConfig * BookmarksPart::config( )
+{
+ return _config;
+}
+
+#include "bookmarks_part.moc"
+
+// kate: space-indent off; indent-width 4; tab-width 4; show-tabs off;