KDevelop API Documentation

sourcenav_part.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2000-2001 by Harald Fernengel                           *
00003  *   harry@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 
00013 #include "sourcenav_part.h"
00014 
00015 #include <kdebug.h>
00016 #include <ktexteditor/viewcursorinterface.h>
00017 #include <ktexteditor/document.h>
00018 #include <ktexteditor/editinterface.h>
00019 #include <kgenericfactory.h>
00020 #include <kaction.h>
00021 #include <kguiitem.h>
00022 #include <kpopupmenu.h>
00023 
00024 #include "kdevcore.h"
00025 #include "kdevpartcontroller.h"
00026 
00027 // maximum steps to remember
00028 static const int MAX_HISTORY = 50;
00029 // textchanges after which the QValueLists are cleaned
00030 static const int MAX_CLEANUP = 200;
00031 // maximum number of items to display in Popup
00032 static const int MAX_ITEMS = 20;
00033 
00034 static int anchorID = 0;
00035 
00036 int Anchor::nextID()
00037 {
00038   return anchorID++;
00039 }
00040 
00041 typedef KGenericFactory<SourceNavPart> SourceNavFactory;
00042 K_EXPORT_COMPONENT_FACTORY( libkdevsourcenav, SourceNavFactory( "kdevsourcenav" ) );
00043 
00044 SourceNavPart::SourceNavPart(QObject *parent, const char *name, const QStringList& )
00045   : KDevPlugin("SourceNav", "sourcenav", parent, name ? name : "SourceNavPart")
00046 {
00047   setInstance(SourceNavFactory::instance());
00048   setXMLFile("kdevpart_sourcenav.rc");
00049 
00050   backPopupVisible = false;
00051   forwardPopupVisible = false;
00052 
00053   connect( partController(), SIGNAL(partAdded(KParts::Part*)), this, SLOT(slotPartAdded(KParts::Part*)) );
00054 
00055   navForward = new KToolBarPopupAction( KGuiItem( i18n("Navigate Forward"), "1rightarrow", i18n( "ToolTip" ), i18n( "What's This" ) ),
00056                                         0, this, SLOT(slotNavForward()), actionCollection(), "navForward" );
00057 
00058   navBack = new KToolBarPopupAction( KGuiItem( i18n("Navigate Backwards"), "1leftarrow", i18n( "ToolTip" ), i18n( "What's This" ) ),
00059                                      0, this, SLOT(slotNavBack()), actionCollection(), "navBack" );
00060 
00061   connect( navForward->popupMenu(), SIGNAL(aboutToShow()), this, SLOT(fillForwardPopup()) );
00062   connect( navForward->popupMenu(), SIGNAL(activated(int)), this, SLOT(forwardPopupClicked(int)) );
00063   connect( navBack->popupMenu(), SIGNAL(aboutToShow()), this, SLOT(fillBackPopup()) );
00064   connect( navBack->popupMenu(), SIGNAL(activated(int)), this, SLOT(backPopupClicked(int)) );
00065 
00066   navForward->setEnabled( false );
00067   navBack->setEnabled( false );
00068 }
00069 
00070 
00071 SourceNavPart::~SourceNavPart()
00072 {
00073 }
00074 
00075 void SourceNavPart::backPopupClicked( int id )
00076 {
00077   navigate( id, navList, forwardList );
00078 }
00079 
00080 void SourceNavPart::forwardPopupClicked( int id )
00081 {
00082   navigate( id, forwardList, navList );
00083 }
00084 
00085 void SourceNavPart::fillPopup( const AnchorList& list, QPopupMenu* pop )
00086 {
00087   if ( !pop )
00088     return;
00089 
00090   QString item;
00091   int i = 0;
00092   pop->clear();
00093   AnchorList::ConstIterator it = list.begin();
00094   while ( it != list.end() && i < MAX_ITEMS ) {
00095     if ( (*it).url().isLocalFile() ) {
00096       item = (*it).url().fileName();
00097     } else {
00098       item = (*it).url().prettyURL();
00099     }
00100     item +=  ":" + QString::number( (*it).line() );
00101     pop->insertItem( item, (*it).id() );
00102     ++i;
00103     ++it;
00104   }
00105 }
00106 
00107 void SourceNavPart::fillBackPopup()
00108 {
00109   fillPopup( navList, navBack->popupMenu() );
00110 }
00111 
00112 void SourceNavPart::fillForwardPopup()
00113 {
00114   fillPopup( forwardList, navForward->popupMenu() );
00115 }
00116 
00117 // called when a new document has been added
00118 void SourceNavPart::slotPartAdded( KParts::Part *part )
00119 {
00120   if ( !part )
00121     return;
00122  
00123   KTextEditor::Document *doc = dynamic_cast<KTextEditor::Document*>(part);
00124   if ( !doc )
00125     return;
00126 
00127   KTextEditor::EditInterface *ed = dynamic_cast<KTextEditor::EditInterface*>(doc);
00128   if ( ed ) {
00129     connect( doc, SIGNAL(textChanged()), this, SLOT(slotTextChanged()));   
00130   }  
00131 
00132 }
00133 
00134 Anchor SourceNavPart::getCurrentPos()
00135 {
00136   uint line = 0;
00137   uint col = 0;
00138 
00139   if ( !partController() )
00140     return Anchor();
00141 
00142   KTextEditor::Document *doc = dynamic_cast<KTextEditor::Document*>(partController()->activePart());
00143   QWidget *view = partController()->activeWidget();
00144   if ( !doc || !view )
00145     return Anchor();
00146 
00147   // hm, let's hope that this is the currently active view...
00148   KTextEditor::ViewCursorInterface *cur = dynamic_cast<KTextEditor::ViewCursorInterface*>(view);
00149   if ( cur ) {
00150     cur->cursorPosition( &line, &col );
00151   }
00152   
00153   return Anchor( doc->url(), line, col );
00154 }
00155 
00156 void SourceNavPart::gotoPos( const Anchor& ankh )
00157 {
00158   if ( !partController() )
00159     return;
00160   partController()->editDocument( ankh.url(), ankh.line() );
00161 }
00162 
00163 // returns true if pos1 is near to pos2
00164 bool SourceNavPart::isNearby( const Anchor& pos1, const Anchor& pos2 )
00165 {
00166   // 10 is just a magic number, might need a bit tweaking ;)
00167   if ( pos1.isValid() && pos2.isValid() && pos1.url() == pos2.url() && QABS((int)pos1.line() - (int)pos2.line()) < 5 )
00168     return true;
00169   return false;
00170 }
00171 
00172 void SourceNavPart::slotTextChanged()
00173 {
00174   const Anchor cur = getCurrentPos();
00175   const Anchor old = navList.isEmpty() ? Anchor() : navList.first();
00176 
00177   if ( !isNearby( cur, old ) ) { 
00178     navList.push_front( cur );
00179   }
00180 
00181   if ( cur.id() % MAX_CLEANUP == 0 ) {
00182     cleanupList( navList );
00183     cleanupList( forwardList );
00184   }
00185 
00186   enableActions();
00187 }
00188 
00189 void SourceNavPart::navigate( int id, AnchorList& list1, AnchorList& list2 )
00190 {
00191   Anchor ankh;
00192 
00193   AnchorList::Iterator it = list1.begin();
00194   while ( it != list1.end() ) {
00195     ankh = (*it);
00196     list2.push_front( *it );
00197     it = list1.remove( it );
00198 
00199     if ( ankh.id() == id ) {
00200       // found the right position
00201       it = list1.end();
00202     }
00203   }
00204 
00205   if ( ankh.isValid() ) {
00206     gotoPos( ankh );
00207   }
00208   enableActions();
00209 }
00210 
00211 void SourceNavPart::navigate( AnchorList& list1, AnchorList& list2 )
00212 {
00213   if ( list1.isEmpty() )
00214     return;
00215 
00216   const Anchor cur = getCurrentPos();
00217   Anchor last = list1.first();
00218 
00219   list2.push_front( last );
00220   list1.pop_front();
00221 
00222   if ( isNearby( cur, last ) ) {
00223     // we are currently at the position of the last change, so go to the one before
00224     if ( list1.isEmpty() ) {
00225       //nowhere to go...
00226       enableActions();
00227       return;
00228     }
00229     last = list1.first();
00230     list2.push_front( last );
00231     list1.pop_front();
00232   }
00233 
00234   gotoPos( last );
00235   enableActions();
00236 }
00237 
00238 void SourceNavPart::slotNavBack()
00239 {
00240   navigate( navList, forwardList );
00241 }
00242 
00243 void SourceNavPart::slotNavForward()
00244 {
00245   navigate( forwardList, navList );
00246 }
00247 
00248 void SourceNavPart::enableActions()
00249 {
00250   navForward->setEnabled( !forwardList.isEmpty() );
00251   navBack->setEnabled( !navList.isEmpty() );
00252 }
00253 
00254 void SourceNavPart::cleanupList( AnchorList& list )
00255 {
00256   AnchorList::Iterator it = list.at( MAX_HISTORY );
00257   while ( it != list.end() ) {
00258     it = list.remove( it );
00259   }
00260 }
00261 
00262 #include "sourcenav_part.moc"
00263 
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 23 00:03:58 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003