You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
513 lines
14 KiB
513 lines
14 KiB
#include <tqfile.h>
|
|
#include <tqclipboard.h>
|
|
#include <tqapplication.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", "tdevelop/kdevhtml_partui.rc"), true);
|
|
|
|
connect(browserExtension(), TQT_SIGNAL(openURLRequestDelayed(const KURL &,const KParts::URLArgs &)),
|
|
this, TQT_SLOT(openURLRequest(const KURL &)) );
|
|
|
|
connect(this, TQT_SIGNAL(started(KIO::Job *)), this, TQT_SLOT(slotStarted(KIO::Job* )));
|
|
connect(this, TQT_SIGNAL(completed()), this, TQT_SLOT(slotCompleted()));
|
|
connect(this, TQT_SIGNAL(canceled(const TQString &)), this, TQT_SLOT(slotCancelled(const TQString &)));
|
|
|
|
KActionCollection * actions = actionCollection();// new KActionCollection( this );
|
|
reloadAction = new KAction( i18n( "Reload" ), "reload", 0,
|
|
this, TQT_SLOT( slotReload() ), actions, "doc_reload" );
|
|
reloadAction->setWhatsThis(i18n("<b>Reload</b><p>Reloads the current document."));
|
|
stopAction = new KAction( i18n( "Stop" ), "stop", 0,
|
|
this, TQT_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, TQT_SLOT( slotDuplicate() ), actions, "doc_dup" );
|
|
duplicateAction->setWhatsThis(i18n("<b>Duplicate window</b><p>Opens current document in a new window."));
|
|
printAction = KStdAction::print(this, TQT_SLOT(slotPrint()), actions, "print_doc");
|
|
copyAction = KStdAction::copy(this, TQT_SLOT(slotCopy()), actions, "copy_doc_selection");
|
|
|
|
connect( this, TQT_SIGNAL(popupMenu(const TQString &, const TQPoint &)), this, TQT_SLOT(popup(const TQString &, const TQPoint &)));
|
|
connect(this, TQT_SIGNAL(selectionChanged()), this, TQT_SLOT(slotSelectionChanged()));
|
|
|
|
//BEGIN documentation history stuff
|
|
|
|
m_backAction = new KToolBarPopupAction(i18n("Back"), "back", 0,
|
|
this, TQT_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(), TQT_SIGNAL(aboutToShow()),
|
|
this, TQT_SLOT(slotBackAboutToShow()));
|
|
connect(m_backAction->popupMenu(), TQT_SIGNAL(activated(int)),
|
|
this, TQT_SLOT(slotPopupActivated(int)));
|
|
|
|
m_forwardAction = new KToolBarPopupAction(i18n("Forward"), "forward", 0,
|
|
this, TQT_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(), TQT_SIGNAL(aboutToShow()),
|
|
this, TQT_SLOT(slotForwardAboutToShow()));
|
|
connect(m_forwardAction->popupMenu(), TQT_SIGNAL(activated(int)),
|
|
this, TQT_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 TQString & url, const TQPoint & 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.TQMenuData::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 TQString &context)
|
|
{
|
|
m_context = context;
|
|
}
|
|
|
|
|
|
TQString KDevHTMLPart::context() const
|
|
{
|
|
return m_context;
|
|
}
|
|
|
|
|
|
// Note: this function is a copy of code in tdecore/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
|
|
|
|
TQString KDevHTMLPart::resolveEnvVarsInURL(const TQString& url)
|
|
{
|
|
// check for environment variables and make necessary translations
|
|
TQString path = url;
|
|
int nDollarPos = path.find( '$' );
|
|
|
|
// Note: the while loop below is a copy of code in tdecore/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++;
|
|
TQString cmd = path.mid( nDollarPos+2, nEndPos-nDollarPos-3 );
|
|
|
|
TQString result;
|
|
FILE *fs = popen(TQFile::encodeName(cmd).data(), "r");
|
|
if (fs)
|
|
{
|
|
TQTextStream 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 $
|
|
TQString 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, TQString::fromUtf8(pEnv) );
|
|
else
|
|
path.replace( nDollarPos, nEndPos-nDollarPos, TQString::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)
|
|
{
|
|
TQString 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 TQString & /*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;
|
|
|
|
TQValueList<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;
|
|
|
|
TQValueList<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;
|
|
|
|
TQValueList<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()
|
|
{
|
|
TQValueList<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( )
|
|
{
|
|
TQString text = selectedText();
|
|
text.replace( TQChar( 0xa0 ), ' ' );
|
|
TQClipboard *cb = TQApplication::clipboard();
|
|
disconnect( cb, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotClearSelection() ) );
|
|
cb->setText(text);
|
|
connect( cb, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotClearSelection() ) );
|
|
}
|
|
|
|
void KDevHTMLPart::slotSelectionChanged( )
|
|
{
|
|
if (selectedText().isEmpty())
|
|
copyAction->setEnabled(false);
|
|
else
|
|
copyAction->setEnabled(true);
|
|
}
|
|
|
|
#include "kdevhtmlpart.moc"
|