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.
tdegraphics/kpdf/part.cpp

1101 lines
37 KiB

/***************************************************************************
* Copyright (C) 2002 by Wilco Greven <greven@kde.org> *
* Copyright (C) 2002 by Chris Cheney <ccheney@cheney.cx> *
* Copyright (C) 2002 by Malcolm Hunter <malcolm.hunter@gmx.co.uk> *
* Copyright (C) 2003-2004 by Christophe Devriese *
* <Christophe.Devriese@student.kuleuven.ac.be> *
* Copyright (C) 2003 by Daniel Molkentin <molkentin@kde.org> *
* Copyright (C) 2003 by Andy Goossens <andygoossens@telenet.be> *
* Copyright (C) 2003 by Dirk Mueller <mueller@kde.org> *
* Copyright (C) 2003 by Laurent Montel <montel@kde.org> *
* Copyright (C) 2004 by Dominique Devriese <devriese@kde.org> *
* Copyright (C) 2004 by Christoph Cullmann <crossfire@babylon2k.de> *
* Copyright (C) 2004 by Henrique Pinto <stampede@coltec.ufmg.br> *
* Copyright (C) 2004 by Waldo Bastian <bastian@kde.org> *
* Copyright (C) 2004-2006 by Albert Astals Cid <tsdgeos@terra.es> *
* Copyright (C) 2004 by Antti Markus <antti.markus@starman.ee> *
* *
* 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. *
***************************************************************************/
// qt/kde includes
#include <tqcheckbox.h>
#include <tqsplitter.h>
#include <tqpainter.h>
#include <tqlayout.h>
#include <tqlabel.h>
#include <tqvbox.h>
#include <tqtoolbox.h>
#include <tqtooltip.h>
#include <tqpushbutton.h>
#include <tqwhatsthis.h>
#include <dcopobject.h>
#include <dcopclient.h>
#include <tdeapplication.h>
#include <tdeaction.h>
#include <kdirwatch.h>
#include <kinstance.h>
#include <kprinter.h>
#include <tdeprint/kprintdialogpage.h>
#include <kstdaction.h>
#include <tdeversion.h>
#include <tdeparts/genericfactory.h>
#include <kurldrag.h>
#include <tdefiledialog.h>
#include <kmessagebox.h>
#include <kfinddialog.h>
#include <knuminput.h>
#include <kiconloader.h>
#include <tdeio/netaccess.h>
#include <tdeio/job.h>
#include <tdepopupmenu.h>
#include <kprocess.h>
#include <kstandarddirs.h>
#include <ktempfile.h>
#include <ktrader.h>
#include <kxmlguiclient.h>
#include <kxmlguifactory.h>
// local includes
#include "xpdf/GlobalParams.h"
#include "part.h"
#include "ui/pageview.h"
#include "ui/thumbnaillist.h"
#include "ui/searchwidget.h"
#include "ui/toc.h"
#include "ui/minibar.h"
#include "ui/propertiesdialog.h"
#include "ui/presentationwidget.h"
#include "conf/preferencesdialog.h"
#include "conf/settings.h"
#include "core/document.h"
#include "core/page.h"
class PDFOptionsPage : public KPrintDialogPage
{
public:
PDFOptionsPage()
{
setTitle( i18n( "PDF Options" ) );
TQVBoxLayout *layout = new TQVBoxLayout(this);
m_forceRaster = new TQCheckBox(i18n("Force rasterization"), this);
TQToolTip::add(m_forceRaster, i18n("Rasterize into an image before printing"));
TQWhatsThis::add(m_forceRaster, i18n("Forces the rasterization of each page into an image before printing it. This usually gives somewhat worse results, but is useful when printing documents that appear to print incorrectly."));
layout->addWidget(m_forceRaster);
layout->addStretch(1);
}
void getOptions( TQMap<TQString,TQString>& opts, bool incldef = false )
{
Q_UNUSED(incldef);
opts[ "kde-kpdf-forceRaster" ] = TQString::number( m_forceRaster->isChecked() );
}
void setOptions( const TQMap<TQString,TQString>& opts )
{
m_forceRaster->setChecked( opts[ "kde-kpdf-forceRaster" ].toInt() );
}
private:
TQCheckBox *m_forceRaster;
};
// definition of searchID for this class
#define PART_SEARCH_ID 1
typedef KParts::GenericFactory<KPDF::Part> KPDFPartFactory;
K_EXPORT_COMPONENT_FACTORY(libkpdfpart, KPDFPartFactory)
using namespace KPDF;
unsigned int Part::m_count = 0;
Part::Part(TQWidget *parentWidget, const char *widgetName,
TQObject *parent, const char *name,
const TQStringList & /*args*/ )
: DCOPObject("kpdf"), KParts::ReadOnlyPart(parent, name), m_showMenuBarAction(0), m_showFullScreenAction(0),
m_actionsSearched(false), m_searchStarted(false)
{
// connect the started signal to tell the job the mimetypes we like
connect(this, TQT_SIGNAL(started(TDEIO::Job *)), this, TQT_SLOT(setMimeTypes(TDEIO::Job *)));
// connect the completed signal so we can put the window caption when loading remote files
connect(this, TQT_SIGNAL(completed()), this, TQT_SLOT(emitWindowCaption()));
connect(this, TQT_SIGNAL(canceled(const TQString &)), this, TQT_SLOT(emitWindowCaption()));
// load catalog for translation
TDEGlobal::locale()->insertCatalogue("kpdf");
// create browser extension (for printing when embedded into browser)
m_bExtension = new BrowserExtension(this);
// xpdf 'extern' global class (m_count is a static instance counter)
//if ( m_count ) TODO check if we need to insert these lines..
// delete globalParams;
globalParams = new GlobalParams("");
globalParams->setupBaseFonts(NULL);
m_count++;
// we need an instance
setInstance(KPDFPartFactory::instance());
// build the document
m_document = new KPDFDocument(widget());
connect( m_document, TQT_SIGNAL( linkFind() ), this, TQT_SLOT( slotFind() ) );
connect( m_document, TQT_SIGNAL( linkGoToPage() ), this, TQT_SLOT( slotGoToPage() ) );
connect( m_document, TQT_SIGNAL( linkPresentation() ), this, TQT_SLOT( slotShowPresentation() ) );
connect( m_document, TQT_SIGNAL( linkEndPresentation() ), this, TQT_SLOT( slotHidePresentation() ) );
connect( m_document, TQT_SIGNAL( openURL(const KURL &) ), this, TQT_SLOT( openURLFromDocument(const KURL &) ) );
connect( m_document, TQT_SIGNAL( close() ), this, TQT_SLOT( close() ) );
if (parent && parent->metaObject()->slotNames(true).contains("slotQuit()"))
connect( m_document, TQT_SIGNAL( quit() ), parent, TQT_SLOT( slotQuit() ) );
else
connect( m_document, TQT_SIGNAL( quit() ), this, TQT_SLOT( cannotQuit() ) );
// widgets: ^searchbar (toolbar containing label and SearchWidget)
// m_searchToolBar = new TDEToolBar( parentWidget, "searchBar" );
// m_searchToolBar->boxLayout()->setSpacing( KDialog::spacingHint() );
// TQLabel * sLabel = new TQLabel( i18n( "&Search:" ), m_searchToolBar, "kde toolbar widget" );
// m_searchWidget = new SearchWidget( m_searchToolBar, m_document );
// sLabel->setBuddy( m_searchWidget );
// m_searchToolBar->setStretchableWidget( m_searchWidget );
// widgets: [] splitter []
m_splitter = new TQSplitter( parentWidget, widgetName );
m_splitter->setOpaqueResize( true );
setWidget( m_splitter );
m_showLeftPanel = new TDEToggleAction( i18n( "Show &Navigation Panel"), "show_side_panel", 0, this, TQT_SLOT( slotShowLeftPanel() ), actionCollection(), "show_leftpanel" );
m_showLeftPanel->setCheckedState( i18n( "Hide &Navigation Panel") );
m_showLeftPanel->setShortcut( "CTRL+L" );
m_showLeftPanel->setChecked( KpdfSettings::showLeftPanel() );
// widgets: [left panel] | []
m_leftPanel = new TQWidget( m_splitter );
m_leftPanel->setMinimumWidth( 90 );
m_leftPanel->setMaximumWidth( 300 );
TQVBoxLayout * leftPanelLayout = new TQVBoxLayout( m_leftPanel );
// widgets: [left toolbox/..] | []
m_toolBox = new TQToolBox( m_leftPanel );
leftPanelLayout->addWidget( m_toolBox );
int index;
// [left toolbox: Table of Contents] | []
// dummy wrapper with layout to enable horizontal scroll bars (bug: 147233)
TQWidget *tocWrapper = new TQWidget(m_toolBox);
TQVBoxLayout *tocWrapperLayout = new TQVBoxLayout(tocWrapper);
m_tocFrame = new TOC( tocWrapper, m_document );
tocWrapperLayout->add(m_tocFrame);
connect(m_tocFrame, TQT_SIGNAL(hasTOC(bool)), this, TQT_SLOT(enableTOC(bool)));
index = m_toolBox->addItem( tocWrapper, TQIconSet(SmallIcon("text_left")), i18n("Contents") );
m_toolBox->setItemToolTip(index, i18n("Contents"));
enableTOC( false );
// [left toolbox: Thumbnails and Bookmarks] | []
TQVBox * thumbsBox = new ThumbnailsBox( m_toolBox );
m_searchWidget = new SearchWidget( thumbsBox, m_document );
m_thumbnailList = new ThumbnailList( thumbsBox, m_document );
// ThumbnailController * m_tc = new ThumbnailController( thumbsBox, m_thumbnailList );
connect( m_thumbnailList, TQT_SIGNAL( urlDropped( const KURL& ) ), TQT_SLOT( openURLFromDocument( const KURL & )) );
connect( m_thumbnailList, TQT_SIGNAL( rightClick(const KPDFPage *, const TQPoint &) ), this, TQT_SLOT( slotShowMenu(const KPDFPage *, const TQPoint &) ) );
// shrink the bottom controller toolbar (too hackish..)
thumbsBox->setStretchFactor( m_searchWidget, 100 );
thumbsBox->setStretchFactor( m_thumbnailList, 100 );
// thumbsBox->setStretchFactor( m_tc, 1 );
index = m_toolBox->addItem( thumbsBox, TQIconSet(SmallIcon("thumbnail")), i18n("Thumbnails") );
m_toolBox->setItemToolTip(index, i18n("Thumbnails"));
m_toolBox->setCurrentItem( thumbsBox );
slotShowLeftPanel();
/* // [left toolbox: Annotations] | []
TQFrame * editFrame = new TQFrame( m_toolBox );
int iIdx = m_toolBox->addItem( editFrame, TQIconSet(SmallIcon("pencil")), i18n("Annotations") );
m_toolBox->setItemEnabled( iIdx, false );*/
// widgets: [../miniBarContainer] | []
TQWidget * miniBarContainer = new TQWidget( m_leftPanel );
leftPanelLayout->addWidget( miniBarContainer );
TQVBoxLayout * miniBarLayout = new TQVBoxLayout( miniBarContainer );
// widgets: [../[spacer/..]] | []
TQWidget * miniSpacer = new TQWidget( miniBarContainer );
miniSpacer->setFixedHeight( 6 );
miniBarLayout->addWidget( miniSpacer );
// widgets: [../[../MiniBar]] | []
m_miniBar = new MiniBar( miniBarContainer, m_document );
miniBarLayout->addWidget( m_miniBar );
// widgets: [] | [right 'pageView']
m_pageView = new PageView( m_splitter, m_document );
m_pageView->setFocus(); //usability setting
m_splitter->setFocusProxy(m_pageView);
connect( m_pageView, TQT_SIGNAL( urlDropped( const KURL& ) ), TQT_SLOT( openURLFromDocument( const KURL & )));
connect( m_pageView, TQT_SIGNAL( rightClick(const KPDFPage *, const TQPoint &) ), this, TQT_SLOT( slotShowMenu(const KPDFPage *, const TQPoint &) ) );
// add document observers
m_document->addObserver( this );
m_document->addObserver( m_thumbnailList );
m_document->addObserver( m_pageView );
m_document->addObserver( m_tocFrame );
m_document->addObserver( m_miniBar );
// ACTIONS
TDEActionCollection * ac = actionCollection();
// Page Traversal actions
m_gotoPage = KStdAction::gotoPage( this, TQT_SLOT( slotGoToPage() ), ac, "goto_page" );
m_gotoPage->setShortcut( "CTRL+G" );
// dirty way to activate gotopage when pressing miniBar's button
connect( m_miniBar, TQT_SIGNAL( gotoPage() ), m_gotoPage, TQT_SLOT( activate() ) );
m_prevPage = KStdAction::prior(this, TQT_SLOT(slotPreviousPage()), ac, "previous_page");
m_prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) );
m_prevPage->setShortcut( 0 );
// dirty way to activate prev page when pressing miniBar's button
connect( m_miniBar, TQT_SIGNAL( prevPage() ), m_prevPage, TQT_SLOT( activate() ) );
m_nextPage = KStdAction::next(this, TQT_SLOT(slotNextPage()), ac, "next_page" );
m_nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) );
m_nextPage->setShortcut( 0 );
// dirty way to activate next page when pressing miniBar's button
connect( m_miniBar, TQT_SIGNAL( nextPage() ), m_nextPage, TQT_SLOT( activate() ) );
m_firstPage = KStdAction::firstPage( this, TQT_SLOT( slotGotoFirst() ), ac, "first_page" );
m_firstPage->setWhatsThis( i18n( "Moves to the first page of the document" ) );
m_lastPage = KStdAction::lastPage( this, TQT_SLOT( slotGotoLast() ), ac, "last_page" );
m_lastPage->setWhatsThis( i18n( "Moves to the last page of the document" ) );
m_historyBack = KStdAction::back( this, TQT_SLOT( slotHistoryBack() ), ac, "history_back" );
m_historyBack->setWhatsThis( i18n( "Go to the place you were before" ) );
m_historyNext = KStdAction::forward( this, TQT_SLOT( slotHistoryNext() ), ac, "history_forward" );
m_historyNext->setWhatsThis( i18n( "Go to the place you were after" ) );
// Find and other actions
m_find = KStdAction::find( this, TQT_SLOT( slotFind() ), ac, "find" );
m_find->setEnabled( false );
m_findNext = KStdAction::findNext( this, TQT_SLOT( slotFindNext() ), ac, "find_next" );
m_findNext->setEnabled( false );
m_saveAs = KStdAction::saveAs( this, TQT_SLOT( slotSaveFileAs() ), ac, "save" );
m_saveAs->setEnabled( false );
TDEAction * prefs = KStdAction::preferences( this, TQT_SLOT( slotPreferences() ), ac, "preferences" );
prefs->setText( i18n( "Configure KPDF..." ) );
m_printPreview = KStdAction::printPreview( this, TQT_SLOT( slotPrintPreview() ), ac );
m_printPreview->setEnabled( false );
m_showProperties = new TDEAction(i18n("&Properties"), "info", 0, this, TQT_SLOT(slotShowProperties()), ac, "properties");
m_showProperties->setEnabled( false );
m_showPresentation = new TDEAction( i18n("P&resentation"), "kpresenter_kpr", "Ctrl+Shift+P", this, TQT_SLOT(slotShowPresentation()), ac, "presentation");
m_showPresentation->setEnabled( false );
// attach the actions of the children widgets too
m_pageView->setupActions( ac );
// apply configuration (both internal settings and GUI configured items)
TQValueList<int> splitterSizes = KpdfSettings::splitterSizes();
if ( !splitterSizes.count() )
{
// the first time use 1/10 for the panel and 9/10 for the pageView
splitterSizes.push_back( 50 );
splitterSizes.push_back( 500 );
}
m_splitter->setSizes( splitterSizes );
// get notified about splitter size changes (HACK that will be removed
// by connecting to TQt4::TQSplitter's sliderMoved())
m_pageView->installEventFilter( this );
m_watcher = new KDirWatch( this );
connect( m_watcher, TQT_SIGNAL( dirty( const TQString& ) ), this, TQT_SLOT( slotFileDirty( const TQString& ) ) );
m_dirtyHandler = new TQTimer( this );
connect( m_dirtyHandler, TQT_SIGNAL( timeout() ),this, TQT_SLOT( slotDoFileDirty() ) );
m_saveSplitterSizeTimer = new TQTimer( this );
connect( m_saveSplitterSizeTimer, TQT_SIGNAL( timeout() ),this, TQT_SLOT( saveSplitterSize() ) );
slotNewConfig();
// [SPEECH] check for KTTSD presence and usability
TDETrader::OfferList offers = TDETrader::self()->query("DCOP/Text-to-Speech", "Name == 'KTTSD'");
KpdfSettings::setUseKTTSD( (offers.count() > 0) );
KpdfSettings::writeConfig();
// set our XML-UI resource file
setXMLFile("part.rc");
updateViewActions();
}
Part::~Part()
{
delete m_tocFrame;
delete m_pageView;
delete m_thumbnailList;
delete m_miniBar;
delete m_document;
if ( --m_count == 0 )
delete globalParams;
}
void Part::notifyViewportChanged( bool /*smoothMove*/ )
{
// update actions if the page is changed
static int lastPage = -1;
int viewportPage = m_document->viewport().pageNumber;
if ( viewportPage != lastPage )
{
updateViewActions();
lastPage = viewportPage;
}
}
void Part::goToPage(uint i)
{
if ( i <= m_document->pages() )
m_document->setViewportPage( i - 1 );
}
void Part::openDocument(KURL doc)
{
openURL(doc);
}
uint Part::pages()
{
return m_document->pages();
}
uint Part::currentPage()
{
if ( m_document->pages() == 0 ) return 0;
else return m_document->currentPage()+1;
}
KURL Part::currentDocument()
{
return m_document->currentDocument();
}
//this don't go anywhere but is required by genericfactory.h
TDEAboutData* Part::createAboutData()
{
// the non-i18n name here must be the same as the directory in
// which the part's rc file is installed ('partrcdir' in the
// Makefile)
TDEAboutData* aboutData = new TDEAboutData("kpdfpart", I18N_NOOP("KPDF::Part"), "0.1");
aboutData->addAuthor("Wilco Greven", 0, "greven@kde.org");
return aboutData;
}
bool Part::openFile()
{
KMimeType::Ptr mime;
if ( m_bExtension->urlArgs().serviceType.isEmpty() )
{
if (!m_jobMime.isEmpty())
{
mime = KMimeType::mimeType(m_jobMime);
if ( mime->is( "application/octet-stream" ) )
{
mime = KMimeType::findByPath( m_file );
}
}
else
{
mime = KMimeType::findByPath( m_file );
}
}
else
{
mime = KMimeType::mimeType( m_bExtension->urlArgs().serviceType );
}
if ( (*mime).is( "application/postscript" ) )
{
TQString app = TDEStandardDirs::findExe( "ps2pdf" );
if ( !app.isNull() )
{
if ( TQFile::exists(m_file) )
{
KTempFile tf( TQString(), ".pdf" );
if ( tf.status() == 0 )
{
tf.close();
m_temporaryLocalFile = tf.name();
TDEProcess *p = new TDEProcess;
*p << app;
*p << m_file << m_temporaryLocalFile;
m_pageView->showText(i18n("Converting from ps to pdf..."), 0);
connect(p, TQT_SIGNAL(processExited(TDEProcess *)), this, TQT_SLOT(psTransformEnded()));
p -> start();
return true;
}
else return false;
}
else return false;
}
else
{
KMessageBox::error(widget(), i18n("You do not have ps2pdf installed, so kpdf cannot open postscript files."));
return false;
}
}
m_temporaryLocalFile = TQString();
bool ok = m_document->openDocument( m_file, url(), mime );
// update one-time actions
m_find->setEnabled( ok && m_document-> supportsSearching());
m_findNext->setEnabled( ok && m_document-> supportsSearching());
m_saveAs->setEnabled( ok );
m_printPreview->setEnabled( ok );
m_showProperties->setEnabled( ok );
m_showPresentation->setEnabled( ok );
// update viewing actions
updateViewActions();
if ( !ok )
{
// if can't open document, update windows so they display blank contents
m_pageView->updateContents();
m_thumbnailList->updateContents();
return false;
}
// set the file to the fileWatcher
if ( !m_watcher->contains(m_file) )
m_watcher->addFile(m_file);
// if the 'OpenTOC' flag is set, open the TOC
if ( m_document->getMetaData( "OpenTOC" ) == "yes" && m_toolBox->isItemEnabled( 0 ) )
{
m_toolBox->setCurrentIndex( 0 );
}
// if the 'StartFullScreen' flag is set, start presentation
if ( m_document->getMetaData( "StartFullScreen" ) == "yes" )
{
KMessageBox::information(m_presentationWidget, i18n("The document is going to be launched on presentation mode because the file requested it."), TQString(), "autoPresentationWarning");
slotShowPresentation();
}
return true;
}
void Part::openURLFromDocument(const KURL &url)
{
m_bExtension->openURLNotify();
m_bExtension->setLocationBarURL(url.prettyURL());
openURL(url);
}
bool Part::openURL(const KURL &url)
{
// note: this can be the right place to check the file for gz or bz2 extension
// if it matches then: download it (if not local) extract to a temp file using
// KTar and proceed with the URL of the temporary file
m_jobMime = TQString();
// this calls the above 'openURL' method
bool b = KParts::ReadOnlyPart::openURL(url);
// these setWindowCaption calls only work for local files
if ( !b )
{
KMessageBox::error( widget(), i18n("Could not open %1").arg( url.prettyURL() ) );
emit setWindowCaption("");
}
else
{
m_viewportDirty.pageNumber = -1;
emit setWindowCaption(url.filename());
}
emit enablePrintAction(b);
return b;
}
void Part::setMimeTypes(TDEIO::Job *job)
{
if (job)
{
job->addMetaData("accept", "application/pdf, */*;q=0.5");
connect(job, TQT_SIGNAL(mimetype(TDEIO::Job*,const TQString&)), this, TQT_SLOT(readMimeType(TDEIO::Job*,const TQString&)));
}
}
void Part::readMimeType(TDEIO::Job *, const TQString &mime)
{
m_jobMime = mime;
}
void Part::emitWindowCaption()
{
// these setWindowCaption call only works for remote files
if (m_document->isOpened()) emit setWindowCaption(url().filename());
else emit setWindowCaption("");
}
bool Part::closeURL()
{
if (!m_temporaryLocalFile.isNull())
{
TQFile::remove( m_temporaryLocalFile );
m_temporaryLocalFile = TQString();
}
slotHidePresentation();
m_find->setEnabled( false );
m_findNext->setEnabled( false );
m_saveAs->setEnabled( false );
m_printPreview->setEnabled( false );
m_showProperties->setEnabled( false );
m_showPresentation->setEnabled( false );
emit setWindowCaption("");
emit enablePrintAction(false);
m_searchStarted = false;
if (!m_file.isEmpty()) m_watcher->removeFile(m_file);
m_document->closeDocument();
updateViewActions();
m_searchWidget->clearText();
return KParts::ReadOnlyPart::closeURL();
}
bool Part::eventFilter( TQObject * watched, TQEvent * e )
{
// if pageView has been resized, save splitter sizes
if ( TQT_BASE_OBJECT(watched) == TQT_BASE_OBJECT(m_pageView) && e->type() == TQEvent::Resize )
m_saveSplitterSizeTimer->start(500, true);
// only intercept events, don't block them
return false;
}
void Part::slotShowLeftPanel()
{
bool showLeft = m_showLeftPanel->isChecked();
KpdfSettings::setShowLeftPanel(showLeft);
KpdfSettings::writeConfig();
// show/hide left qtoolbox
m_leftPanel->setShown( showLeft );
// this needs to be hidden explicitly to disable thumbnails gen
m_thumbnailList->setShown( showLeft );
}
void Part::slotFileDirty( const TQString& fileName )
{
// The beauty of this is that each start cancels the previous one.
// This means that timeout() is only fired when there have
// no changes to the file for the last 750 milisecs.
// This is supposed to ensure that we don't update on every other byte
// that gets written to the file.
if ( fileName == m_file )
{
m_dirtyHandler->start( 750, true );
}
}
void Part::slotDoFileDirty()
{
if (m_viewportDirty.pageNumber == -1)
{
m_viewportDirty = m_document->viewport();
m_dirtyToolboxIndex = m_toolBox->currentIndex();
m_wasPresentationOpen = ((PresentationWidget*)m_presentationWidget != 0);
m_pageView->showText(i18n("Reloading the document..."), 0);
}
if (KParts::ReadOnlyPart::openURL(KURL::fromPathOrURL(m_file)))
{
if (m_viewportDirty.pageNumber >= (int)m_document->pages()) m_viewportDirty.pageNumber = (int)m_document->pages() - 1;
m_document->setViewport(m_viewportDirty);
m_viewportDirty.pageNumber = -1;
if ( m_toolBox->currentIndex() != m_dirtyToolboxIndex && m_toolBox->isItemEnabled( m_dirtyToolboxIndex ) )
{
m_toolBox->setCurrentIndex( m_dirtyToolboxIndex );
}
if (m_wasPresentationOpen) slotShowPresentation();
emit enablePrintAction(true);
emit setWindowCaption(url().filename());
}
else
{
m_watcher->addFile(m_file);
m_dirtyHandler->start( 750, true );
}
}
void Part::close()
{
if (parent() && strcmp(parent()->name(), "KPDF::Shell") == 0)
{
closeURL();
}
else KMessageBox::information(widget(), i18n("This link points to a close document action that does not work when using the embedded viewer."), TQString(), "warnNoCloseIfNotInKPDF");
}
void Part::updateViewActions()
{
bool opened = m_document->pages() > 0;
if ( opened )
{
bool atBegin = m_document->currentPage() < 1;
bool atEnd = m_document->currentPage() >= (m_document->pages() - 1);
m_gotoPage->setEnabled( m_document->pages() > 1 );
m_firstPage->setEnabled( !atBegin );
m_prevPage->setEnabled( !atBegin );
m_lastPage->setEnabled( !atEnd );
m_nextPage->setEnabled( !atEnd );
m_historyBack->setEnabled( !m_document->historyAtBegin() );
m_historyNext->setEnabled( !m_document->historyAtEnd() );
}
else
{
m_gotoPage->setEnabled( false );
m_firstPage->setEnabled( false );
m_lastPage->setEnabled( false );
m_prevPage->setEnabled( false );
m_nextPage->setEnabled( false );
m_historyBack->setEnabled( false );
m_historyNext->setEnabled( false );
}
}
void Part::enableTOC(bool enable)
{
m_toolBox->setItemEnabled(0, enable);
}
void Part::psTransformEnded()
{
TQString aux = m_file;
m_file = m_temporaryLocalFile;
openFile();
m_file = aux; // so watching works, we have to watch the ps file not the autogenerated pdf
m_watcher->removeFile(m_temporaryLocalFile);
if ( !m_watcher->contains(m_file) )
m_watcher->addFile(m_file);
}
void Part::cannotQuit()
{
KMessageBox::information(widget(), i18n("This link points to a quit application action that does not work when using the embedded viewer."), TQString(), "warnNoQuitIfNotInKPDF");
}
void Part::saveSplitterSize()
{
KpdfSettings::setSplitterSizes( m_splitter->sizes() );
KpdfSettings::writeConfig();
}
//BEGIN go to page dialog
class KPDFGotoPageDialog : public KDialogBase
{
public:
KPDFGotoPageDialog(TQWidget *p, int current, int max) : KDialogBase(p, 0L, true, i18n("Go to Page"), Ok | Cancel, Ok) {
TQWidget *w = new TQWidget(this);
setMainWidget(w);
TQVBoxLayout *topLayout = new TQVBoxLayout( w, 0, spacingHint() );
e1 = new KIntNumInput(current, w);
e1->setRange(1, max);
e1->setEditFocus(true);
TQLabel *label = new TQLabel( e1,i18n("&Page:"), w );
topLayout->addWidget(label);
topLayout->addWidget(e1);
topLayout->addSpacing(spacingHint()); // A little bit extra space
topLayout->addStretch(10);
e1->setFocus();
}
int getPage() {
return e1->value();
}
protected:
KIntNumInput *e1;
};
//END go to page dialog
void Part::slotGoToPage()
{
KPDFGotoPageDialog pageDialog( m_pageView, m_document->currentPage() + 1, m_document->pages() );
if ( pageDialog.exec() == TQDialog::Accepted )
m_document->setViewportPage( pageDialog.getPage() - 1 );
}
void Part::slotPreviousPage()
{
if ( m_document->isOpened() && !(m_document->currentPage() < 1) )
m_document->setViewportPage( m_document->currentPage() - 1 );
}
void Part::slotNextPage()
{
if ( m_document->isOpened() && m_document->currentPage() < (m_document->pages() - 1) )
m_document->setViewportPage( m_document->currentPage() + 1 );
}
void Part::slotGotoFirst()
{
if ( m_document->isOpened() )
m_document->setViewportPage( 0 );
}
void Part::slotGotoLast()
{
if ( m_document->isOpened() )
m_document->setViewportPage( m_document->pages() - 1 );
}
void Part::slotHistoryBack()
{
m_document->setPrevViewport();
}
void Part::slotHistoryNext()
{
m_document->setNextViewport();
}
void Part::slotFind()
{
static bool savedCaseSensitive = false;
KFindDialog dlg( widget() );
dlg.setHasCursor( false );
if ( !m_searchHistory.empty() )
dlg.setFindHistory( m_searchHistory );
#if KDE_IS_VERSION(3,3,90)
dlg.setSupportsBackwardsFind( false );
dlg.setSupportsWholeWordsFind( false );
dlg.setSupportsRegularExpressionFind( false );
#endif
if ( savedCaseSensitive )
{
dlg.setOptions( dlg.options() | KFindDialog::CaseSensitive );
}
if ( dlg.exec() == TQDialog::Accepted )
{
savedCaseSensitive = dlg.options() & KFindDialog::CaseSensitive;
m_searchHistory = dlg.findHistory();
m_searchStarted = true;
m_document->resetSearch( PART_SEARCH_ID );
m_document->searchText( PART_SEARCH_ID, dlg.pattern(), false, savedCaseSensitive,
KPDFDocument::NextMatch, true, tqRgb( 255, 255, 64 ) );
}
}
void Part::slotFindNext()
{
if (!m_document->continueLastSearch())
slotFind();
}
void Part::slotSaveFileAs()
{
KURL saveURL = KFileDialog::getSaveURL( url().isLocalFile() ? url().url() : url().fileName(), TQString(), widget() );
if ( saveURL.isValid() && !saveURL.isEmpty() )
{
if (saveURL == url())
{
KMessageBox::information( widget(), i18n("You are trying to overwrite \"%1\" with itself. This is not allowed. Please save it in another location.").arg(saveURL.filename()) );
return;
}
if ( TDEIO::NetAccess::exists( saveURL, false, widget() ) )
{
if (KMessageBox::warningContinueCancel( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?").arg(saveURL.filename()), TQString(), i18n("Overwrite")) != KMessageBox::Continue)
return;
}
if ( !TDEIO::NetAccess::file_copy( m_file, saveURL, -1, true ) )
KMessageBox::information( 0, i18n("File could not be saved in '%1'. Try to save it to another location.").arg( saveURL.prettyURL() ) );
}
}
void Part::slotPreferences()
{
// an instance the dialog could be already created and could be cached,
// in which case you want to display the cached dialog
if ( PreferencesDialog::showDialog( "preferences" ) )
return;
// we didn't find an instance of this dialog, so lets create it
PreferencesDialog * dialog = new PreferencesDialog( m_pageView, KpdfSettings::self() );
// keep us informed when the user changes settings
connect( dialog, TQT_SIGNAL( settingsChanged() ), this, TQT_SLOT( slotNewConfig() ) );
dialog->show();
}
void Part::slotNewConfig()
{
// Apply settings here. A good policy is to check wether the setting has
// changed before applying changes.
// Watch File
bool watchFile = KpdfSettings::watchFile();
if ( watchFile && m_watcher->isStopped() )
m_watcher->startScan();
if ( !watchFile && !m_watcher->isStopped() )
{
m_dirtyHandler->stop();
m_watcher->stopScan();
}
bool showSearch = KpdfSettings::showSearchBar();
if ( m_searchWidget->isShown() != showSearch )
m_searchWidget->setShown( showSearch );
// Main View (pageView)
TQScrollView::ScrollBarMode scrollBarMode = KpdfSettings::showScrollBars() ?
TQScrollView::AlwaysOn : TQScrollView::AlwaysOff;
if ( m_pageView->hScrollBarMode() != scrollBarMode )
{
m_pageView->setHScrollBarMode( scrollBarMode );
m_pageView->setVScrollBarMode( scrollBarMode );
}
// update document settings
m_document->reparseConfig();
// update Main View and ThumbnailList contents
// TODO do this only when changing KpdfSettings::renderMode()
m_pageView->updateContents();
if ( KpdfSettings::showLeftPanel() && m_thumbnailList->isShown() )
m_thumbnailList->updateWidgets();
}
void Part::slotPrintPreview()
{
if (m_document->pages() == 0) return;
double width, height;
int landscape, portrait;
KPrinter printer;
const KPDFPage *page;
printer.setMinMax(1, m_document->pages());
printer.setPreviewOnly( true );
// if some pages are landscape and others are not the most common win as kprinter does
// not accept a per page setting
landscape = 0;
portrait = 0;
for (uint i = 0; i < m_document->pages(); i++)
{
page = m_document->page(i);
width = page->width();
height = page->height();
if (page->rotation() == 90 || page->rotation() == 270) tqSwap(width, height);
if (width > height) landscape++;
else portrait++;
}
if (landscape > portrait) printer.setOption("orientation-requested", "4");
doPrint(printer);
}
void Part::slotShowMenu(const KPDFPage *page, const TQPoint &point)
{
bool reallyShow = false;
if (!m_actionsSearched)
{
// the quest for options_show_menubar
KXMLGUIClient *client;
TDEActionCollection *ac;
TDEActionPtrList::const_iterator it, end, begin;
TDEActionPtrList actions;
if (factory())
{
TQPtrList<KXMLGUIClient> clients(factory()->clients());
TQPtrListIterator<KXMLGUIClient> clientsIt( clients );
for( ; (!m_showMenuBarAction || !m_showFullScreenAction) && clientsIt.current(); ++clientsIt)
{
client = clientsIt.current();
ac = client->actionCollection();
actions = ac->actions();
end = actions.end();
begin = actions.begin();
for ( it = begin; it != end; ++it )
{
if (TQString((*it)->name()) == "options_show_menubar") m_showMenuBarAction = (TDEToggleAction*)(*it);
if (TQString((*it)->name()) == "fullscreen") m_showFullScreenAction = (TDEToggleAction*)(*it);
}
}
}
m_actionsSearched = true;
}
TDEPopupMenu *popup = new TDEPopupMenu( widget(), "rmb popup" );
if (page)
{
popup->insertTitle( i18n( "Page %1" ).arg( page->number() + 1 ) );
if ( page->hasBookmark() )
popup->insertItem( SmallIcon("bookmark"), i18n("Remove Bookmark"), 1 );
else
popup->insertItem( SmallIcon("bookmark_add"), i18n("Add Bookmark"), 1 );
if ( m_pageView->canFitPageWidth() )
popup->insertItem( SmallIcon("viewmagfit"), i18n("Fit Width"), 2 );
//popup->insertItem( SmallIcon("pencil"), i18n("Edit"), 3 );
//popup->setItemEnabled( 3, false );
reallyShow = true;
}
/*
//Albert says: I have not ported this as i don't see it does anything
if ( d->mouseOnRect ) // and rect->objectType() == ObjectRect::Image ...
{
m_popup->insertItem( SmallIcon("filesave"), i18n("Save Image..."), 4 );
m_popup->setItemEnabled( 4, false );
}*/
if ((m_showMenuBarAction && !m_showMenuBarAction->isChecked()) || (m_showFullScreenAction && m_showFullScreenAction->isChecked()))
{
popup->insertTitle( i18n( "Tools" ) );
if (m_showMenuBarAction && !m_showMenuBarAction->isChecked()) m_showMenuBarAction->plug(popup);
if (m_showFullScreenAction && m_showFullScreenAction->isChecked()) m_showFullScreenAction->plug(popup);
reallyShow = true;
}
if (reallyShow)
{
switch ( popup->exec(point) )
{
case 1:
m_document->toggleBookmark( page->number() );
break;
case 2:
m_pageView->fitPageWidth( page->number() );
break;
// case 3: // switch to edit mode
// break;
}
}
delete popup;
}
void Part::slotShowProperties()
{
PropertiesDialog *d = new PropertiesDialog(widget(), m_document);
d->exec();
delete d;
}
void Part::slotShowPresentation()
{
if ( !m_presentationWidget )
{
m_presentationWidget = new PresentationWidget( widget(), m_document );
m_presentationWidget->setupActions( actionCollection() );
}
}
void Part::slotHidePresentation()
{
if ( m_presentationWidget )
delete (PresentationWidget*) m_presentationWidget;
}
void Part::slotTogglePresentation()
{
if ( m_document->isOpened() )
{
if ( !m_presentationWidget )
{
m_presentationWidget = new PresentationWidget( widget(), m_document );
m_presentationWidget->setupActions( actionCollection() );
}
else delete (PresentationWidget*) m_presentationWidget;
}
}
void Part::slotPrint()
{
if (m_document->pages() == 0) return;
double width, height;
int landscape, portrait;
KPrinter printer;
const KPDFPage *page;
printer.setPageSelection(KPrinter::ApplicationSide);
printer.setMinMax(1, m_document->pages());
printer.setCurrentPage(m_document->currentPage()+1);
// if some pages are landscape and others are not the most common win as kprinter does
// not accept a per page setting
landscape = 0;
portrait = 0;
for (uint i = 0; i < m_document->pages(); i++)
{
page = m_document->page(i);
width = page->width();
height = page->height();
if (page->rotation() == 90 || page->rotation() == 270) tqSwap(width, height);
if (width > height) landscape++;
else portrait++;
}
if (landscape > portrait) printer.setOrientation(KPrinter::Landscape);
KPrinter::addDialogPage(new PDFOptionsPage());
if (printer.setup(widget())) doPrint( printer );
}
void Part::doPrint(KPrinter &printer)
{
if (!m_document->isAllowed(KPDFDocument::AllowPrint))
{
KMessageBox::error(widget(), i18n("Printing this document is not allowed."));
return;
}
if (!m_document->print(printer))
{
KMessageBox::error(widget(), i18n("Could not print the document. Please report to bugs.kde.org"));
}
}
void Part::restoreDocument(TDEConfig* config)
{
KURL url ( config->readPathEntry( "URL" ) );
if ( url.isValid() )
{
TQString viewport = config->readEntry( "Viewport" );
if (!viewport.isEmpty()) m_document->setNextDocumentViewport( DocumentViewport( viewport ) );
openURL( url );
}
}
void Part::saveDocumentRestoreInfo(TDEConfig* config)
{
config->writePathEntry( "URL", url().url() );
config->writeEntry( "Viewport", m_document->viewport().toString() );
}
/*
* BrowserExtension class
*/
BrowserExtension::BrowserExtension(Part* parent)
: KParts::BrowserExtension( parent, "KPDF::BrowserExtension" )
{
emit enableAction("print", true);
setURLDropHandlingEnabled(true);
}
void BrowserExtension::print()
{
static_cast<Part*>(parent())->slotPrint();
}
#include "part.moc"