TDE core libraries
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.

part.cpp 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. /* This file is part of the KDE project
  2. Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
  3. (C) 1999 David Faure <faure@kde.org>
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public
  6. License as published by the Free Software Foundation; either
  7. version 2 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public License
  13. along with this library; see the file COPYING.LIB. If not, write to
  14. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  15. Boston, MA 02110-1301, USA.
  16. */
  17. #include <tdeparts/part.h>
  18. #include <tdeparts/event.h>
  19. #include <tdeparts/plugin.h>
  20. #include <tdeparts/mainwindow.h>
  21. #include <tdeparts/partmanager.h>
  22. #include <tqapplication.h>
  23. #include <tqfile.h>
  24. #include <tqpoint.h>
  25. #include <tqpointarray.h>
  26. #include <tqpainter.h>
  27. #include <tqtextstream.h>
  28. #include <tqfileinfo.h>
  29. #include <kinstance.h>
  30. #include <tdelocale.h>
  31. #include <tdetempfile.h>
  32. #include <tdemessagebox.h>
  33. #include <tdeio/job.h>
  34. #include <kstandarddirs.h>
  35. #include <tdefiledialog.h>
  36. #include <kdirnotify_stub.h>
  37. #include <stdio.h>
  38. #include <unistd.h>
  39. #include <assert.h>
  40. #include <kdebug.h>
  41. template class TQPtrList<KXMLGUIClient>;
  42. using namespace KParts;
  43. namespace KParts
  44. {
  45. class PartBasePrivate
  46. {
  47. public:
  48. PartBasePrivate()
  49. {
  50. m_pluginLoadingMode = PartBase::LoadPlugins;
  51. }
  52. ~PartBasePrivate()
  53. {
  54. }
  55. PartBase::PluginLoadingMode m_pluginLoadingMode;
  56. };
  57. class PartPrivate
  58. {
  59. public:
  60. PartPrivate()
  61. {
  62. m_bSelectable = true;
  63. }
  64. ~PartPrivate()
  65. {
  66. }
  67. bool m_bSelectable;
  68. };
  69. }
  70. PartBase::PartBase()
  71. {
  72. d = new PartBasePrivate;
  73. m_obj = 0L;
  74. }
  75. PartBase::~PartBase()
  76. {
  77. delete d;
  78. }
  79. void PartBase::setPartObject( TQObject *obj )
  80. {
  81. m_obj = obj;
  82. }
  83. TQObject *PartBase::partObject() const
  84. {
  85. return m_obj;
  86. }
  87. void PartBase::setInstance( TDEInstance *inst )
  88. {
  89. setInstance( inst, true );
  90. }
  91. void PartBase::setInstance( TDEInstance *inst, bool bLoadPlugins )
  92. {
  93. KXMLGUIClient::setInstance( inst );
  94. TDEGlobal::locale()->insertCatalogue( inst->instanceName() );
  95. // install 'instancename'data resource type
  96. TDEGlobal::dirs()->addResourceType( inst->instanceName() + "data",
  97. TDEStandardDirs::kde_default( "data" )
  98. + TQString::fromLatin1( inst->instanceName() ) + '/' );
  99. if ( bLoadPlugins )
  100. loadPlugins( m_obj, this, instance() );
  101. }
  102. void PartBase::loadPlugins( TQObject *parent, KXMLGUIClient *parentGUIClient, TDEInstance *instance )
  103. {
  104. if( d->m_pluginLoadingMode != DoNotLoadPlugins )
  105. Plugin::loadPlugins( parent, parentGUIClient, instance, d->m_pluginLoadingMode == LoadPlugins );
  106. }
  107. void PartBase::setPluginLoadingMode( PluginLoadingMode loadingMode )
  108. {
  109. d->m_pluginLoadingMode = loadingMode;
  110. }
  111. Part::Part( TQObject *parent, const char* name )
  112. : TQObject( parent, name )
  113. {
  114. d = new PartPrivate;
  115. m_widget = 0L;
  116. m_manager = 0L;
  117. PartBase::setPartObject( this );
  118. }
  119. Part::~Part()
  120. {
  121. kdDebug(1000) << "Part::~Part " << this << endl;
  122. if ( m_widget )
  123. {
  124. // We need to disconnect first, to avoid calling it !
  125. disconnect( m_widget, TQT_SIGNAL( destroyed() ),
  126. this, TQT_SLOT( slotWidgetDestroyed() ) );
  127. }
  128. if ( m_manager )
  129. m_manager->removePart(this);
  130. if ( m_widget )
  131. {
  132. kdDebug(1000) << "deleting widget " << m_widget << " " << m_widget->name() << endl;
  133. delete (TQWidget*) m_widget;
  134. }
  135. delete d;
  136. }
  137. void Part::embed( TQWidget * parentWidget )
  138. {
  139. if ( widget() )
  140. widget()->reparent( parentWidget, 0, TQPoint( 0, 0 ), true );
  141. }
  142. TQWidget *Part::widget()
  143. {
  144. return m_widget;
  145. }
  146. void Part::setManager( PartManager *manager )
  147. {
  148. m_manager = manager;
  149. }
  150. PartManager *Part::manager() const
  151. {
  152. return m_manager;
  153. }
  154. Part *Part::hitTest( TQWidget *widget, const TQPoint & )
  155. {
  156. if ( (TQWidget *)m_widget != widget )
  157. return 0L;
  158. return this;
  159. }
  160. void Part::setWidget( TQWidget *widget )
  161. {
  162. assert ( !m_widget ); // otherwise we get two connects
  163. m_widget = widget;
  164. connect( m_widget, TQT_SIGNAL( destroyed() ),
  165. this, TQT_SLOT( slotWidgetDestroyed() ) );
  166. // Tell the actionCollection() which widget its
  167. // action shortcuts should be connected to.
  168. actionCollection()->setWidget( widget );
  169. // Since KParts objects are XML-based, shortcuts should
  170. // be connected to the widget when the XML settings
  171. // are processed, rather than on TDEAction construction.
  172. actionCollection()->setAutoConnectShortcuts( false );
  173. }
  174. void Part::setSelectable( bool selectable )
  175. {
  176. d->m_bSelectable = selectable;
  177. }
  178. bool Part::isSelectable() const
  179. {
  180. return d->m_bSelectable;
  181. }
  182. void Part::customEvent( TQCustomEvent *event )
  183. {
  184. if ( PartActivateEvent::test( event ) )
  185. {
  186. partActivateEvent( (PartActivateEvent *)event );
  187. return;
  188. }
  189. if ( PartSelectEvent::test( event ) )
  190. {
  191. partSelectEvent( (PartSelectEvent *)event );
  192. return;
  193. }
  194. if ( GUIActivateEvent::test( event ) )
  195. {
  196. guiActivateEvent( (GUIActivateEvent *)event );
  197. return;
  198. }
  199. TQObject::customEvent( event );
  200. }
  201. void Part::partActivateEvent( PartActivateEvent * )
  202. {
  203. }
  204. void Part::partSelectEvent( PartSelectEvent * )
  205. {
  206. }
  207. void Part::guiActivateEvent( GUIActivateEvent * )
  208. {
  209. }
  210. TQWidget *Part::hostContainer( const TQString &containerName )
  211. {
  212. if ( !factory() )
  213. return 0L;
  214. return factory()->container( containerName, this );
  215. }
  216. void Part::slotWidgetDestroyed()
  217. {
  218. kdDebug(1000) << "KPart::slotWidgetDestroyed(), deleting part " << name() << endl;
  219. m_widget = 0;
  220. delete this;
  221. }
  222. //////////////////////////////////////////////////
  223. namespace KParts
  224. {
  225. class ReadOnlyPartPrivate
  226. {
  227. public:
  228. ReadOnlyPartPrivate()
  229. {
  230. m_job = 0L;
  231. m_uploadJob = 0L;
  232. m_showProgressInfo = true;
  233. m_saveOk = false;
  234. m_waitForSave = false;
  235. m_duringSaveAs = false;
  236. }
  237. ~ReadOnlyPartPrivate()
  238. {
  239. }
  240. TDEIO::FileCopyJob * m_job;
  241. TDEIO::FileCopyJob * m_uploadJob;
  242. KURL m_originalURL; // for saveAs
  243. TQString m_originalFilePath; // for saveAs
  244. bool m_showProgressInfo : 1;
  245. bool m_saveOk : 1;
  246. bool m_waitForSave : 1;
  247. bool m_duringSaveAs : 1;
  248. };
  249. }
  250. ReadOnlyPart::ReadOnlyPart( TQObject *parent, const char *name )
  251. : Part( parent, name ), m_bTemp( false )
  252. {
  253. d = new ReadOnlyPartPrivate;
  254. }
  255. ReadOnlyPart::~ReadOnlyPart()
  256. {
  257. ReadOnlyPart::closeURL();
  258. delete d;
  259. }
  260. void ReadOnlyPart::setProgressInfoEnabled( bool show )
  261. {
  262. d->m_showProgressInfo = show;
  263. }
  264. bool ReadOnlyPart::isProgressInfoEnabled() const
  265. {
  266. return d->m_showProgressInfo;
  267. }
  268. #ifndef KDE_NO_COMPAT
  269. void ReadOnlyPart::showProgressInfo( bool show )
  270. {
  271. d->m_showProgressInfo = show;
  272. }
  273. #endif
  274. bool ReadOnlyPart::openURL( const KURL &url )
  275. {
  276. if ( !url.isValid() )
  277. return false;
  278. if ( !closeURL() )
  279. return false;
  280. m_url = url;
  281. if ( m_url.isLocalFile() )
  282. {
  283. emit started( 0 );
  284. m_file = m_url.path();
  285. bool ret = openFile();
  286. if (ret)
  287. {
  288. emit completed();
  289. emit setWindowCaption( m_url.prettyURL() );
  290. };
  291. return ret;
  292. }
  293. else
  294. {
  295. m_bTemp = true;
  296. // Use same extension as remote file. This is important for mimetype-determination (e.g. koffice)
  297. TQString fileName = url.fileName();
  298. TQFileInfo fileInfo(fileName);
  299. TQString ext = fileInfo.extension();
  300. TQString extension;
  301. if ( !ext.isEmpty() && url.query().isNull() ) // not if the URL has a query, e.g. cgi.pl?something
  302. extension = "."+ext; // keep the '.'
  303. KTempFile tempFile( TQString::null, extension );
  304. m_file = tempFile.name();
  305. KURL destURL;
  306. destURL.setPath( m_file );
  307. d->m_job = TDEIO::file_copy( m_url, destURL, 0600, true, false, d->m_showProgressInfo );
  308. d->m_job->setWindow( widget() ? widget()->topLevelWidget() : 0 );
  309. emit started( d->m_job );
  310. connect( d->m_job, TQT_SIGNAL( result( TDEIO::Job * ) ), this, TQT_SLOT( slotJobFinished ( TDEIO::Job * ) ) );
  311. return true;
  312. }
  313. }
  314. void ReadOnlyPart::abortLoad()
  315. {
  316. if ( d->m_job )
  317. {
  318. //kdDebug(1000) << "Aborting job " << d->m_job << endl;
  319. d->m_job->kill();
  320. d->m_job = 0;
  321. }
  322. }
  323. bool ReadOnlyPart::closeURL()
  324. {
  325. abortLoad(); //just in case
  326. if ( m_bTemp )
  327. {
  328. unlink( TQFile::encodeName(m_file) );
  329. m_bTemp = false;
  330. }
  331. // It always succeeds for a read-only part,
  332. // but the return value exists for reimplementations
  333. // (e.g. pressing cancel for a modified read-write part)
  334. return true;
  335. }
  336. void ReadOnlyPart::slotJobFinished( TDEIO::Job * job )
  337. {
  338. kdDebug(1000) << "ReadOnlyPart::slotJobFinished" << endl;
  339. assert( job == d->m_job );
  340. d->m_job = 0;
  341. if (job->error())
  342. emit canceled( job->errorString() );
  343. else
  344. {
  345. if ( openFile() )
  346. emit setWindowCaption( m_url.prettyURL() );
  347. emit completed();
  348. }
  349. }
  350. void ReadOnlyPart::guiActivateEvent( GUIActivateEvent * event )
  351. {
  352. if (event->activated())
  353. {
  354. if (!m_url.isEmpty())
  355. {
  356. kdDebug(1000) << "ReadOnlyPart::guiActivateEvent -> " << m_url.prettyURL() << endl;
  357. emit setWindowCaption( m_url.prettyURL() );
  358. } else emit setWindowCaption( "" );
  359. }
  360. }
  361. bool ReadOnlyPart::openStream( const TQString& mimeType, const KURL& url )
  362. {
  363. if ( !closeURL() )
  364. return false;
  365. m_url = url;
  366. return doOpenStream( mimeType );
  367. }
  368. bool ReadOnlyPart::writeStream( const TQByteArray& data )
  369. {
  370. return doWriteStream( data );
  371. }
  372. bool ReadOnlyPart::closeStream()
  373. {
  374. return doCloseStream();
  375. }
  376. //////////////////////////////////////////////////
  377. ReadWritePart::ReadWritePart( TQObject *parent, const char *name )
  378. : ReadOnlyPart( parent, name ), m_bModified( false ), m_bClosing( false )
  379. {
  380. m_bReadWrite = true;
  381. }
  382. ReadWritePart::~ReadWritePart()
  383. {
  384. // parent destructor will delete temp file
  385. // we can't call our own closeURL() here, because
  386. // "cancel" wouldn't cancel anything. We have to assume
  387. // the app called closeURL() before destroying us.
  388. }
  389. void ReadWritePart::setReadWrite( bool readwrite )
  390. {
  391. // Perhaps we should check isModified here and issue a warning if true
  392. m_bReadWrite = readwrite;
  393. }
  394. void ReadWritePart::setModified( bool modified )
  395. {
  396. kdDebug(1000) << "ReadWritePart::setModified( " << (modified ? "true" : "false") << ")" << endl;
  397. if ( !m_bReadWrite && modified )
  398. {
  399. kdError(1000) << "Can't set a read-only document to 'modified' !" << endl;
  400. return;
  401. }
  402. m_bModified = modified;
  403. }
  404. void ReadWritePart::setModified()
  405. {
  406. setModified( true );
  407. }
  408. bool ReadWritePart::queryClose()
  409. {
  410. if ( !isReadWrite() || !isModified() )
  411. return true;
  412. TQString docName = url().fileName();
  413. if (docName.isEmpty()) docName = i18n( "Untitled" );
  414. int res = KMessageBox::warningYesNoCancel( widget(),
  415. i18n( "The document \"%1\" has been modified.\n"
  416. "Do you want to save your changes or discard them?" ).arg( docName ),
  417. i18n( "Close Document" ), KStdGuiItem::save(), KStdGuiItem::discard() );
  418. bool abortClose=false;
  419. bool handled=false;
  420. switch(res) {
  421. case KMessageBox::Yes :
  422. sigQueryClose(&handled,&abortClose);
  423. if (!handled)
  424. {
  425. if (m_url.isEmpty())
  426. {
  427. KURL url = KFileDialog::getSaveURL();
  428. if (url.isEmpty())
  429. return false;
  430. saveAs( url );
  431. }
  432. else
  433. {
  434. save();
  435. }
  436. } else if (abortClose) return false;
  437. return waitSaveComplete();
  438. case KMessageBox::No :
  439. return true;
  440. default : // case KMessageBox::Cancel :
  441. return false;
  442. }
  443. }
  444. bool ReadWritePart::closeURL()
  445. {
  446. abortLoad(); //just in case
  447. if ( isReadWrite() && isModified() )
  448. {
  449. if (!queryClose())
  450. return false;
  451. }
  452. // Not modified => ok and delete temp file.
  453. return ReadOnlyPart::closeURL();
  454. }
  455. bool ReadWritePart::closeURL( bool promptToSave )
  456. {
  457. return promptToSave ? closeURL() : ReadOnlyPart::closeURL();
  458. }
  459. bool ReadWritePart::save()
  460. {
  461. d->m_saveOk = false;
  462. if ( m_file.isEmpty() ) // document was created empty
  463. prepareSaving();
  464. if( saveFile() )
  465. return saveToURL();
  466. else
  467. emit canceled(TQString::null);
  468. return false;
  469. }
  470. bool ReadWritePart::saveAs( const KURL & kurl )
  471. {
  472. if (!kurl.isValid())
  473. {
  474. kdError(1000) << "saveAs: Malformed URL " << kurl.url() << endl;
  475. return false;
  476. }
  477. d->m_duringSaveAs = true;
  478. d->m_originalURL = m_url;
  479. d->m_originalFilePath = m_file;
  480. m_url = kurl; // Store where to upload in saveToURL
  481. prepareSaving();
  482. bool result = save(); // Save local file and upload local file
  483. if (result)
  484. emit setWindowCaption( m_url.prettyURL() );
  485. else
  486. {
  487. m_url = d->m_originalURL;
  488. m_file = d->m_originalFilePath;
  489. d->m_duringSaveAs = false;
  490. d->m_originalURL = KURL();
  491. d->m_originalFilePath = TQString::null;
  492. }
  493. return result;
  494. }
  495. // Set m_file correctly for m_url
  496. void ReadWritePart::prepareSaving()
  497. {
  498. // Local file
  499. if ( m_url.isLocalFile() )
  500. {
  501. if ( m_bTemp ) // get rid of a possible temp file first
  502. { // (happens if previous url was remote)
  503. unlink( TQFile::encodeName(m_file) );
  504. m_bTemp = false;
  505. }
  506. m_file = m_url.path();
  507. }
  508. else
  509. { // Remote file
  510. // We haven't saved yet, or we did but locally - provide a temp file
  511. if ( m_file.isEmpty() || !m_bTemp )
  512. {
  513. KTempFile tempFile;
  514. m_file = tempFile.name();
  515. m_bTemp = true;
  516. }
  517. // otherwise, we already had a temp file
  518. }
  519. }
  520. bool ReadWritePart::saveToURL()
  521. {
  522. if ( m_url.isLocalFile() )
  523. {
  524. setModified( false );
  525. emit completed();
  526. // if m_url is a local file there won't be a temp file -> nothing to remove
  527. assert( !m_bTemp );
  528. d->m_saveOk = true;
  529. d->m_duringSaveAs = false;
  530. d->m_originalURL = KURL();
  531. d->m_originalFilePath = TQString::null;
  532. return true; // Nothing to do
  533. }
  534. else
  535. {
  536. if (d->m_uploadJob)
  537. {
  538. unlink(TQFile::encodeName(d->m_uploadJob->srcURL().path()));
  539. d->m_uploadJob->kill();
  540. d->m_uploadJob = 0;
  541. }
  542. KTempFile tempFile;
  543. TQString uploadFile = tempFile.name();
  544. KURL uploadUrl;
  545. uploadUrl.setPath( uploadFile );
  546. tempFile.unlink();
  547. // Create hardlink
  548. if (::link(TQFile::encodeName(m_file), TQFile::encodeName(uploadFile)) != 0)
  549. {
  550. // Uh oh, some error happened.
  551. return false;
  552. }
  553. d->m_uploadJob = TDEIO::file_move( uploadUrl, m_url, -1, true /*overwrite*/ );
  554. d->m_uploadJob->setWindow( widget() ? widget()->topLevelWidget() : 0 );
  555. connect( d->m_uploadJob, TQT_SIGNAL( result( TDEIO::Job * ) ), this, TQT_SLOT( slotUploadFinished (TDEIO::Job *) ) );
  556. return true;
  557. }
  558. }
  559. void ReadWritePart::slotUploadFinished( TDEIO::Job * )
  560. {
  561. if (d->m_uploadJob->error())
  562. {
  563. unlink(TQFile::encodeName(d->m_uploadJob->srcURL().path()));
  564. TQString error = d->m_uploadJob->errorString();
  565. d->m_uploadJob = 0;
  566. if (d->m_duringSaveAs) {
  567. m_url = d->m_originalURL;
  568. m_file = d->m_originalFilePath;
  569. }
  570. emit canceled( error );
  571. }
  572. else
  573. {
  574. KDirNotify_stub allDirNotify("*", "KDirNotify*");
  575. KURL dirUrl( m_url );
  576. dirUrl.setPath( dirUrl.directory() );
  577. allDirNotify.FilesAdded( dirUrl );
  578. d->m_uploadJob = 0;
  579. setModified( false );
  580. emit completed();
  581. d->m_saveOk = true;
  582. }
  583. d->m_duringSaveAs = false;
  584. d->m_originalURL = KURL();
  585. d->m_originalFilePath = TQString::null;
  586. if (d->m_waitForSave)
  587. {
  588. tqApp->exit_loop();
  589. }
  590. }
  591. // Trolls: Nothing to see here, please step away.
  592. void tqt_enter_modal( TQWidget *widget );
  593. void tqt_leave_modal( TQWidget *widget );
  594. bool ReadWritePart::waitSaveComplete()
  595. {
  596. if (!d->m_uploadJob)
  597. return d->m_saveOk;
  598. d->m_waitForSave = true;
  599. TQWidget dummy(0,0,(WFlags)(WType_Dialog | WShowModal));
  600. dummy.setFocusPolicy( TQ_NoFocus );
  601. tqt_enter_modal(&dummy);
  602. tqApp->enter_loop();
  603. tqt_leave_modal(&dummy);
  604. d->m_waitForSave = false;
  605. return d->m_saveOk;
  606. }
  607. #include "part.moc"
  608. // vim:sw=2:ts=8:et