KDevelop API Documentation

kdevhtmlpart.cpp

Go to the documentation of this file.
00001 #include <qfile.h>
00002 #include <qclipboard.h>
00003 #include <qapplication.h>
00004 
00005 #include <kaction.h>
00006 #include <kstdaction.h>
00007 #include <kstddirs.h>
00008 #include <klocale.h>
00009 #include <kpopupmenu.h>
00010 #include <kiconloader.h>
00011 #include <kmainwindow.h>
00012 #include <khtmlview.h>
00013 
00014 #include <kdevmainwindow.h>
00015 //#include <partcontroller.h>
00016 //#include "toplevel.h"
00017 
00018 
00019 #include "kdevhtmlpart.h"
00020 
00021 KDevHTMLPart::KDevHTMLPart()
00022   : KHTMLPart(0L, 0L, 0L, "KDevHTMLPart", BrowserViewGUI )
00023 {
00024   setXMLFile(locate("data", "kdevelop/kdevhtml_partui.rc"), true);
00025   
00026   connect(browserExtension(), SIGNAL(openURLRequestDelayed(const KURL &,const KParts::URLArgs &)),
00027           this, SLOT(openURLRequest(const KURL &)) );
00028 
00029   connect(this, SIGNAL(started(KIO::Job *)), this, SLOT(slotStarted(KIO::Job* )));
00030   connect(this, SIGNAL(completed()), this, SLOT(slotCompleted()));
00031   connect(this, SIGNAL(canceled(const QString &)), this, SLOT(slotCancelled(const QString &)));
00032 
00033   KActionCollection * actions = actionCollection();// new KActionCollection( this );
00034   reloadAction = new KAction( i18n( "Reload" ), "reload", 0,
00035     this, SLOT( slotReload() ), actions, "doc_reload" );
00036   reloadAction->setWhatsThis(i18n("<b>Reload</b><p>Reloads the current document."));
00037   stopAction = new KAction( i18n( "Stop" ), "stop", 0,
00038     this, SLOT( slotStop() ), actions, "doc_stop" );
00039   stopAction->setWhatsThis(i18n("<b>Stop</b><p>Stops the loading of current document."));
00040   duplicateAction = new KAction( i18n( "Duplicate Tab" ), "window_new", 0,
00041     this, SLOT( slotDuplicate() ), actions, "doc_dup" );
00042   duplicateAction->setWhatsThis(i18n("<b>Duplicate window</b><p>Opens current document in a new window."));
00043   printAction = KStdAction::print(this, SLOT(slotPrint()), actions, "print_doc");
00044   copyAction = KStdAction::copy(this, SLOT(slotCopy()), actions, "copy_doc_selection");
00045 
00046   connect( this, SIGNAL(popupMenu(const QString &, const QPoint &)), this, SLOT(popup(const QString &, const QPoint &)));
00047   connect(this, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()));
00048 
00049 //BEGIN documentation history stuff  
00050     
00051   m_backAction = new KToolBarPopupAction(i18n("Back"), "back", 0,
00052     this, SLOT(slotBack()),
00053     actions, "browser_back");
00054   m_backAction->setEnabled( false );
00055   m_backAction->setToolTip(i18n("Back"));
00056   m_backAction->setWhatsThis(i18n("<b>Back</b><p>Moves backwards one step in the <b>documentation</b> browsing history."));
00057 
00058   connect(m_backAction->popupMenu(), SIGNAL(aboutToShow()),
00059          this, SLOT(slotBackAboutToShow()));
00060   connect(m_backAction->popupMenu(), SIGNAL(activated(int)),
00061          this, SLOT(slotPopupActivated(int)));
00062 
00063   m_forwardAction = new KToolBarPopupAction(i18n("Forward"), "forward", 0,
00064     this, SLOT(slotForward()),
00065     actions, "browser_forward");
00066   m_forwardAction->setEnabled( false );
00067   m_forwardAction->setToolTip(i18n("Forward"));
00068   m_forwardAction->setWhatsThis(i18n("<b>Forward</b><p>Moves forward one step in the <b>documentation</b> browsing history."));
00069 
00070   connect(m_forwardAction->popupMenu(), SIGNAL(aboutToShow()),
00071          this, SLOT(slotForwardAboutToShow()));
00072   connect(m_forwardAction->popupMenu(), SIGNAL(activated(int)),
00073          this, SLOT(slotPopupActivated(int)));
00074   
00075   m_restoring = false;
00076   m_Current = m_history.end();
00077 //END documentation history stuff  
00078   
00079 }
00080 
00081 void KDevHTMLPart::popup( const QString & url, const QPoint & p )
00082 {
00083 //  KPopupMenu popup( i18n( "Documentation Viewer" ), this->widget() );
00084   KPopupMenu popup(this->widget());
00085 
00086   bool needSep = false;  
00087   int idNewWindow = -2;
00088   if (!url.isEmpty() && (m_options & CanOpenInNewWindow))
00089   {
00090     idNewWindow = popup.insertItem(SmallIcon("window_new"),i18n("Open in New Tab"));
00091     popup.setWhatsThis(idNewWindow, i18n("<b>Open in new window</b><p>Opens current link in a new window."));
00092     needSep = true;
00093   }
00094   if (m_options & CanDuplicate)
00095   {
00096       duplicateAction->plug(&popup);
00097       needSep = true;
00098   }
00099   if (needSep)
00100       popup.insertSeparator();
00101     
00102   m_backAction->plug( &popup );
00103   m_forwardAction->plug( &popup );
00104   reloadAction->plug(&popup);
00105 //  stopAction->plug(&popup);
00106   popup.insertSeparator();
00107 
00108   copyAction->plug( &popup );
00109   popup.insertSeparator();
00110   
00111   printAction->plug(&popup);
00112   popup.insertSeparator();
00113     
00114   KAction * incFontAction = this->action("incFontSizes");
00115   KAction * decFontAction = this->action("decFontSizes");
00116   if ( incFontAction && decFontAction )
00117   {
00118     incFontAction->plug( &popup );
00119     decFontAction->plug( &popup );
00120     popup.insertSeparator();
00121   }
00122 
00123 
00124 /*  if (!url.isEmpty())
00125   {
00126     KAction *ac = action("savelinkas");
00127     if (ac)
00128     {
00129         qWarning("savelinkas found");
00130         ac->plug(m_popup);
00131     }
00132     KAction *ac2 = action("copylinklocation");
00133     if (ac2)
00134         ac2->plug(m_popup);
00135     m_popup->insertSeparator();
00136   }*/
00137 
00138   KAction *ac = action("setEncoding");
00139   if (ac)
00140     ac->plug(&popup);
00141 
00142   int r = popup.exec(p);
00143 
00144   if (r == idNewWindow)
00145   {
00146     KURL kurl;
00147     if (!KURL(url).path().startsWith("/"))
00148     {
00149         kdDebug() << "processing relative url: " << url << endl;
00150         if (url.startsWith("#"))
00151         {
00152             kurl = KURL(KDevHTMLPart::url());
00153             kurl.setRef(url.mid(1));
00154         }
00155         else
00156             kurl = KURL(KDevHTMLPart::url().upURL().url(true)+url);
00157     }
00158     else
00159         kurl = KURL(url);
00160 //    kurl.addPath(url);
00161     if (kurl.isValid())
00162         slotOpenInNewWindow(kurl);
00163 //      openURL( kurl );
00164   }
00165 }
00166 
00167 void KDevHTMLPart::setContext(const QString &context)
00168 {
00169   m_context = context;
00170 }
00171 
00172 
00173 QString KDevHTMLPart::context() const
00174 {
00175   return m_context;
00176 }
00177 
00178 
00179 // Note: this function is a copy of code in kdecore/kconfigbase.cpp ;)
00180 static bool isUtf8(const char *buf) {
00181   int i, n;
00182   register unsigned char c;
00183   bool gotone = false;
00184 
00185 #define F 0   /* character never appears in text */
00186 #define T 1   /* character appears in plain ASCII text */
00187 #define I 2   /* character appears in ISO-8859 text */
00188 #define X 3   /* character appears in non-ISO extended ASCII (Mac, IBM PC) */
00189 
00190   static const unsigned char text_chars[256] = {
00191   /*                  BEL BS HT LF    FF CR    */
00192         F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F,  /* 0x0X */
00193         /*                              ESC          */
00194         F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F,  /* 0x1X */
00195         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x2X */
00196         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x3X */
00197         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x4X */
00198         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x5X */
00199         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x6X */
00200         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F,  /* 0x7X */
00201         /*            NEL                            */
00202         X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X,  /* 0x8X */
00203         X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,  /* 0x9X */
00204         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xaX */
00205         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xbX */
00206         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xcX */
00207         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xdX */
00208         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xeX */
00209         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I   /* 0xfX */
00210   };
00211 
00212   /* *ulen = 0; */
00213   for (i = 0; (c = buf[i]); i++) {
00214     if ((c & 0x80) == 0) {        /* 0xxxxxxx is plain ASCII */
00215       /*
00216        * Even if the whole file is valid UTF-8 sequences,
00217        * still reject it if it uses weird control characters.
00218        */
00219 
00220       if (text_chars[c] != T)
00221         return false;
00222 
00223     } else if ((c & 0x40) == 0) { /* 10xxxxxx never 1st byte */
00224       return false;
00225     } else {                           /* 11xxxxxx begins UTF-8 */
00226       int following;
00227 
00228     if ((c & 0x20) == 0) {             /* 110xxxxx */
00229       following = 1;
00230     } else if ((c & 0x10) == 0) {      /* 1110xxxx */
00231       following = 2;
00232     } else if ((c & 0x08) == 0) {      /* 11110xxx */
00233       following = 3;
00234     } else if ((c & 0x04) == 0) {      /* 111110xx */
00235       following = 4;
00236     } else if ((c & 0x02) == 0) {      /* 1111110x */
00237       following = 5;
00238     } else
00239       return false;
00240 
00241       for (n = 0; n < following; n++) {
00242         i++;
00243         if (!(c = buf[i]))
00244           goto done;
00245 
00246         if ((c & 0x80) == 0 || (c & 0x40))
00247           return false;
00248       }
00249       gotone = true;
00250     }
00251   }
00252 done:
00253   return gotone;   /* don't claim it's UTF-8 if it's all 7-bit */
00254 }
00255 #undef F
00256 #undef T
00257 #undef I
00258 #undef X
00259 
00260 QString KDevHTMLPart::resolveEnvVarsInURL(const QString& url)
00261 {
00262   // check for environment variables and make necessary translations
00263   QString path = url;
00264   int nDollarPos = path.find( '$' );
00265 
00266   // Note: the while loop below is a copy of code in kdecore/kconfigbase.cpp ;)
00267   while( nDollarPos != -1 && nDollarPos+1 < static_cast<int>(path.length())) {
00268     // there is at least one $
00269     if( (path)[nDollarPos+1] == '(' ) {
00270       uint nEndPos = nDollarPos+1;
00271       // the next character is no $
00272       while ( (nEndPos <= path.length()) && (path[nEndPos]!=')') )
00273           nEndPos++;
00274       nEndPos++;
00275       QString cmd = path.mid( nDollarPos+2, nEndPos-nDollarPos-3 );
00276 
00277       QString result;
00278       FILE *fs = popen(QFile::encodeName(cmd).data(), "r");
00279       if (fs)
00280       {
00281          QTextStream ts(fs, IO_ReadOnly);
00282          result = ts.read().stripWhiteSpace();
00283          pclose(fs);
00284       }
00285       path.replace( nDollarPos, nEndPos-nDollarPos, result );
00286     } else if( (path)[nDollarPos+1] != '$' ) {
00287       uint nEndPos = nDollarPos+1;
00288       // the next character is no $
00289       QString aVarName;
00290       if (path[nEndPos]=='{')
00291       {
00292         while ( (nEndPos <= path.length()) && (path[nEndPos]!='}') )
00293             nEndPos++;
00294         nEndPos++;
00295         aVarName = path.mid( nDollarPos+2, nEndPos-nDollarPos-3 );
00296       }
00297       else
00298       {
00299         while ( nEndPos <= path.length() && (path[nEndPos].isNumber()
00300                 || path[nEndPos].isLetter() || path[nEndPos]=='_' )  )
00301             nEndPos++;
00302         aVarName = path.mid( nDollarPos+1, nEndPos-nDollarPos-1 );
00303       }
00304       const char* pEnv = 0;
00305       if (!aVarName.isEmpty())
00306            pEnv = getenv( aVarName.ascii() );
00307       if( pEnv ) {
00308         // !!! Sergey A. Sukiyazov <corwin@micom.don.ru> !!!
00309         // A environment variables may contain values in 8bit
00310         // locale cpecified encoding or in UTF8 encoding.
00311         if (isUtf8( pEnv ))
00312             path.replace( nDollarPos, nEndPos-nDollarPos, QString::fromUtf8(pEnv) );
00313         else
00314             path.replace( nDollarPos, nEndPos-nDollarPos, QString::fromLocal8Bit(pEnv) );
00315       } else
00316       path.remove( nDollarPos, nEndPos-nDollarPos );
00317     } else {
00318       // remove one of the dollar signs
00319       path.remove( nDollarPos, 1 );
00320       nDollarPos++;
00321     }
00322     nDollarPos = path.find( '$', nDollarPos );
00323   }
00324 
00325   return path;
00326 }
00327 
00328 bool KDevHTMLPart::openURL(const KURL &url)
00329 {
00330   QString path = resolveEnvVarsInURL(url.url());
00331   KURL newUrl(path);
00332   
00333   bool retval = KHTMLPart::openURL(newUrl);
00334   if ( retval )
00335   {
00336     emit fileNameChanged(this);
00337     if ( !m_restoring ) 
00338     {
00339         addHistoryEntry();
00340     }
00341   }
00342   
00343   m_backAction->setEnabled( m_Current != m_history.begin() );
00344   m_forwardAction->setEnabled( m_Current != m_history.fromLast() );
00345   
00346   return retval;
00347 }
00348 
00349 void KDevHTMLPart::openURLRequest(const KURL &url)
00350 {
00351     openURL( url );
00352 }
00353 
00354 void KDevHTMLPart::slotReload( )
00355 {
00356     openURL( url() );
00357 }
00358 
00359 void KDevHTMLPart::slotStop( )
00360 {
00361     closeURL();
00362 }
00363 
00364 void KDevHTMLPart::slotStarted( KIO::Job * )
00365 {
00366     stopAction->setEnabled(true);
00367 }
00368 
00369 void KDevHTMLPart::slotCompleted( )
00370 {
00371     stopAction->setEnabled(false);
00372 }
00373 
00374 void KDevHTMLPart::slotCancelled( const QString & /*errMsg*/ )
00375 {
00376     stopAction->setEnabled(false);
00377 }
00378 
00379 /*void KDevHTMLPart::slotDuplicate( )
00380 {
00381     PartController::getInstance()->showDocument(url(), true);
00382 }*/
00383 
00384 void KDevHTMLPart::slotPrint( )
00385 {
00386     view()->print();
00387 }
00388 
00389 void KDevHTMLPart::slotBack()
00390 {
00391     if ( m_Current != m_history.begin() )
00392     {
00393         --m_Current;
00394         m_restoring = true;
00395         openURL( (*m_Current).url );
00396         m_restoring = false;
00397     }
00398 }
00399 
00400 void KDevHTMLPart::slotForward()
00401 {
00402     if (  m_Current != m_history.fromLast() )
00403     {
00404         ++m_Current;
00405         m_restoring = true;
00406         openURL( (*m_Current).url );
00407         m_restoring = false;
00408     }
00409 }
00410 
00411 void KDevHTMLPart::slotBackAboutToShow()
00412 {
00413     KPopupMenu *popup = m_backAction->popupMenu();
00414     popup->clear();
00415 
00416     if ( m_Current == m_history.begin() ) return;
00417 
00418     QValueList<DocumentationHistoryEntry>::Iterator it = m_Current;
00419     --it;
00420     
00421     int i = 0;
00422     while( i < 10 )
00423     {
00424         if ( it == m_history.begin() )
00425         {
00426             popup->insertItem( (*it).url.url(), (*it).id );
00427             return;
00428         } 
00429         
00430         popup->insertItem( (*it).url.url(), (*it).id );
00431         ++i;
00432         --it;
00433     } 
00434 }
00435 
00436 void KDevHTMLPart::slotForwardAboutToShow()
00437 {
00438     KPopupMenu *popup = m_forwardAction->popupMenu();
00439     popup->clear();
00440 
00441     if ( m_Current == m_history.fromLast() ) return;
00442 
00443     QValueList<DocumentationHistoryEntry>::Iterator it = m_Current;
00444     ++it;
00445     
00446     int i = 0;
00447     while( i < 10 )
00448     {
00449         if ( it == m_history.fromLast() )
00450         {
00451             popup->insertItem( (*it).url.url(), (*it).id );
00452             return;
00453         } 
00454         
00455         popup->insertItem( (*it).url.url(), (*it).id );
00456         ++i;
00457         ++it;
00458     } 
00459 }
00460 
00461 void KDevHTMLPart::slotPopupActivated( int id )
00462 {
00463     kdDebug(9000) << "id: " << id << endl;
00464 
00465     QValueList<DocumentationHistoryEntry>::Iterator it = m_history.begin();
00466     while( it != m_history.end() )
00467     {
00468         kdDebug(9000) << "(*it).id: " << (*it).id << endl;
00469         if ( (*it).id == id )
00470         {
00471             m_Current = it;
00472             m_restoring = true;
00473             openURL( (*m_Current).url );
00474             m_restoring = false;
00475             return;
00476         }
00477         ++it;
00478     }
00479 }
00480 
00481 void KDevHTMLPart::addHistoryEntry()
00482 {
00483     QValueList<DocumentationHistoryEntry>::Iterator it = m_Current;
00484     
00485     // if We're not already the last entry, we truncate the list here before adding an entry
00486     if ( it != m_history.end() && it != m_history.fromLast() )
00487     {
00488         m_history.erase( ++it, m_history.end() );
00489     }
00490     
00491     DocumentationHistoryEntry newEntry( url() );
00492         
00493     // Only save the new entry if it is different from the last
00494     if ( newEntry.url != (*m_Current).url )
00495     {
00496         m_history.append( newEntry );
00497         m_Current = m_history.fromLast();
00498     }
00499 }
00500 
00501 void KDevHTMLPart::slotCopy( )
00502 {
00503     QString text = selectedText();
00504     text.replace( QChar( 0xa0 ), ' ' );
00505     QClipboard *cb = QApplication::clipboard();
00506     disconnect( cb, SIGNAL( selectionChanged() ), this, SLOT( slotClearSelection() ) );
00507     cb->setText(text);
00508     connect( cb, SIGNAL( selectionChanged() ), this, SLOT( slotClearSelection() ) );
00509 }
00510 
00511 void KDevHTMLPart::slotSelectionChanged( )
00512 {
00513     if (selectedText().isEmpty())
00514         copyAction->setEnabled(false);
00515     else
00516         copyAction->setEnabled(true);
00517 }
00518 
00519 #include "kdevhtmlpart.moc"
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:36 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003