TDE graphics utilities
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.

1104 lines
37KB

  1. /***************************************************************************
  2. * Copyright (C) 2002 by Wilco Greven <greven@kde.org> *
  3. * Copyright (C) 2002 by Chris Cheney <ccheney@cheney.cx> *
  4. * Copyright (C) 2002 by Malcolm Hunter <malcolm.hunter@gmx.co.uk> *
  5. * Copyright (C) 2003-2004 by Christophe Devriese *
  6. * <Christophe.Devriese@student.kuleuven.ac.be> *
  7. * Copyright (C) 2003 by Daniel Molkentin <molkentin@kde.org> *
  8. * Copyright (C) 2003 by Andy Goossens <andygoossens@telenet.be> *
  9. * Copyright (C) 2003 by Dirk Mueller <mueller@kde.org> *
  10. * Copyright (C) 2003 by Laurent Montel <montel@kde.org> *
  11. * Copyright (C) 2004 by Dominique Devriese <devriese@kde.org> *
  12. * Copyright (C) 2004 by Christoph Cullmann <crossfire@babylon2k.de> *
  13. * Copyright (C) 2004 by Henrique Pinto <stampede@coltec.ufmg.br> *
  14. * Copyright (C) 2004 by Waldo Bastian <bastian@kde.org> *
  15. * Copyright (C) 2004-2006 by Albert Astals Cid <tsdgeos@terra.es> *
  16. * Copyright (C) 2004 by Antti Markus <antti.markus@starman.ee> *
  17. * *
  18. * This program is free software; you can redistribute it and/or modify *
  19. * it under the terms of the GNU General Public License as published by *
  20. * the Free Software Foundation; either version 2 of the License, or *
  21. * (at your option) any later version. *
  22. ***************************************************************************/
  23. // qt/kde includes
  24. #include <tqcheckbox.h>
  25. #include <tqsplitter.h>
  26. #include <tqpainter.h>
  27. #include <tqlayout.h>
  28. #include <tqlabel.h>
  29. #include <tqvbox.h>
  30. #include <tqtoolbox.h>
  31. #include <tqtooltip.h>
  32. #include <tqpushbutton.h>
  33. #include <tqwhatsthis.h>
  34. #include <dcopobject.h>
  35. #include <dcopclient.h>
  36. #include <tdeapplication.h>
  37. #include <tdeaction.h>
  38. #include <kdirwatch.h>
  39. #include <kinstance.h>
  40. #include <kprinter.h>
  41. #include <tdeprint/kprintdialogpage.h>
  42. #include <kstdaction.h>
  43. #include <tdeversion.h>
  44. #include <tdeparts/genericfactory.h>
  45. #include <kurldrag.h>
  46. #include <tdefiledialog.h>
  47. #include <tdemessagebox.h>
  48. #include <kfinddialog.h>
  49. #include <knuminput.h>
  50. #include <kiconloader.h>
  51. #include <tdeio/netaccess.h>
  52. #include <tdeio/job.h>
  53. #include <tdepopupmenu.h>
  54. #include <kprocess.h>
  55. #include <kstandarddirs.h>
  56. #include <tdetempfile.h>
  57. #include <ktrader.h>
  58. #include <kxmlguiclient.h>
  59. #include <kxmlguifactory.h>
  60. // local includes
  61. #include "xpdf/GlobalParams.h"
  62. #include "part.h"
  63. #include "ui/pageview.h"
  64. #include "ui/thumbnaillist.h"
  65. #include "ui/searchwidget.h"
  66. #include "ui/toc.h"
  67. #include "ui/minibar.h"
  68. #include "ui/propertiesdialog.h"
  69. #include "ui/presentationwidget.h"
  70. #include "conf/preferencesdialog.h"
  71. #include "conf/settings.h"
  72. #include "core/document.h"
  73. #include "core/page.h"
  74. class PDFOptionsPage : public KPrintDialogPage
  75. {
  76. public:
  77. PDFOptionsPage()
  78. {
  79. setTitle( i18n( "PDF Options" ) );
  80. TQVBoxLayout *layout = new TQVBoxLayout(this);
  81. m_forceRaster = new TQCheckBox(i18n("Force rasterization"), this);
  82. TQToolTip::add(m_forceRaster, i18n("Rasterize into an image before printing"));
  83. 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."));
  84. layout->addWidget(m_forceRaster);
  85. layout->addStretch(1);
  86. }
  87. void getOptions( TQMap<TQString,TQString>& opts, bool incldef = false )
  88. {
  89. Q_UNUSED(incldef);
  90. opts[ "kde-kpdf-forceRaster" ] = TQString::number( m_forceRaster->isChecked() );
  91. }
  92. void setOptions( const TQMap<TQString,TQString>& opts )
  93. {
  94. m_forceRaster->setChecked( opts[ "kde-kpdf-forceRaster" ].toInt() );
  95. }
  96. private:
  97. TQCheckBox *m_forceRaster;
  98. };
  99. // definition of searchID for this class
  100. #define PART_SEARCH_ID 1
  101. typedef KParts::GenericFactory<KPDF::Part> KPDFPartFactory;
  102. K_EXPORT_COMPONENT_FACTORY(libkpdfpart, KPDFPartFactory)
  103. using namespace KPDF;
  104. unsigned int Part::m_count = 0;
  105. Part::Part(TQWidget *parentWidget, const char *widgetName,
  106. TQObject *parent, const char *name,
  107. const TQStringList & /*args*/ )
  108. : DCOPObject("kpdf"), KParts::ReadOnlyPart(parent, name), m_showMenuBarAction(0), m_showFullScreenAction(0),
  109. m_actionsSearched(false), m_searchStarted(false)
  110. {
  111. // connect the started signal to tell the job the mimetypes we like
  112. connect(this, TQT_SIGNAL(started(TDEIO::Job *)), this, TQT_SLOT(setMimeTypes(TDEIO::Job *)));
  113. // connect the completed signal so we can put the window caption when loading remote files
  114. connect(this, TQT_SIGNAL(completed()), this, TQT_SLOT(emitWindowCaption()));
  115. connect(this, TQT_SIGNAL(canceled(const TQString &)), this, TQT_SLOT(emitWindowCaption()));
  116. // load catalog for translation
  117. TDEGlobal::locale()->insertCatalogue("kpdf");
  118. // create browser extension (for printing when embedded into browser)
  119. m_bExtension = new BrowserExtension(this);
  120. // xpdf 'extern' global class (m_count is a static instance counter)
  121. //if ( m_count ) TODO check if we need to insert these lines..
  122. // delete globalParams;
  123. globalParams = new GlobalParams("");
  124. globalParams->setupBaseFonts(NULL);
  125. m_count++;
  126. // we need an instance
  127. setInstance(KPDFPartFactory::instance());
  128. // build the document
  129. m_document = new KPDFDocument(widget());
  130. connect( m_document, TQT_SIGNAL( linkFind() ), this, TQT_SLOT( slotFind() ) );
  131. connect( m_document, TQT_SIGNAL( linkGoToPage() ), this, TQT_SLOT( slotGoToPage() ) );
  132. connect( m_document, TQT_SIGNAL( linkPresentation() ), this, TQT_SLOT( slotShowPresentation() ) );
  133. connect( m_document, TQT_SIGNAL( linkEndPresentation() ), this, TQT_SLOT( slotHidePresentation() ) );
  134. connect( m_document, TQT_SIGNAL( openURL(const KURL &) ), this, TQT_SLOT( openURLFromDocument(const KURL &) ) );
  135. connect( m_document, TQT_SIGNAL( close() ), this, TQT_SLOT( close() ) );
  136. if (parent && parent->metaObject()->slotNames(true).contains("slotQuit()"))
  137. connect( m_document, TQT_SIGNAL( quit() ), parent, TQT_SLOT( slotQuit() ) );
  138. else
  139. connect( m_document, TQT_SIGNAL( quit() ), this, TQT_SLOT( cannotQuit() ) );
  140. // widgets: ^searchbar (toolbar containing label and SearchWidget)
  141. // m_searchToolBar = new TDEToolBar( parentWidget, "searchBar" );
  142. // m_searchToolBar->boxLayout()->setSpacing( KDialog::spacingHint() );
  143. // TQLabel * sLabel = new TQLabel( i18n( "&Search:" ), m_searchToolBar, "tde toolbar widget" );
  144. // m_searchWidget = new SearchWidget( m_searchToolBar, m_document );
  145. // sLabel->setBuddy( m_searchWidget );
  146. // m_searchToolBar->setStretchableWidget( m_searchWidget );
  147. // widgets: [] splitter []
  148. m_splitter = new TQSplitter( parentWidget, widgetName );
  149. m_splitter->setOpaqueResize( true );
  150. setWidget( m_splitter );
  151. m_showLeftPanel = new TDEToggleAction( i18n( "Show &Navigation Panel"), "show_side_panel", 0, this, TQT_SLOT( slotShowLeftPanel() ), actionCollection(), "show_leftpanel" );
  152. m_showLeftPanel->setCheckedState( i18n( "Hide &Navigation Panel") );
  153. m_showLeftPanel->setShortcut( "CTRL+L" );
  154. m_showLeftPanel->setChecked( KpdfSettings::showLeftPanel() );
  155. // widgets: [left panel] | []
  156. m_leftPanel = new TQWidget( m_splitter );
  157. m_leftPanel->setMinimumWidth( 90 );
  158. m_leftPanel->setMaximumWidth( 300 );
  159. TQVBoxLayout * leftPanelLayout = new TQVBoxLayout( m_leftPanel );
  160. // widgets: [left toolbox/..] | []
  161. m_toolBox = new TQToolBox( m_leftPanel );
  162. leftPanelLayout->addWidget( m_toolBox );
  163. int index;
  164. // [left toolbox: Table of Contents] | []
  165. // dummy wrapper with layout to enable horizontal scroll bars (bug: 147233)
  166. TQWidget *tocWrapper = new TQWidget(m_toolBox);
  167. TQVBoxLayout *tocWrapperLayout = new TQVBoxLayout(tocWrapper);
  168. m_tocFrame = new TOC( tocWrapper, m_document );
  169. tocWrapperLayout->add(m_tocFrame);
  170. connect(m_tocFrame, TQT_SIGNAL(hasTOC(bool)), this, TQT_SLOT(enableTOC(bool)));
  171. index = m_toolBox->addItem( tocWrapper, TQIconSet(SmallIcon("format-text-direction-ltr")), i18n("Contents") );
  172. m_toolBox->setItemToolTip(index, i18n("Contents"));
  173. enableTOC( false );
  174. // [left toolbox: Thumbnails and Bookmarks] | []
  175. TQVBox * thumbsBox = new ThumbnailsBox( m_toolBox );
  176. m_searchWidget = new SearchWidget( thumbsBox, m_document );
  177. m_thumbnailList = new ThumbnailList( thumbsBox, m_document );
  178. // ThumbnailController * m_tc = new ThumbnailController( thumbsBox, m_thumbnailList );
  179. connect( m_thumbnailList, TQT_SIGNAL( urlDropped( const KURL& ) ), TQT_SLOT( openURLFromDocument( const KURL & )) );
  180. connect( m_thumbnailList, TQT_SIGNAL( rightClick(const KPDFPage *, const TQPoint &) ), this, TQT_SLOT( slotShowMenu(const KPDFPage *, const TQPoint &) ) );
  181. // shrink the bottom controller toolbar (too hackish..)
  182. thumbsBox->setStretchFactor( m_searchWidget, 100 );
  183. thumbsBox->setStretchFactor( m_thumbnailList, 100 );
  184. // thumbsBox->setStretchFactor( m_tc, 1 );
  185. index = m_toolBox->addItem( thumbsBox, TQIconSet(SmallIcon("thumbnail")), i18n("Thumbnails") );
  186. m_toolBox->setItemToolTip(index, i18n("Thumbnails"));
  187. m_toolBox->setCurrentItem( thumbsBox );
  188. slotShowLeftPanel();
  189. /* // [left toolbox: Annotations] | []
  190. TQFrame * editFrame = new TQFrame( m_toolBox );
  191. int iIdx = m_toolBox->addItem( editFrame, TQIconSet(SmallIcon("pencil")), i18n("Annotations") );
  192. m_toolBox->setItemEnabled( iIdx, false );*/
  193. // widgets: [../miniBarContainer] | []
  194. TQWidget * miniBarContainer = new TQWidget( m_leftPanel );
  195. leftPanelLayout->addWidget( miniBarContainer );
  196. TQVBoxLayout * miniBarLayout = new TQVBoxLayout( miniBarContainer );
  197. // widgets: [../[spacer/..]] | []
  198. TQWidget * miniSpacer = new TQWidget( miniBarContainer );
  199. miniSpacer->setFixedHeight( 6 );
  200. miniBarLayout->addWidget( miniSpacer );
  201. // widgets: [../[../MiniBar]] | []
  202. m_miniBar = new MiniBar( miniBarContainer, m_document );
  203. miniBarLayout->addWidget( m_miniBar );
  204. // widgets: [] | [right 'pageView']
  205. m_pageView = new PageView( m_splitter, m_document );
  206. m_pageView->setFocus(); //usability setting
  207. m_splitter->setFocusProxy(m_pageView);
  208. connect( m_pageView, TQT_SIGNAL( urlDropped( const KURL& ) ), TQT_SLOT( openURLFromDocument( const KURL & )));
  209. connect( m_pageView, TQT_SIGNAL( rightClick(const KPDFPage *, const TQPoint &) ), this, TQT_SLOT( slotShowMenu(const KPDFPage *, const TQPoint &) ) );
  210. // add document observers
  211. m_document->addObserver( this );
  212. m_document->addObserver( m_thumbnailList );
  213. m_document->addObserver( m_pageView );
  214. m_document->addObserver( m_tocFrame );
  215. m_document->addObserver( m_miniBar );
  216. // ACTIONS
  217. TDEActionCollection * ac = actionCollection();
  218. // Page Traversal actions
  219. m_gotoPage = KStdAction::gotoPage( this, TQT_SLOT( slotGoToPage() ), ac, "goto_page" );
  220. m_gotoPage->setShortcut( "CTRL+G" );
  221. // dirty way to activate gotopage when pressing miniBar's button
  222. connect( m_miniBar, TQT_SIGNAL( gotoPage() ), m_gotoPage, TQT_SLOT( activate() ) );
  223. m_prevPage = KStdAction::prior(this, TQT_SLOT(slotPreviousPage()), ac, "previous_page");
  224. m_prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) );
  225. m_prevPage->setShortcut( 0 );
  226. // dirty way to activate prev page when pressing miniBar's button
  227. connect( m_miniBar, TQT_SIGNAL( prevPage() ), m_prevPage, TQT_SLOT( activate() ) );
  228. m_nextPage = KStdAction::next(this, TQT_SLOT(slotNextPage()), ac, "next_page" );
  229. m_nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) );
  230. m_nextPage->setShortcut( 0 );
  231. // dirty way to activate next page when pressing miniBar's button
  232. connect( m_miniBar, TQT_SIGNAL( nextPage() ), m_nextPage, TQT_SLOT( activate() ) );
  233. m_firstPage = KStdAction::firstPage( this, TQT_SLOT( slotGotoFirst() ), ac, "first_page" );
  234. m_firstPage->setWhatsThis( i18n( "Moves to the first page of the document" ) );
  235. m_lastPage = KStdAction::lastPage( this, TQT_SLOT( slotGotoLast() ), ac, "last_page" );
  236. m_lastPage->setWhatsThis( i18n( "Moves to the last page of the document" ) );
  237. m_historyBack = KStdAction::back( this, TQT_SLOT( slotHistoryBack() ), ac, "history_back" );
  238. m_historyBack->setWhatsThis( i18n( "Go to the place you were before" ) );
  239. m_historyNext = KStdAction::forward( this, TQT_SLOT( slotHistoryNext() ), ac, "history_forward" );
  240. m_historyNext->setWhatsThis( i18n( "Go to the place you were after" ) );
  241. // Find and other actions
  242. m_find = KStdAction::find( this, TQT_SLOT( slotFind() ), ac, "find" );
  243. m_find->setEnabled( false );
  244. m_findNext = KStdAction::findNext( this, TQT_SLOT( slotFindNext() ), ac, "find_next" );
  245. m_findNext->setEnabled( false );
  246. m_saveAs = KStdAction::saveAs( this, TQT_SLOT( slotSaveFileAs() ), ac, "save" );
  247. m_saveAs->setEnabled( false );
  248. TDEAction * prefs = KStdAction::preferences( this, TQT_SLOT( slotPreferences() ), ac, "preferences" );
  249. prefs->setText( i18n( "Configure KPDF..." ) );
  250. m_printPreview = KStdAction::printPreview( this, TQT_SLOT( slotPrintPreview() ), ac );
  251. m_printPreview->setEnabled( false );
  252. m_showProperties = new TDEAction(i18n("&Properties"), "application-vnd.tde.info", 0, this, TQT_SLOT(slotShowProperties()), ac, "properties");
  253. m_showProperties->setEnabled( false );
  254. m_showPresentation = new TDEAction( i18n("P&resentation"), "application-x-kpresenter", "Ctrl+Shift+P", this, TQT_SLOT(slotShowPresentation()), ac, "presentation");
  255. m_showPresentation->setEnabled( false );
  256. // attach the actions of the children widgets too
  257. m_pageView->setupActions( ac );
  258. // apply configuration (both internal settings and GUI configured items)
  259. TQValueList<int> splitterSizes = KpdfSettings::splitterSizes();
  260. if ( !splitterSizes.count() )
  261. {
  262. // the first time use 1/10 for the panel and 9/10 for the pageView
  263. splitterSizes.push_back( 50 );
  264. splitterSizes.push_back( 500 );
  265. }
  266. m_splitter->setSizes( splitterSizes );
  267. // get notified about splitter size changes (HACK that will be removed
  268. // by connecting to TQt4::TQSplitter's sliderMoved())
  269. m_pageView->installEventFilter( this );
  270. m_watcher = new KDirWatch( this );
  271. connect( m_watcher, TQT_SIGNAL( dirty( const TQString& ) ), this, TQT_SLOT( slotFileDirty( const TQString& ) ) );
  272. m_dirtyHandler = new TQTimer( this );
  273. connect( m_dirtyHandler, TQT_SIGNAL( timeout() ),this, TQT_SLOT( slotDoFileDirty() ) );
  274. m_saveSplitterSizeTimer = new TQTimer( this );
  275. connect( m_saveSplitterSizeTimer, TQT_SIGNAL( timeout() ),this, TQT_SLOT( saveSplitterSize() ) );
  276. slotNewConfig();
  277. // [SPEECH] check for KTTSD presence and usability
  278. TDETrader::OfferList offers = TDETrader::self()->query("DCOP/Text-to-Speech", "Name == 'KTTSD'");
  279. KpdfSettings::setUseKTTSD( (offers.count() > 0) );
  280. KpdfSettings::writeConfig();
  281. // set our XML-UI resource file
  282. setXMLFile("part.rc");
  283. updateViewActions();
  284. }
  285. Part::~Part()
  286. {
  287. delete m_tocFrame;
  288. delete m_pageView;
  289. delete m_thumbnailList;
  290. delete m_miniBar;
  291. delete m_document;
  292. if ( --m_count == 0 )
  293. delete globalParams;
  294. }
  295. void Part::notifyViewportChanged( bool /*smoothMove*/ )
  296. {
  297. // update actions if the page is changed
  298. static int lastPage = -1;
  299. int viewportPage = m_document->viewport().pageNumber;
  300. if ( viewportPage != lastPage )
  301. {
  302. updateViewActions();
  303. lastPage = viewportPage;
  304. }
  305. }
  306. void Part::goToPage(uint i)
  307. {
  308. if ( i <= m_document->pages() )
  309. m_document->setViewportPage( i - 1 );
  310. }
  311. void Part::openDocument(KURL doc)
  312. {
  313. openURL(doc);
  314. }
  315. uint Part::pages()
  316. {
  317. return m_document->pages();
  318. }
  319. uint Part::currentPage()
  320. {
  321. if ( m_document->pages() == 0 ) return 0;
  322. else return m_document->currentPage()+1;
  323. }
  324. KURL Part::currentDocument()
  325. {
  326. return m_document->currentDocument();
  327. }
  328. //this don't go anywhere but is required by genericfactory.h
  329. TDEAboutData* Part::createAboutData()
  330. {
  331. // the non-i18n name here must be the same as the directory in
  332. // which the part's rc file is installed ('partrcdir' in the
  333. // Makefile)
  334. TDEAboutData* aboutData = new TDEAboutData("kpdfpart", I18N_NOOP("KPDF::Part"), "0.1");
  335. aboutData->addAuthor("Wilco Greven", 0, "greven@kde.org");
  336. return aboutData;
  337. }
  338. bool Part::openFile()
  339. {
  340. KMimeType::Ptr mime;
  341. if ( m_bExtension->urlArgs().serviceType.isEmpty() )
  342. {
  343. if (!m_jobMime.isEmpty())
  344. {
  345. mime = KMimeType::mimeType(m_jobMime);
  346. if ( mime->is( "application/octet-stream" ) )
  347. {
  348. mime = KMimeType::findByPath( m_file );
  349. }
  350. }
  351. else
  352. {
  353. mime = KMimeType::findByPath( m_file );
  354. }
  355. }
  356. else
  357. {
  358. mime = KMimeType::mimeType( m_bExtension->urlArgs().serviceType );
  359. }
  360. if ( (*mime).is( "application/postscript" ) )
  361. {
  362. TQString app = TDEStandardDirs::findExe( "ps2pdf" );
  363. if ( !app.isNull() )
  364. {
  365. if ( TQFile::exists(m_file) )
  366. {
  367. KTempFile tf( TQString(), ".pdf" );
  368. if ( tf.status() == 0 )
  369. {
  370. tf.close();
  371. m_temporaryLocalFile = tf.name();
  372. TDEProcess *p = new TDEProcess;
  373. *p << app;
  374. *p << m_file << m_temporaryLocalFile;
  375. m_pageView->showText(i18n("Converting from ps to pdf..."), 0);
  376. connect(p, TQT_SIGNAL(processExited(TDEProcess *)), this, TQT_SLOT(psTransformEnded()));
  377. p -> start();
  378. return true;
  379. }
  380. else return false;
  381. }
  382. else return false;
  383. }
  384. else
  385. {
  386. KMessageBox::error(widget(), i18n("You do not have ps2pdf installed, so kpdf cannot open postscript files."));
  387. return false;
  388. }
  389. }
  390. m_temporaryLocalFile = TQString();
  391. bool ok = m_document->openDocument( m_file, url(), mime );
  392. // update one-time actions
  393. m_find->setEnabled( ok && m_document-> supportsSearching());
  394. m_findNext->setEnabled( ok && m_document-> supportsSearching());
  395. m_saveAs->setEnabled( ok );
  396. m_printPreview->setEnabled( ok );
  397. m_showProperties->setEnabled( ok );
  398. m_showPresentation->setEnabled( ok );
  399. // update viewing actions
  400. updateViewActions();
  401. if ( !ok )
  402. {
  403. // if can't open document, update windows so they display blank contents
  404. m_pageView->updateContents();
  405. m_thumbnailList->updateContents();
  406. return false;
  407. }
  408. // set the file to the fileWatcher
  409. if ( !m_watcher->contains(m_file) )
  410. m_watcher->addFile(m_file);
  411. // if the 'OpenTOC' flag is set, open the TOC
  412. if ( m_document->getMetaData( "OpenTOC" ) == "yes" && m_toolBox->isItemEnabled( 0 ) )
  413. {
  414. m_toolBox->setCurrentIndex( 0 );
  415. }
  416. // if the 'StartFullScreen' flag is set, start presentation
  417. if ( m_document->getMetaData( "StartFullScreen" ) == "yes" )
  418. {
  419. KMessageBox::information(m_presentationWidget, i18n("The document is going to be launched on presentation mode because the file requested it."), TQString(), "autoPresentationWarning");
  420. slotShowPresentation();
  421. }
  422. return true;
  423. }
  424. void Part::openURLFromDocument(const KURL &url)
  425. {
  426. m_bExtension->openURLNotify();
  427. m_bExtension->setLocationBarURL(url.prettyURL());
  428. openURL(url);
  429. }
  430. bool Part::openURL(const KURL &url)
  431. {
  432. // note: this can be the right place to check the file for gz or bz2 extension
  433. // if it matches then: download it (if not local) extract to a temp file using
  434. // KTar and proceed with the URL of the temporary file
  435. m_jobMime = TQString();
  436. // this calls the above 'openURL' method
  437. bool b = KParts::ReadOnlyPart::openURL(url);
  438. // these setWindowCaption calls only work for local files
  439. if ( !b )
  440. {
  441. KMessageBox::error( widget(), i18n("Could not open %1").arg( url.prettyURL() ) );
  442. emit setWindowCaption("");
  443. }
  444. else
  445. {
  446. m_viewportDirty.pageNumber = -1;
  447. emit setWindowCaption(url.filename());
  448. }
  449. emit enablePrintAction(b);
  450. return b;
  451. }
  452. void Part::setMimeTypes(TDEIO::Job *job)
  453. {
  454. if (job)
  455. {
  456. job->addMetaData("accept", "application/pdf, */*;q=0.5");
  457. connect(job, TQT_SIGNAL(mimetype(TDEIO::Job*,const TQString&)), this, TQT_SLOT(readMimeType(TDEIO::Job*,const TQString&)));
  458. }
  459. }
  460. void Part::readMimeType(TDEIO::Job *, const TQString &mime)
  461. {
  462. m_jobMime = mime;
  463. }
  464. void Part::emitWindowCaption()
  465. {
  466. // these setWindowCaption call only works for remote files
  467. if (m_document->isOpened()) emit setWindowCaption(url().filename());
  468. else emit setWindowCaption("");
  469. }
  470. bool Part::closeURL()
  471. {
  472. if (!m_temporaryLocalFile.isNull())
  473. {
  474. TQFile::remove( m_temporaryLocalFile );
  475. m_temporaryLocalFile = TQString();
  476. }
  477. slotHidePresentation();
  478. m_find->setEnabled( false );
  479. m_findNext->setEnabled( false );
  480. m_saveAs->setEnabled( false );
  481. m_printPreview->setEnabled( false );
  482. m_showProperties->setEnabled( false );
  483. m_showPresentation->setEnabled( false );
  484. emit setWindowCaption("");
  485. emit enablePrintAction(false);
  486. m_searchStarted = false;
  487. if (!m_file.isEmpty()) m_watcher->removeFile(m_file);
  488. m_document->closeDocument();
  489. updateViewActions();
  490. m_searchWidget->clearText();
  491. return KParts::ReadOnlyPart::closeURL();
  492. }
  493. bool Part::eventFilter( TQObject * watched, TQEvent * e )
  494. {
  495. // if pageView has been resized, save splitter sizes
  496. if ( TQT_BASE_OBJECT(watched) == TQT_BASE_OBJECT(m_pageView) && e->type() == TQEvent::Resize )
  497. m_saveSplitterSizeTimer->start(500, true);
  498. // only intercept events, don't block them
  499. return false;
  500. }
  501. void Part::slotShowLeftPanel()
  502. {
  503. bool showLeft = m_showLeftPanel->isChecked();
  504. KpdfSettings::setShowLeftPanel(showLeft);
  505. KpdfSettings::writeConfig();
  506. // show/hide left qtoolbox
  507. m_leftPanel->setShown( showLeft );
  508. // this needs to be hidden explicitly to disable thumbnails gen
  509. m_thumbnailList->setShown( showLeft );
  510. }
  511. void Part::slotFileDirty( const TQString& fileName )
  512. {
  513. // The beauty of this is that each start cancels the previous one.
  514. // This means that timeout() is only fired when there have
  515. // no changes to the file for the last 750 milisecs.
  516. // This is supposed to ensure that we don't update on every other byte
  517. // that gets written to the file.
  518. if ( fileName == m_file )
  519. {
  520. m_dirtyHandler->start( 750, true );
  521. }
  522. }
  523. void Part::slotDoFileDirty()
  524. {
  525. if (m_viewportDirty.pageNumber == -1)
  526. {
  527. m_viewportDirty = m_document->viewport();
  528. m_dirtyToolboxIndex = m_toolBox->currentIndex();
  529. m_wasPresentationOpen = ((PresentationWidget*)m_presentationWidget != 0);
  530. m_pageView->showText(i18n("Reloading the document..."), 0);
  531. }
  532. if (KParts::ReadOnlyPart::openURL(KURL::fromPathOrURL(m_file)))
  533. {
  534. if (m_viewportDirty.pageNumber >= (int)m_document->pages()) m_viewportDirty.pageNumber = (int)m_document->pages() - 1;
  535. m_document->setViewport(m_viewportDirty);
  536. m_viewportDirty.pageNumber = -1;
  537. if ( m_toolBox->currentIndex() != m_dirtyToolboxIndex && m_toolBox->isItemEnabled( m_dirtyToolboxIndex ) )
  538. {
  539. m_toolBox->setCurrentIndex( m_dirtyToolboxIndex );
  540. }
  541. if (m_wasPresentationOpen) slotShowPresentation();
  542. emit enablePrintAction(true);
  543. emit setWindowCaption(url().filename());
  544. }
  545. else
  546. {
  547. m_watcher->addFile(m_file);
  548. m_dirtyHandler->start( 750, true );
  549. }
  550. }
  551. void Part::close()
  552. {
  553. if (parent() && strcmp(parent()->name(), "KPDF::Shell") == 0)
  554. {
  555. closeURL();
  556. }
  557. else KMessageBox::information(widget(), i18n("This link points to a close document action that does not work when using the embedded viewer."), TQString(), "warnNoCloseIfNotInKPDF");
  558. }
  559. void Part::updateViewActions()
  560. {
  561. bool opened = m_document->pages() > 0;
  562. if ( opened )
  563. {
  564. bool atBegin = m_document->currentPage() < 1;
  565. bool atEnd = m_document->currentPage() >= (m_document->pages() - 1);
  566. m_gotoPage->setEnabled( m_document->pages() > 1 );
  567. m_firstPage->setEnabled( !atBegin );
  568. m_prevPage->setEnabled( !atBegin );
  569. m_lastPage->setEnabled( !atEnd );
  570. m_nextPage->setEnabled( !atEnd );
  571. m_historyBack->setEnabled( !m_document->historyAtBegin() );
  572. m_historyNext->setEnabled( !m_document->historyAtEnd() );
  573. }
  574. else
  575. {
  576. m_gotoPage->setEnabled( false );
  577. m_firstPage->setEnabled( false );
  578. m_lastPage->setEnabled( false );
  579. m_prevPage->setEnabled( false );
  580. m_nextPage->setEnabled( false );
  581. m_historyBack->setEnabled( false );
  582. m_historyNext->setEnabled( false );
  583. }
  584. }
  585. void Part::enableTOC(bool enable)
  586. {
  587. m_toolBox->setItemEnabled(0, enable);
  588. }
  589. void Part::psTransformEnded()
  590. {
  591. TQString aux = m_file;
  592. m_file = m_temporaryLocalFile;
  593. openFile();
  594. m_file = aux; // so watching works, we have to watch the ps file not the autogenerated pdf
  595. m_watcher->removeFile(m_temporaryLocalFile);
  596. if ( !m_watcher->contains(m_file) )
  597. m_watcher->addFile(m_file);
  598. }
  599. void Part::cannotQuit()
  600. {
  601. KMessageBox::information(widget(), i18n("This link points to a quit application action that does not work when using the embedded viewer."), TQString(), "warnNoQuitIfNotInKPDF");
  602. }
  603. void Part::saveSplitterSize()
  604. {
  605. KpdfSettings::setSplitterSizes( m_splitter->sizes() );
  606. KpdfSettings::writeConfig();
  607. }
  608. //BEGIN go to page dialog
  609. class KPDFGotoPageDialog : public KDialogBase
  610. {
  611. public:
  612. KPDFGotoPageDialog(TQWidget *p, int current, int max) : KDialogBase(p, 0L, true, i18n("Go to Page"), Ok | Cancel, Ok) {
  613. TQWidget *w = new TQWidget(this);
  614. setMainWidget(w);
  615. TQVBoxLayout *topLayout = new TQVBoxLayout( w, 0, spacingHint() );
  616. e1 = new KIntNumInput(current, w);
  617. e1->setRange(1, max);
  618. e1->setEditFocus(true);
  619. TQLabel *label = new TQLabel( e1,i18n("&Page:"), w );
  620. topLayout->addWidget(label);
  621. topLayout->addWidget(e1);
  622. topLayout->addSpacing(spacingHint()); // A little bit extra space
  623. topLayout->addStretch(10);
  624. e1->setFocus();
  625. }
  626. int getPage() {
  627. return e1->value();
  628. }
  629. protected:
  630. KIntNumInput *e1;
  631. };
  632. //END go to page dialog
  633. void Part::slotGoToPage()
  634. {
  635. KPDFGotoPageDialog pageDialog( m_pageView, m_document->currentPage() + 1, m_document->pages() );
  636. if ( pageDialog.exec() == TQDialog::Accepted )
  637. m_document->setViewportPage( pageDialog.getPage() - 1 );
  638. }
  639. void Part::slotPreviousPage()
  640. {
  641. if ( m_document->isOpened() && !(m_document->currentPage() < 1) )
  642. m_document->setViewportPage( m_document->currentPage() - 1 );
  643. }
  644. void Part::slotNextPage()
  645. {
  646. if ( m_document->isOpened() && m_document->currentPage() < (m_document->pages() - 1) )
  647. m_document->setViewportPage( m_document->currentPage() + 1 );
  648. }
  649. void Part::slotGotoFirst()
  650. {
  651. if ( m_document->isOpened() )
  652. m_document->setViewportPage( 0 );
  653. }
  654. void Part::slotGotoLast()
  655. {
  656. if ( m_document->isOpened() )
  657. m_document->setViewportPage( m_document->pages() - 1 );
  658. }
  659. void Part::slotHistoryBack()
  660. {
  661. m_document->setPrevViewport();
  662. }
  663. void Part::slotHistoryNext()
  664. {
  665. m_document->setNextViewport();
  666. }
  667. void Part::slotFind()
  668. {
  669. static bool savedCaseSensitive = false;
  670. KFindDialog dlg( widget() );
  671. dlg.setHasCursor( false );
  672. if ( !m_searchHistory.empty() )
  673. dlg.setFindHistory( m_searchHistory );
  674. #if KDE_IS_VERSION(3,3,90)
  675. dlg.setSupportsBackwardsFind( false );
  676. dlg.setSupportsWholeWordsFind( false );
  677. dlg.setSupportsRegularExpressionFind( false );
  678. #endif
  679. if ( savedCaseSensitive )
  680. {
  681. dlg.setOptions( dlg.options() | KFindDialog::CaseSensitive );
  682. }
  683. if ( dlg.exec() == TQDialog::Accepted )
  684. {
  685. savedCaseSensitive = dlg.options() & KFindDialog::CaseSensitive;
  686. m_searchHistory = dlg.findHistory();
  687. m_searchStarted = true;
  688. m_document->resetSearch( PART_SEARCH_ID );
  689. m_document->searchText( PART_SEARCH_ID, dlg.pattern(), false, savedCaseSensitive,
  690. KPDFDocument::NextMatch, true, tqRgb( 255, 255, 64 ) );
  691. }
  692. }
  693. void Part::slotFindNext()
  694. {
  695. if (!m_document->continueLastSearch())
  696. slotFind();
  697. }
  698. void Part::slotSaveFileAs()
  699. {
  700. KURL saveURL = KFileDialog::getSaveURL( url().isLocalFile() ? url().url() : url().fileName(), TQString(), widget() );
  701. if ( saveURL.isValid() && !saveURL.isEmpty() )
  702. {
  703. if (saveURL == url())
  704. {
  705. 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()) );
  706. return;
  707. }
  708. if ( TDEIO::NetAccess::exists( saveURL, false, widget() ) )
  709. {
  710. 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)
  711. return;
  712. }
  713. if ( !TDEIO::NetAccess::file_copy( m_file, saveURL, -1, true ) )
  714. KMessageBox::information( 0, i18n("File could not be saved in '%1'. Try to save it to another location.").arg( saveURL.prettyURL() ) );
  715. }
  716. }
  717. void Part::slotPreferences()
  718. {
  719. // an instance the dialog could be already created and could be cached,
  720. // in which case you want to display the cached dialog
  721. if ( PreferencesDialog::showDialog( "preferences" ) )
  722. return;
  723. // we didn't find an instance of this dialog, so lets create it
  724. PreferencesDialog * dialog = new PreferencesDialog( m_pageView, KpdfSettings::self() );
  725. // keep us informed when the user changes settings
  726. connect( dialog, TQT_SIGNAL( settingsChanged() ), this, TQT_SLOT( slotNewConfig() ) );
  727. dialog->show();
  728. }
  729. void Part::slotNewConfig()
  730. {
  731. // Apply settings here. A good policy is to check wether the setting has
  732. // changed before applying changes.
  733. // Watch File
  734. bool watchFile = KpdfSettings::watchFile();
  735. if ( watchFile && m_watcher->isStopped() )
  736. m_watcher->startScan();
  737. if ( !watchFile && !m_watcher->isStopped() )
  738. {
  739. m_dirtyHandler->stop();
  740. m_watcher->stopScan();
  741. }
  742. bool showSearch = KpdfSettings::showSearchBar();
  743. if ( m_searchWidget->isShown() != showSearch )
  744. m_searchWidget->setShown( showSearch );
  745. // Main View (pageView)
  746. TQScrollView::ScrollBarMode scrollBarMode = KpdfSettings::showScrollBars() ?
  747. TQScrollView::AlwaysOn : TQScrollView::AlwaysOff;
  748. if ( m_pageView->hScrollBarMode() != scrollBarMode )
  749. {
  750. m_pageView->setHScrollBarMode( scrollBarMode );
  751. m_pageView->setVScrollBarMode( scrollBarMode );
  752. }
  753. // update document settings
  754. m_document->reparseConfig();
  755. // update Main View and ThumbnailList contents
  756. // TODO do this only when changing KpdfSettings::renderMode()
  757. m_pageView->updateContents();
  758. if ( KpdfSettings::showLeftPanel() && m_thumbnailList->isShown() )
  759. m_thumbnailList->updateWidgets();
  760. }
  761. void Part::slotPrintPreview()
  762. {
  763. if (m_document->pages() == 0) return;
  764. double width, height;
  765. int landscape, portrait;
  766. KPrinter printer;
  767. const KPDFPage *page;
  768. printer.setMinMax(1, m_document->pages());
  769. printer.setPreviewOnly( true );
  770. // if some pages are landscape and others are not the most common win as kprinter does
  771. // not accept a per page setting
  772. landscape = 0;
  773. portrait = 0;
  774. for (uint i = 0; i < m_document->pages(); i++)
  775. {
  776. page = m_document->page(i);
  777. width = page->width();
  778. height = page->height();
  779. if (page->rotation() == 90 || page->rotation() == 270) tqSwap(width, height);
  780. if (width > height) landscape++;
  781. else portrait++;
  782. }
  783. if (landscape > portrait) printer.setOption("orientation-requested", "4");
  784. doPrint(printer);
  785. }
  786. void Part::slotShowMenu(const KPDFPage *page, const TQPoint &point)
  787. {
  788. bool reallyShow = false;
  789. if (!m_actionsSearched)
  790. {
  791. // the quest for options_show_menubar
  792. KXMLGUIClient *client;
  793. TDEActionCollection *ac;
  794. TDEActionPtrList::const_iterator it, end, begin;
  795. TDEActionPtrList actions;
  796. if (factory())
  797. {
  798. TQPtrList<KXMLGUIClient> clients(factory()->clients());
  799. TQPtrListIterator<KXMLGUIClient> clientsIt( clients );
  800. for( ; (!m_showMenuBarAction || !m_showFullScreenAction) && clientsIt.current(); ++clientsIt)
  801. {
  802. client = clientsIt.current();
  803. ac = client->actionCollection();
  804. actions = ac->actions();
  805. end = actions.end();
  806. begin = actions.begin();
  807. for ( it = begin; it != end; ++it )
  808. {
  809. if (TQString((*it)->name()) == "options_show_menubar") m_showMenuBarAction = (TDEToggleAction*)(*it);
  810. if (TQString((*it)->name()) == "fullscreen") m_showFullScreenAction = (TDEToggleAction*)(*it);
  811. }
  812. }
  813. }
  814. m_actionsSearched = true;
  815. }
  816. TDEPopupMenu *popup = new TDEPopupMenu( widget(), "rmb popup" );
  817. if (page)
  818. {
  819. popup->insertTitle( i18n( "Page %1" ).arg( page->number() + 1 ) );
  820. if ( page->hasBookmark() )
  821. popup->insertItem( SmallIcon("bookmark"), i18n("Remove Bookmark"), 1 );
  822. else
  823. popup->insertItem( SmallIcon("bookmark_add"), i18n("Add Bookmark"), 1 );
  824. if ( m_pageView->canFitPageWidth() )
  825. popup->insertItem( SmallIcon("zoom-fit-best"), i18n("Fit Width"), 2 );
  826. //popup->insertItem( SmallIcon("pencil"), i18n("Edit"), 3 );
  827. //popup->setItemEnabled( 3, false );
  828. reallyShow = true;
  829. }
  830. /*
  831. //Albert says: I have not ported this as i don't see it does anything
  832. if ( d->mouseOnRect ) // and rect->objectType() == ObjectRect::Image ...
  833. {
  834. m_popup->insertItem( SmallIcon("document-save"), i18n("Save Image..."), 4 );
  835. m_popup->setItemEnabled( 4, false );
  836. }*/
  837. if ((m_showMenuBarAction && !m_showMenuBarAction->isChecked()) || (m_showFullScreenAction && m_showFullScreenAction->isChecked()))
  838. {
  839. popup->insertTitle( i18n( "Tools" ) );
  840. if (m_showMenuBarAction && !m_showMenuBarAction->isChecked()) m_showMenuBarAction->plug(popup);
  841. if (m_showFullScreenAction && m_showFullScreenAction->isChecked()) m_showFullScreenAction->plug(popup);
  842. reallyShow = true;
  843. }
  844. if (reallyShow)
  845. {
  846. switch ( popup->exec(point) )
  847. {
  848. case 1:
  849. m_document->toggleBookmark( page->number() );
  850. break;
  851. case 2:
  852. m_pageView->fitPageWidth( page->number() );
  853. break;
  854. // case 3: // switch to edit mode
  855. // break;
  856. }
  857. }
  858. delete popup;
  859. }
  860. void Part::slotShowProperties()
  861. {
  862. PropertiesDialog *d = new PropertiesDialog(widget(), m_document);
  863. d->exec();
  864. delete d;
  865. }
  866. void Part::slotShowPresentation()
  867. {
  868. if ( !m_presentationWidget )
  869. {
  870. m_presentationWidget = new PresentationWidget( widget(), m_document );
  871. m_presentationWidget->setupActions( actionCollection() );
  872. }
  873. }
  874. void Part::slotHidePresentation()
  875. {
  876. if ( m_presentationWidget )
  877. delete (PresentationWidget*) m_presentationWidget;
  878. }
  879. void Part::slotTogglePresentation()
  880. {
  881. if ( m_document->isOpened() )
  882. {
  883. if ( !m_presentationWidget )
  884. {
  885. m_presentationWidget = new PresentationWidget( widget(), m_document );
  886. m_presentationWidget->setupActions( actionCollection() );
  887. }
  888. else delete (PresentationWidget*) m_presentationWidget;
  889. }
  890. }
  891. void Part::slotPrint()
  892. {
  893. if (m_document->pages() == 0) return;
  894. double width, height;
  895. int landscape, portrait;
  896. KPrinter printer;
  897. const KPDFPage *page;
  898. printer.setPageSelection(KPrinter::ApplicationSide);
  899. printer.setMinMax(1, m_document->pages());
  900. printer.setCurrentPage(m_document->currentPage()+1);
  901. // if some pages are landscape and others are not the most common win as kprinter does
  902. // not accept a per page setting
  903. landscape = 0;
  904. portrait = 0;
  905. for (uint i = 0; i < m_document->pages(); i++)
  906. {
  907. page = m_document->page(i);
  908. width = page->width();
  909. height = page->height();
  910. if (page->rotation() == 90 || page->rotation() == 270) tqSwap(width, height);
  911. if (width > height) landscape++;
  912. else portrait++;
  913. }
  914. if (landscape > portrait) printer.setOrientation(KPrinter::Landscape);
  915. KPrinter::addDialogPage(new PDFOptionsPage());
  916. if (printer.setup(widget())) doPrint( printer );
  917. }
  918. void Part::doPrint(KPrinter &printer)
  919. {
  920. if (!m_document->isAllowed(KPDFDocument::AllowPrint))
  921. {
  922. KMessageBox::error(widget(), i18n("Printing this document is not allowed."));
  923. return;
  924. }
  925. if (!m_document->print(printer))
  926. {
  927. KMessageBox::error(widget(), i18n("Could not print the document. Please report to bugs.trinitydesktop.org"));
  928. }
  929. }
  930. void Part::restoreDocument(TDEConfig* config)
  931. {
  932. KURL url ( config->readPathEntry( "URL" ) );
  933. if ( url.isValid() )
  934. {
  935. TQString viewport = config->readEntry( "Viewport" );
  936. if (!viewport.isEmpty()) m_document->setNextDocumentViewport( DocumentViewport( viewport ) );
  937. openURL( url );
  938. }
  939. }
  940. void Part::saveDocumentRestoreInfo(TDEConfig* config)
  941. {
  942. if ( url().isValid() )
  943. {
  944. config->writePathEntry( "URL", url().url() );
  945. config->writeEntry( "Viewport", m_document->viewport().toString() );
  946. }
  947. }
  948. /*
  949. * BrowserExtension class
  950. */
  951. BrowserExtension::BrowserExtension(Part* parent)
  952. : KParts::BrowserExtension( parent, "KPDF::BrowserExtension" )
  953. {
  954. emit enableAction("print", true);
  955. setURLDropHandlingEnabled(true);
  956. }
  957. void BrowserExtension::print()
  958. {
  959. static_cast<Part*>(parent())->slotPrint();
  960. }
  961. #include "part.moc"