diff options
Diffstat (limited to 'lib/widgets/kdevhtmlpart.cpp')
-rw-r--r-- | lib/widgets/kdevhtmlpart.cpp | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/lib/widgets/kdevhtmlpart.cpp b/lib/widgets/kdevhtmlpart.cpp new file mode 100644 index 00000000..688e373a --- /dev/null +++ b/lib/widgets/kdevhtmlpart.cpp @@ -0,0 +1,512 @@ +#include <qfile.h> +#include <qclipboard.h> +#include <qapplication.h> + +#include <kxmlguiclient.h> +#include <kaction.h> +#include <kstdaction.h> +#include <kstandarddirs.h> +#include <klocale.h> +#include <kpopupmenu.h> +#include <kiconloader.h> +#include <kmainwindow.h> +#include <khtmlview.h> +#include <khtml_settings.h> +#include <kconfig.h> + +#include <kdevmainwindow.h> + + +#include "kdevhtmlpart.h" + +KDevHTMLPart::KDevHTMLPart() + : KHTMLPart(0L, 0L, 0L, "KDevHTMLPart", DefaultGUI ) +{ + setXMLFile(locate("data", "kdevelop/kdevhtml_partui.rc"), true); + + connect(browserExtension(), SIGNAL(openURLRequestDelayed(const KURL &,const KParts::URLArgs &)), + this, SLOT(openURLRequest(const KURL &)) ); + + connect(this, SIGNAL(started(KIO::Job *)), this, SLOT(slotStarted(KIO::Job* ))); + connect(this, SIGNAL(completed()), this, SLOT(slotCompleted())); + connect(this, SIGNAL(canceled(const QString &)), this, SLOT(slotCancelled(const QString &))); + + KActionCollection * actions = actionCollection();// new KActionCollection( this ); + reloadAction = new KAction( i18n( "Reload" ), "reload", 0, + this, SLOT( slotReload() ), actions, "doc_reload" ); + reloadAction->setWhatsThis(i18n("<b>Reload</b><p>Reloads the current document.")); + stopAction = new KAction( i18n( "Stop" ), "stop", 0, + this, SLOT( slotStop() ), actions, "doc_stop" ); + stopAction->setWhatsThis(i18n("<b>Stop</b><p>Stops the loading of current document.")); + duplicateAction = new KAction( i18n( "Duplicate Tab" ), "window_new", 0, + this, SLOT( slotDuplicate() ), actions, "doc_dup" ); + duplicateAction->setWhatsThis(i18n("<b>Duplicate window</b><p>Opens current document in a new window.")); + printAction = KStdAction::print(this, SLOT(slotPrint()), actions, "print_doc"); + copyAction = KStdAction::copy(this, SLOT(slotCopy()), actions, "copy_doc_selection"); + + connect( this, SIGNAL(popupMenu(const QString &, const QPoint &)), this, SLOT(popup(const QString &, const QPoint &))); + connect(this, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged())); + +//BEGIN documentation history stuff + + m_backAction = new KToolBarPopupAction(i18n("Back"), "back", 0, + this, SLOT(slotBack()), + actions, "browser_back"); + m_backAction->setEnabled( false ); + m_backAction->setToolTip(i18n("Back")); + m_backAction->setWhatsThis(i18n("<b>Back</b><p>Moves backwards one step in the <b>documentation</b> browsing history.")); + + connect(m_backAction->popupMenu(), SIGNAL(aboutToShow()), + this, SLOT(slotBackAboutToShow())); + connect(m_backAction->popupMenu(), SIGNAL(activated(int)), + this, SLOT(slotPopupActivated(int))); + + m_forwardAction = new KToolBarPopupAction(i18n("Forward"), "forward", 0, + this, SLOT(slotForward()), + actions, "browser_forward"); + m_forwardAction->setEnabled( false ); + m_forwardAction->setToolTip(i18n("Forward")); + m_forwardAction->setWhatsThis(i18n("<b>Forward</b><p>Moves forward one step in the <b>documentation</b> browsing history.")); + + connect(m_forwardAction->popupMenu(), SIGNAL(aboutToShow()), + this, SLOT(slotForwardAboutToShow())); + connect(m_forwardAction->popupMenu(), SIGNAL(activated(int)), + this, SLOT(slotPopupActivated(int))); + + m_restoring = false; + m_Current = m_history.end(); +//END documentation history stuff + + //settings: + KConfig *appConfig = KGlobal::config(); + appConfig->setGroup("KHTMLPart"); + setStandardFont(appConfig->readEntry("StandardFont", + settings()->stdFontName())); + setFixedFont(appConfig->readEntry("FixedFont", + settings()->fixedFontName())); + setZoomFactor(appConfig->readEntry("Zoom", "100").toInt()); +} + +void KDevHTMLPart::popup( const QString & url, const QPoint & p ) +{ +// KPopupMenu popup( i18n( "Documentation Viewer" ), this->widget() ); + KPopupMenu popup(this->widget()); + + bool needSep = false; + int idNewWindow = -2; + if (!url.isEmpty() && (m_options & CanOpenInNewWindow)) + { + idNewWindow = popup.insertItem(SmallIcon("window_new"),i18n("Open in New Tab")); + popup.setWhatsThis(idNewWindow, i18n("<b>Open in new window</b><p>Opens current link in a new window.")); + needSep = true; + } + if (m_options & CanDuplicate) + { + duplicateAction->plug(&popup); + needSep = true; + } + if (needSep) + popup.insertSeparator(); + + m_backAction->plug( &popup ); + m_forwardAction->plug( &popup ); + reloadAction->plug(&popup); +// stopAction->plug(&popup); + popup.insertSeparator(); + + copyAction->plug( &popup ); + popup.insertSeparator(); + + printAction->plug(&popup); + popup.insertSeparator(); + + KAction * incFontAction = this->action("incFontSizes"); + KAction * decFontAction = this->action("decFontSizes"); + if ( incFontAction && decFontAction ) + { + incFontAction->plug( &popup ); + decFontAction->plug( &popup ); + popup.insertSeparator(); + } + + KAction *ac = action("setEncoding"); + if (ac) + ac->plug(&popup); + + int r = popup.exec(p); + + if (r == idNewWindow) + { + KURL kurl; + if (!KURL(url).path().startsWith("/")) + { + kdDebug() << "processing relative url: " << url << endl; + if (url.startsWith("#")) + { + kurl = KURL(KDevHTMLPart::url()); + kurl.setRef(url.mid(1)); + } + else + kurl = KURL(KDevHTMLPart::url().upURL().url(true)+url); + } + else + kurl = KURL(url); + + if (kurl.isValid()) + slotOpenInNewWindow(kurl); + } +} + +void KDevHTMLPart::setContext(const QString &context) +{ + m_context = context; +} + + +QString KDevHTMLPart::context() const +{ + return m_context; +} + + +// Note: this function is a copy of code in kdecore/kconfigbase.cpp ;) +static bool isUtf8(const char *buf) { + int i, n; + register unsigned char c; + bool gotone = false; + +#define F 0 /* character never appears in text */ +#define T 1 /* character appears in plain ASCII text */ +#define I 2 /* character appears in ISO-8859 text */ +#define X 3 /* character appears in non-ISO extended ASCII (Mac, IBM PC) */ + + static const unsigned char text_chars[256] = { + /* BEL BS HT LF FF CR */ + F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F, /* 0x0X */ + /* ESC */ + F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F, /* 0x1X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x2X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x3X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x4X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x5X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x6X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F, /* 0x7X */ + /* NEL */ + X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X, /* 0x8X */ + X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 0x9X */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xaX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xbX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xcX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xdX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xeX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I /* 0xfX */ + }; + + /* *ulen = 0; */ + for (i = 0; (c = buf[i]); i++) { + if ((c & 0x80) == 0) { /* 0xxxxxxx is plain ASCII */ + /* + * Even if the whole file is valid UTF-8 sequences, + * still reject it if it uses weird control characters. + */ + + if (text_chars[c] != T) + return false; + + } else if ((c & 0x40) == 0) { /* 10xxxxxx never 1st byte */ + return false; + } else { /* 11xxxxxx begins UTF-8 */ + int following; + + if ((c & 0x20) == 0) { /* 110xxxxx */ + following = 1; + } else if ((c & 0x10) == 0) { /* 1110xxxx */ + following = 2; + } else if ((c & 0x08) == 0) { /* 11110xxx */ + following = 3; + } else if ((c & 0x04) == 0) { /* 111110xx */ + following = 4; + } else if ((c & 0x02) == 0) { /* 1111110x */ + following = 5; + } else + return false; + + for (n = 0; n < following; n++) { + i++; + if (!(c = buf[i])) + goto done; + + if ((c & 0x80) == 0 || (c & 0x40)) + return false; + } + gotone = true; + } + } +done: + return gotone; /* don't claim it's UTF-8 if it's all 7-bit */ +} +#undef F +#undef T +#undef I +#undef X + +QString KDevHTMLPart::resolveEnvVarsInURL(const QString& url) +{ + // check for environment variables and make necessary translations + QString path = url; + int nDollarPos = path.find( '$' ); + + // Note: the while loop below is a copy of code in kdecore/kconfigbase.cpp ;) + while( nDollarPos != -1 && nDollarPos+1 < static_cast<int>(path.length())) { + // there is at least one $ + if( (path)[nDollarPos+1] == '(' ) { + uint nEndPos = nDollarPos+1; + // the next character is no $ + while ( (nEndPos <= path.length()) && (path[nEndPos]!=')') ) + nEndPos++; + nEndPos++; + QString cmd = path.mid( nDollarPos+2, nEndPos-nDollarPos-3 ); + + QString result; + FILE *fs = popen(QFile::encodeName(cmd).data(), "r"); + if (fs) + { + QTextStream ts(fs, IO_ReadOnly); + result = ts.read().stripWhiteSpace(); + pclose(fs); + } + path.replace( nDollarPos, nEndPos-nDollarPos, result ); + } else if( (path)[nDollarPos+1] != '$' ) { + uint nEndPos = nDollarPos+1; + // the next character is no $ + QString aVarName; + if (path[nEndPos]=='{') + { + while ( (nEndPos <= path.length()) && (path[nEndPos]!='}') ) + nEndPos++; + nEndPos++; + aVarName = path.mid( nDollarPos+2, nEndPos-nDollarPos-3 ); + } + else + { + while ( nEndPos <= path.length() && (path[nEndPos].isNumber() + || path[nEndPos].isLetter() || path[nEndPos]=='_' ) ) + nEndPos++; + aVarName = path.mid( nDollarPos+1, nEndPos-nDollarPos-1 ); + } + const char* pEnv = 0; + if (!aVarName.isEmpty()) + pEnv = getenv( aVarName.ascii() ); + if( pEnv ) { + // !!! Sergey A. Sukiyazov <corwin@micom.don.ru> !!! + // A environment variables may contain values in 8bit + // locale cpecified encoding or in UTF8 encoding. + if (isUtf8( pEnv )) + path.replace( nDollarPos, nEndPos-nDollarPos, QString::fromUtf8(pEnv) ); + else + path.replace( nDollarPos, nEndPos-nDollarPos, QString::fromLocal8Bit(pEnv) ); + } else + path.remove( nDollarPos, nEndPos-nDollarPos ); + } else { + // remove one of the dollar signs + path.remove( nDollarPos, 1 ); + nDollarPos++; + } + nDollarPos = path.find( '$', nDollarPos ); + } + + return path; +} + +bool KDevHTMLPart::openURL(const KURL &url) +{ + QString path = resolveEnvVarsInURL(url.url()); + KURL newUrl(path); + + bool retval = KHTMLPart::openURL(newUrl); + if ( retval ) + { + emit fileNameChanged(this); + if ( !m_restoring ) + { + addHistoryEntry(); + } + } + + m_backAction->setEnabled( m_Current != m_history.begin() ); + m_forwardAction->setEnabled( m_Current != m_history.fromLast() ); + + return retval; +} + +void KDevHTMLPart::openURLRequest(const KURL &url) +{ + openURL( url ); +} + +void KDevHTMLPart::slotReload( ) +{ + openURL( url() ); +} + +void KDevHTMLPart::slotStop( ) +{ + closeURL(); +} + +void KDevHTMLPart::slotStarted( KIO::Job * ) +{ + stopAction->setEnabled(true); +} + +void KDevHTMLPart::slotCompleted( ) +{ + stopAction->setEnabled(false); +} + +void KDevHTMLPart::slotCancelled( const QString & /*errMsg*/ ) +{ + stopAction->setEnabled(false); +} + +/*void KDevHTMLPart::slotDuplicate( ) +{ + PartController::getInstance()->showDocument(url(), true); +}*/ + +void KDevHTMLPart::slotPrint( ) +{ + view()->print(); +} + +void KDevHTMLPart::slotBack() +{ + if ( m_Current != m_history.begin() ) + { + --m_Current; + m_restoring = true; + openURL( (*m_Current).url ); + m_restoring = false; + } +} + +void KDevHTMLPart::slotForward() +{ + if ( m_Current != m_history.fromLast() ) + { + ++m_Current; + m_restoring = true; + openURL( (*m_Current).url ); + m_restoring = false; + } +} + +void KDevHTMLPart::slotBackAboutToShow() +{ + KPopupMenu *popup = m_backAction->popupMenu(); + popup->clear(); + + if ( m_Current == m_history.begin() ) return; + + QValueList<DocumentationHistoryEntry>::Iterator it = m_Current; + --it; + + int i = 0; + while( i < 10 ) + { + if ( it == m_history.begin() ) + { + popup->insertItem( (*it).url.url(), (*it).id ); + return; + } + + popup->insertItem( (*it).url.url(), (*it).id ); + ++i; + --it; + } +} + +void KDevHTMLPart::slotForwardAboutToShow() +{ + KPopupMenu *popup = m_forwardAction->popupMenu(); + popup->clear(); + + if ( m_Current == m_history.fromLast() ) return; + + QValueList<DocumentationHistoryEntry>::Iterator it = m_Current; + ++it; + + int i = 0; + while( i < 10 ) + { + if ( it == m_history.fromLast() ) + { + popup->insertItem( (*it).url.url(), (*it).id ); + return; + } + + popup->insertItem( (*it).url.url(), (*it).id ); + ++i; + ++it; + } +} + +void KDevHTMLPart::slotPopupActivated( int id ) +{ + kdDebug(9000) << "id: " << id << endl; + + QValueList<DocumentationHistoryEntry>::Iterator it = m_history.begin(); + while( it != m_history.end() ) + { + kdDebug(9000) << "(*it).id: " << (*it).id << endl; + if ( (*it).id == id ) + { + m_Current = it; + m_restoring = true; + openURL( (*m_Current).url ); + m_restoring = false; + return; + } + ++it; + } +} + +void KDevHTMLPart::addHistoryEntry() +{ + QValueList<DocumentationHistoryEntry>::Iterator it = m_Current; + + // if We're not already the last entry, we truncate the list here before adding an entry + if ( it != m_history.end() && it != m_history.fromLast() ) + { + m_history.erase( ++it, m_history.end() ); + } + + DocumentationHistoryEntry newEntry( url() ); + + // Only save the new entry if it is different from the last + if ( newEntry.url != (*m_Current).url ) + { + m_history.append( newEntry ); + m_Current = m_history.fromLast(); + } +} + +void KDevHTMLPart::slotCopy( ) +{ + QString text = selectedText(); + text.replace( QChar( 0xa0 ), ' ' ); + QClipboard *cb = QApplication::clipboard(); + disconnect( cb, SIGNAL( selectionChanged() ), this, SLOT( slotClearSelection() ) ); + cb->setText(text); + connect( cb, SIGNAL( selectionChanged() ), this, SLOT( slotClearSelection() ) ); +} + +void KDevHTMLPart::slotSelectionChanged( ) +{ + if (selectedText().isEmpty()) + copyAction->setEnabled(false); + else + copyAction->setEnabled(true); +} + +#include "kdevhtmlpart.moc" |