00001 #include <sys/types.h>
00002 #include <sys/stat.h>
00003 #include <unistd.h>
00004
00005 #include <qpopupmenu.h>
00006 #include <qfile.h>
00007 #include <qlayout.h>
00008 #include <qmap.h>
00009 #include <qlabel.h>
00010 #include <qradiobutton.h>
00011 #include <qcheckbox.h>
00012
00013 #include <kmimetype.h>
00014 #include <kservice.h>
00015 #include <ktrader.h>
00016 #include <kapplication.h>
00017 #include <krun.h>
00018 #include <kdebug.h>
00019 #include <klocale.h>
00020 #include <kmessagebox.h>
00021 #include <kparts/part.h>
00022 #include <kparts/factory.h>
00023 #include <kparts/partmanager.h>
00024 #include <kparts/browserextension.h>
00025 #include <kfiledialog.h>
00026 #include <kmainwindow.h>
00027 #include <kaction.h>
00028 #include <kstatusbar.h>
00029 #include <khtml_part.h>
00030 #include <kpopupmenu.h>
00031 #include <kio/netaccess.h>
00032 #include <kdialogbase.h>
00033 #include <klineedit.h>
00034 #include <kshortcut.h>
00035 #include <kcompletion.h>
00036 #include <kdirwatch.h>
00037 #include <kdeversion.h>
00038 #include <kiconloader.h>
00039 #include <kuserprofile.h>
00040 #include <kencodingfiledialog.h>
00041
00042 #include <ktexteditor/view.h>
00043 #include <ktexteditor/document.h>
00044 #include <ktexteditor/viewcursorinterface.h>
00045
00046 #include "toplevel.h"
00047 #include "api.h"
00048 #include "core.h"
00049 #include "editorproxy.h"
00050 #include "documentationpart.h"
00051 #include "ksavealldialog.h"
00052
00053 #include "kdevproject.h"
00054 #include "urlutil.h"
00055 #include "mimewarningdialog.h"
00056
00057 #include "designer.h"
00058 #include "kdevlanguagesupport.h"
00059
00060 #include "partcontroller.h"
00061
00062 PartController *PartController::s_instance = 0;
00063
00064 using namespace MainWindowUtils;
00065
00066 struct HistoryEntry {
00067 KURL url;
00068 QString context;
00069
00070 HistoryEntry( const KURL& u, const QString& c ): url( u ), context( c ) {}
00071 };
00072
00073 PartController::PartController(QWidget *parent)
00074 : KDevPartController(parent), _editorFactory(0L)
00075 {
00076 connect(this, SIGNAL(partRemoved(KParts::Part*)), this, SLOT(slotPartRemoved(KParts::Part* )) );
00077 connect(this, SIGNAL(partAdded(KParts::Part*)), this, SLOT(slotPartAdded(KParts::Part* )) );
00078 connect(this, SIGNAL(activePartChanged(KParts::Part*)), this, SLOT(slotActivePartChanged(KParts::Part*)));
00079
00080 setupActions();
00081
00082 m_Current = m_history.end();
00083 m_isJumping = false;
00084
00085 m_openNextAsText = false;
00086 }
00087
00088
00089 PartController::~PartController()
00090 {
00091 }
00092
00093
00094 void PartController::createInstance(QWidget *parent)
00095 {
00096 if (!s_instance)
00097 s_instance = new PartController(parent);
00098 }
00099
00100
00101 PartController *PartController::getInstance()
00102 {
00103 return s_instance;
00104 }
00105
00106
00107 void PartController::setupActions()
00108 {
00109 KActionCollection *ac = TopLevel::getInstance()->main()->actionCollection();
00110
00111 KAction* newAction = KStdAction::open(this, SLOT(slotOpenFile()),
00112 ac, "file_open");
00113 newAction->setToolTip( i18n("Open file") );
00114 newAction->setWhatsThis( i18n("<b>Open file</b><p>Opens an existing file without adding it to the project.</p>") );
00115
00116 m_openRecentAction = KStdAction::openRecent( this, SLOT(slotOpenRecent(const KURL&) ),
00117 ac, "file_open_recent" );
00118 m_openRecentAction->setWhatsThis(QString("<b>%1</b><p>%2").arg(beautifyToolTip(m_openRecentAction->text())).arg(i18n("Opens recently opened file.")));
00119 m_openRecentAction->loadEntries( kapp->config(), "RecentFiles" );
00120
00121 m_saveAllFilesAction = new KAction(i18n("Save Al&l"), 0,
00122 this, SLOT(slotSaveAllFiles()),
00123 ac, "file_save_all");
00124 m_saveAllFilesAction->setToolTip( i18n("Save all modified files") );
00125 m_saveAllFilesAction->setWhatsThis(i18n("<b>Save all</b><p>Saves all modified files."));
00126 m_saveAllFilesAction->setEnabled(false);
00127
00128 m_revertAllFilesAction = new KAction(i18n("Rever&t All"), 0,
00129 this, SLOT(slotRevertAllFiles()),
00130 ac, "file_revert_all");
00131 m_revertAllFilesAction->setToolTip(i18n("Revert all changes"));
00132 m_revertAllFilesAction->setWhatsThis(i18n("<b>Revert all</b><p>Reverts all changes in opened files. Prompts to save changes so the reversion can be canceled for each modified file."));
00133 m_revertAllFilesAction->setEnabled(false);
00134
00135 m_closeWindowAction = KStdAction::close(
00136 this, SLOT(slotCloseWindow()),
00137 ac, "file_close");
00138 m_closeWindowAction->setToolTip( i18n("Close current file") );
00139 m_closeWindowAction->setWhatsThis(QString("<b>%1</b><p>%2").arg(beautifyToolTip(m_closeWindowAction->text())).arg(i18n("Closes current file.")));
00140 m_closeWindowAction->setEnabled(false);
00141
00142 m_closeAllWindowsAction = new KAction(i18n("Close All"), 0,
00143 this, SLOT(slotCloseAllWindows()),
00144 ac, "file_close_all");
00145 m_closeAllWindowsAction->setToolTip( i18n("Close all files") );
00146 m_closeAllWindowsAction->setWhatsThis(i18n("<b>Close all</b><p>Close all opened files."));
00147 m_closeAllWindowsAction->setEnabled(false);
00148
00149 m_closeOtherWindowsAction = new KAction(i18n("Close All Others"), 0,
00150 this, SLOT(slotCloseOtherWindows()),
00151 ac, "file_closeother");
00152 m_closeOtherWindowsAction->setToolTip( i18n("Close other files") );
00153 m_closeOtherWindowsAction->setWhatsThis(i18n("<b>Close all others</b><p>Close all opened files except current."));
00154 m_closeOtherWindowsAction->setEnabled(false);
00155
00156 m_switchToAction = new KAction(i18n("Switch To..."), KShortcut("CTRL+/"),
00157 this, SLOT(slotSwitchTo()),
00158 ac, "file_switchto");
00159 m_switchToAction->setToolTip(i18n("Switch to"));
00160 m_switchToAction->setWhatsThis(i18n("<b>Switch to</b><p>Prompts to enter the name of previously opened file to switch to."));
00161
00162 new KActionSeparator(ac, "dummy_separator");
00163
00164 m_backAction = new KToolBarPopupAction(i18n("Back"), "back", 0, this, SLOT(slotBack()), ac, "history_back");
00165 m_backAction->setEnabled( false );
00166 m_backAction->setToolTip(i18n("Back"));
00167 m_backAction->setWhatsThis(i18n("<b>Back</b><p>Moves backwards one step in the navigation history."));
00168
00169
00170 connect(m_backAction->popupMenu(), SIGNAL(aboutToShow()),
00171 this, SLOT(slotBackAboutToShow()));
00172 connect(m_backAction->popupMenu(), SIGNAL(activated(int)),
00173 this, SLOT(slotPopupActivated(int)));
00174
00175
00176 m_forwardAction = new KToolBarPopupAction(i18n("Forward"), "forward", 0, this, SLOT(slotForward()), ac, "history_forward");
00177 m_forwardAction->setEnabled( false );
00178 m_forwardAction->setToolTip(i18n("Forward"));
00179 m_forwardAction->setWhatsThis(i18n("<b>Forward</b><p>Moves forward one step in the navigation history."));
00180
00181 connect(m_forwardAction->popupMenu(), SIGNAL(aboutToShow()),
00182 this, SLOT(slotForwardAboutToShow()));
00183 connect(m_forwardAction->popupMenu(), SIGNAL(activated(int)),
00184 this, SLOT(slotPopupActivated(int)));
00185 }
00186
00187 void PartController::setEncoding(const QString &encoding)
00188 {
00189 m_presetEncoding = encoding;
00190 }
00191
00192 KParts::Part* PartController::findOpenDocument(const KURL& url)
00193 {
00194
00195 KParts::Part * part = partForURL( url );
00196 if ( part )
00197 {
00198 return part;
00199 }
00200
00201
00202 if ( API::getInstance()->project() )
00203 {
00204 KURL partURL = findURLInProject( url );
00205 partURL.cleanPath();
00206 return partForURL( partURL );
00207 }
00208
00209 return 0L;
00210 }
00211
00212 KURL PartController::findURLInProject(const KURL& url)
00213 {
00214 QStringList fileList = API::getInstance()->project()->allFiles();
00215
00216 bool filenameOnly = (url.url().find('/') == -1);
00217 QString filename = filenameOnly ? "/" : "";
00218 filename += url.url();
00219
00220 for (QStringList::Iterator it = fileList.begin(); it != fileList.end(); ++it) {
00221 if ((*it).endsWith(filename)) {
00222
00223 return KURL( API::getInstance()->project()->projectDirectory() + "/" + *it );
00224 }
00225 }
00226
00227 return url;
00228 }
00229
00230 void PartController::editDocument(const KURL &inputUrl, int lineNum, int col)
00231 {
00232 editDocumentInternal(inputUrl, lineNum, col);
00233 }
00234
00235 void PartController::editDocumentInternal( const KURL & inputUrl, int lineNum, int col, bool activate )
00236 {
00237 kdDebug(9000) << k_funcinfo << inputUrl.prettyURL() << " linenum " << lineNum << " activate? " << activate << endl;
00238
00239 KURL url = inputUrl;
00240
00241 KConfig *config = kapp->config();
00242 config->setGroup("General Options");
00243 bool embedKDevDesigner = config->readBoolEntry("Embed KDevDesigner", true);
00244 config->setGroup("General");
00245
00246 kdDebug(9000) << " - embed: " << (embedKDevDesigner ? "true" : "false") << endl;
00247
00248
00249 if ( !url.isValid() || !KIO::NetAccess::exists(url, false, 0) )
00250 {
00251 bool done = false;
00252
00253
00254 if ( API::getInstance()->project() )
00255 {
00256 if (url.isRelativeURL(url.url())) {
00257 KURL relURL(API::getInstance()->project()->projectDirectory(), url.url());
00258
00259 if (relURL.isValid() && KIO::NetAccess::exists(url, false, 0)) {
00260 url = relURL;
00261 done = true;
00262 }
00263 kdDebug() << k_funcinfo << "Looking for file in project dir: " << API::getInstance()->project()->projectDirectory() << " url " << url.url() << " transformed to " << relURL.url() << ": " << done << endl;
00264 }
00265
00266 if (!done) {
00267 url = findURLInProject(url);
00268
00269 if ( !url.isValid() || !KIO::NetAccess::exists(url, false, 0) )
00270
00271 url = API::getInstance()->project()->projectDirectory() + "/" + url.path();
00272
00273 else
00274 done = true;
00275 }
00276 }
00277
00278 if ( !done && ( !url.isValid() || !KIO::NetAccess::exists(url, false, 0) ))
00279 {
00280
00281 kdDebug(9000) << "cannot find URL: " << url.url() << endl;
00282 return;
00283 }
00284 }
00285
00286
00287
00288
00289 url.cleanPath(true);
00290 if (url.isLocalFile())
00291 {
00292 QString path = url.path();
00293 path = URLUtil::canonicalPath(path);
00294 if ( !path.isEmpty() )
00295 url.setPath(path);
00296 }
00297
00298
00299 KParts::Part *existingPart = partForURL(url);
00300 if (existingPart)
00301 {
00302 Q_ASSERT(activate);
00303 activatePart(existingPart);
00304 EditorProxy::getInstance()->setLineNumber(existingPart, lineNum, col);
00305 addHistoryEntry( url, lineNum, col );
00306 return;
00307 }
00308
00309 KMimeType::Ptr MimeType = KMimeType::findByURL( url );
00310
00311 kdDebug(9000) << "mimeType = " << MimeType->name() << endl;
00312
00313
00314 if ( MimeType->is( "inode/directory" ) )
00315 {
00316 return;
00317 }
00318
00319 if ( !m_presetEncoding.isNull() )
00320 {
00321 m_openNextAsText = true;
00322 }
00323
00324 if ( !m_openNextAsText && embedKDevDesigner && MimeType->is( "application/x-designer" ) )
00325 {
00326 KParts::ReadOnlyPart *designerPart = qtDesignerPart();
00327 if (designerPart)
00328 {
00329 activatePart(designerPart);
00330 designerPart->openURL(url);
00331 return;
00332 }
00333 }
00334
00335
00336
00337 if (!embedKDevDesigner)
00338 {
00339 if ( !m_openNextAsText && MimeType->is( "application/x-designer" ) )
00340 {
00341 KServiceTypeProfile::OfferList offers = KServiceTypeProfile::offers(MimeType->name(), "Application");
00342 for (KServiceTypeProfile::OfferList::const_iterator it = offers.begin(); it != offers.end(); ++it)
00343 {
00344 KService::Ptr app = (*it).service();
00345 if ( app && app->desktopEntryName() == "designer" )
00346 {
00347 KRun::run(*app.data(), url);
00348 return;
00349 }
00350 }
00351 }
00352 }
00353
00354 QStringList texttypeslist = config->readListEntry( "TextTypes" );
00355 if ( texttypeslist.contains( MimeType->name() ) )
00356 {
00357 m_openNextAsText = true;
00358 }
00359
00360
00361 if ( m_openNextAsText || MimeType->is( "text/plain" ) || MimeType->is( "text/html" ) || MimeType->is( "application/x-zerosize" ) )
00362 {
00363 KTextEditor::Editor * editorpart = createEditorPart(activate);
00364
00365 if ( editorpart )
00366 {
00367 if ( !m_presetEncoding.isNull() )
00368 {
00369 KParts::BrowserExtension * extension = KParts::BrowserExtension::childObject( editorpart );
00370 if ( extension )
00371 {
00372 KParts::URLArgs args;
00373 args.serviceType = QString( "text/plain;" ) + m_presetEncoding;
00374 extension->setURLArgs(args);
00375 }
00376 m_presetEncoding = QString::null;
00377 }
00378
00379 editorpart->openURL( url );
00380
00381 QWidget* widget = editorpart->widget();
00382
00383 if (!widget) {
00384
00385
00386 kdDebug() << k_lineinfo << "Creating Editor wrapper..." << endl;
00387 widget = new EditorWrapper(static_cast<KTextEditor::Document*>(editorpart), activate, TopLevel::getInstance()->main());
00388 }
00389
00390 integratePart(editorpart, url, widget, true, activate);
00391 EditorProxy::getInstance()->setLineNumber(editorpart, lineNum, col);
00392
00393 addHistoryEntry( url, lineNum, col );
00394
00395 m_openNextAsText = false;
00396
00397 m_openRecentAction->addURL( url );
00398 m_openRecentAction->saveEntries( kapp->config(), "RecentFiles" );
00399
00400 return;
00401 }
00402 }
00403
00404
00405
00406 KParts::Factory *factory = 0;
00407 QString className;
00408
00409 QString services[] = { "KParts/ReadWritePart", "KParts/ReadOnlyPart" };
00410 QString classnames[] = { "KParts::ReadWritePart", "KParts::ReadOnlyPart" };
00411 for (uint i=0; i<2; ++i)
00412 {
00413 factory = findPartFactory( MimeType->name(), services[i] );
00414 if (factory)
00415 {
00416 className = classnames[i];
00417 break;
00418 }
00419 }
00420
00421 kdDebug(9000) << "factory = " << factory << endl;
00422
00423 if (factory)
00424 {
00425
00426 KParts::ReadOnlyPart *part = static_cast<KParts::ReadOnlyPart*>( factory->createPart( TopLevel::getInstance()->main(), 0, 0, 0, className.latin1() ) );
00427 if ( part )
00428 {
00429 part->openURL( url );
00430
00431 if ( dynamic_cast<KTextEditor::Editor*>( part ) )
00432 {
00433 integratePart(part, url, part->widget(), true, activate);
00434 EditorProxy::getInstance()->setLineNumber(part, lineNum, col);
00435 }
00436 else
00437 {
00438 integratePart( part, url );
00439 }
00440
00441 addHistoryEntry( url, lineNum, col );
00442
00443 m_openRecentAction->addURL( url );
00444 m_openRecentAction->saveEntries( kapp->config(), "RecentFiles" );
00445 }
00446 }
00447 else
00448 {
00449 MimeWarningDialog dlg;
00450 dlg.text->setText( dlg.text->text().arg(url.path()).arg(MimeType->name()) );
00451
00452 if ( dlg.exec() == QDialog::Accepted )
00453 {
00454 if ( dlg.open_with_kde->isChecked() )
00455 {
00456 KRun::runURL(url, MimeType->name() );
00457 }
00458 else
00459 {
00460 if ( dlg.always_open_as_text->isChecked() )
00461 {
00462 KConfig *config = kapp->config();
00463 config->setGroup("General");
00464 QStringList texttypeslist = config->readListEntry( "TextTypes" );
00465 texttypeslist << MimeType->name();
00466 config->writeEntry( "TextTypes", texttypeslist );
00467 }
00468 m_openNextAsText = true;
00469 editDocument( url, lineNum, col );
00470 }
00471 }
00472 }
00473 }
00474
00475
00476 void PartController::showDocument(const KURL &url, bool newWin)
00477 {
00478 QString fixedPath = DocumentationPart::resolveEnvVarsInURL(url.url());
00479 KURL docUrl(fixedPath);
00480 kdDebug(9000) << "SHOW: " << docUrl.url() << endl;
00481
00482 if ( docUrl.isLocalFile() && KMimeType::findByURL(docUrl)->name() != "text/html" ) {
00483
00484
00485 editDocument( docUrl );
00486 return;
00487 }
00488
00489
00490 DocumentationPart *part = dynamic_cast<DocumentationPart*>(activePart());
00491 if (!part || newWin)
00492 {
00493 part = new DocumentationPart;
00494 integratePart(part,docUrl);
00495 connect(part, SIGNAL(fileNameChanged(KParts::ReadOnlyPart* )),
00496 this, SIGNAL(partURLChanged(KParts::ReadOnlyPart* )));
00497 }
00498 else
00499 {
00500 activatePart(part);
00501 }
00502 part->openURL(docUrl);
00503 }
00504
00505 KParts::Factory *PartController::findPartFactory(const QString &mimeType, const QString &partType, const QString &preferredName)
00506 {
00507 KTrader::OfferList offers = KTrader::self()->query(mimeType, QString("'%1' in ServiceTypes").arg(partType));
00508
00509 if (offers.count() > 0)
00510 {
00511 KService::Ptr ptr = 0;
00512
00513 if ( !preferredName.isEmpty() ) {
00514 KTrader::OfferList::Iterator it;
00515 for (it = offers.begin(); it != offers.end(); ++it) {
00516 if ((*it)->name() == preferredName) {
00517 ptr = (*it);
00518 }
00519 }
00520 }
00521
00522 if ( !ptr ) {
00523 ptr = offers.first();
00524 }
00525 return static_cast<KParts::Factory*>(KLibLoader::self()->factory(QFile::encodeName(ptr->library())));
00526 }
00527
00528 return 0;
00529 }
00530
00531 KTextEditor::Editor * PartController::createEditorPart( bool activate )
00532 {
00533
00534 if ( !_editorFactory )
00535 {
00536 kapp->config()->setGroup("Editor");
00537 QString preferred = kapp->config()->readPathEntry("EmbeddedKTextEditor");
00538
00539 _editorFactory = findPartFactory( "text/plain", "KTextEditor/Document", preferred );
00540
00541 if ( !_editorFactory ) return 0L;
00542 }
00543
00544
00545 activate = false;
00546
00547 return static_cast<KTextEditor::Editor*>( _editorFactory->createPart( TopLevel::getInstance()->main(), 0, 0, 0, activate ? "KTextEditor/Editor" : "KTextEditor::Document" ) );
00548 }
00549
00550 void PartController::integratePart(KParts::Part *part, const KURL &url, QWidget* widget, bool isTextEditor, bool activate )
00551 {
00552 if (!widget) widget = part->widget();
00553
00554 if (!widget) {
00556 kdDebug(9000) << "no widget for this part!!" << endl;
00557 return;
00558 }
00559
00560 TopLevel::getInstance()->embedPartView(widget, url.filename(), url.url());
00561
00562 addPart(part, activate);
00563
00564
00565 KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(part);
00566 if ( !ro_part ) return;
00567
00568 emit loadedFile( ro_part->url() );
00569
00570 if ( ro_part->url().isLocalFile() )
00571 {
00572 emit loadedFile(ro_part->url().path());
00573 }
00574
00575 connect( part, SIGNAL(modifiedOnDisc(Kate::Document*, bool, unsigned char)), this, SLOT(slotDocumentDirty(Kate::Document*, bool, unsigned char)) );
00576
00577
00578 connect(part, SIGNAL(completed()), this, SLOT(slotUploadFinished()));
00579
00580
00581
00582
00583
00584
00585
00586
00587 if (isTextEditor)
00588 integrateTextEditorPart(static_cast<KTextEditor::Document*>(part));
00589
00590 KInterfaceDesigner::Designer *designerPart = dynamic_cast<KInterfaceDesigner::Designer *>(part);
00591 if (designerPart && API::getInstance()->languageSupport())
00592 {
00593 kdDebug() << "integrating designer part with language support" << endl;
00594 connect(designerPart, SIGNAL(addedFunction(DesignerType, const QString&, Function )),
00595 API::getInstance()->languageSupport(),
00596 SLOT(addFunction(DesignerType, const QString&, Function )));
00597 connect(designerPart, SIGNAL(editedFunction(DesignerType, const QString&, Function, Function )), API::getInstance()->languageSupport(),
00598 SLOT(editFunction(DesignerType, const QString&, Function, Function )));
00599 connect(designerPart, SIGNAL(removedFunction(DesignerType, const QString&, Function )),
00600 API::getInstance()->languageSupport(),
00601 SLOT(removeFunction(DesignerType, const QString&, Function )));
00602 connect(designerPart, SIGNAL(editFunction(DesignerType, const QString&, const QString& )),
00603 API::getInstance()->languageSupport(),
00604 SLOT(openFunction(DesignerType, const QString&, const QString& )));
00605 }
00606 }
00607
00608 void PartController::integrateTextEditorPart(KTextEditor::Document* doc)
00609 {
00610
00611
00612
00613
00614
00615
00616
00617
00618 QPtrList<KTextEditor::View> list = doc->views();
00619 QPtrListIterator<KTextEditor::View> it( list );
00620 while ( it.current() )
00621 {
00622 connect( it, SIGNAL( newStatus() ), this, SLOT( slotNewStatus() ) );
00623 ++it;
00624 }
00625 }
00626
00627 void PartController::slotPartAdded( KParts::Part * part )
00628 {
00629 kdDebug(9000) << k_funcinfo << endl;
00630
00631 if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart*>( part ) )
00632 {
00633 updatePartURL( ro_part );
00634 }
00635
00636 updateMenuItems();
00637 }
00638
00639 void PartController::slotPartRemoved( KParts::Part * part )
00640 {
00641 kdDebug(9000) << k_funcinfo << endl;
00642
00643 _partURLMap.remove( static_cast<KParts::ReadOnlyPart*>(part) );
00644
00645 updateMenuItems();
00646 }
00647
00648 void PartController::updatePartURL( KParts::ReadOnlyPart * ro_part )
00649 {
00650 if ( ro_part->url().isEmpty() )
00651 {
00652 kdDebug(9000) << "updatePartURL() called with empty URL for part: " << ro_part << endl;
00653 return;
00654 }
00655 _partURLMap[ ro_part ] = ro_part->url();
00656 }
00657
00658 bool PartController::partURLHasChanged( KParts::ReadOnlyPart * ro_part )
00659 {
00660 if ( _partURLMap.contains( ro_part ) && !ro_part->url().isEmpty() )
00661 {
00662 if ( _partURLMap[ ro_part ] != ro_part->url() )
00663 {
00664 return true;
00665 }
00666 }
00667 return false;
00668 }
00669
00670 KURL PartController::storedURLForPart( KParts::ReadOnlyPart * ro_part )
00671 {
00672 if ( _partURLMap.contains( ro_part ) )
00673 {
00674 return _partURLMap[ ro_part ];
00675 }
00676 return KURL();
00677 }
00678
00679
00680 void PartController::slotUploadFinished()
00681 {
00682 KParts::ReadOnlyPart *ro_part = const_cast<KParts::ReadOnlyPart*>( dynamic_cast<const KParts::ReadOnlyPart*>(sender()) );
00683 if ( !ro_part ) return;
00684
00685 if ( partURLHasChanged( ro_part ) )
00686 {
00687 emit partURLChanged( ro_part );
00688 updatePartURL( ro_part );
00689 }
00690 }
00691
00692 KParts::ReadOnlyPart *PartController::partForURL(const KURL &url)
00693 {
00694 QPtrListIterator<KParts::Part> it(*parts());
00695 for ( ; it.current(); ++it)
00696 {
00697 KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(it.current());
00698 if (ro_part && url == ro_part->url())
00699 return ro_part;
00700 }
00701 return 0;
00702 }
00703
00704 KParts::Part * PartController::partForWidget( const QWidget * widget )
00705 {
00706 QPtrListIterator<KParts::Part> it(*parts());
00707 for ( ; it.current(); ++it)
00708 {
00709 if ( it.current()->widget() == widget )
00710 {
00711 return *it;
00712 }
00713 }
00714 return 0;
00715 }
00716
00717
00718 void PartController::activatePart(KParts::Part *part)
00719 {
00720 if ( !part ) return;
00721
00722 QWidget * widget = EditorProxy::getInstance()->widgetForPart( part );
00723 if (widget)
00724 {
00725 TopLevel::getInstance()->raiseView( widget );
00726 widget->show();
00727 widget->setFocus();
00728 }
00729
00730 setActivePart(part);
00731
00732 QWidget* w2 = EditorProxy::getInstance()->widgetForPart( part );
00733 if (w2 != widget)
00734 w2->setFocus();
00735 }
00736
00737 bool PartController::closePart(KParts::Part *part)
00738 {
00739 if ( !part ) return true;
00740
00741 if ( KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart*>( part ) )
00742 {
00743 KURL url = ro_part->url();
00744 if ( ! ro_part->closeURL() )
00745 {
00746 return false;
00747 }
00748 _dirtyDocuments.remove( static_cast<KParts::ReadWritePart*>( ro_part ) );
00749
00750 emit closedFile( url );
00751
00752 }
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772 removePart( part );
00773
00774 if (QWidget* w = EditorProxy::getInstance()->topWidgetForPart(part))
00775 TopLevel::getInstance()->removeView(w);
00776
00777 delete part;
00778
00779 return true;
00780 }
00781
00782
00783 void PartController::updateMenuItems()
00784 {
00785 bool hasWriteParts = false;
00786 bool hasReadOnlyParts = false;
00787
00788 QPtrListIterator<KParts::Part> it(*parts());
00789 for ( ; it.current(); ++it)
00790 {
00791 if (it.current()->inherits("KParts::ReadWritePart"))
00792 hasWriteParts = true;
00793 if (it.current()->inherits("KParts::ReadOnlyPart"))
00794 hasReadOnlyParts = true;
00795 }
00796
00797 m_saveAllFilesAction->setEnabled(hasWriteParts);
00798 m_revertAllFilesAction->setEnabled(hasWriteParts);
00799 m_closeWindowAction->setEnabled(hasReadOnlyParts);
00800 m_closeAllWindowsAction->setEnabled(hasReadOnlyParts);
00801 m_closeOtherWindowsAction->setEnabled(hasReadOnlyParts);
00802
00803 m_backAction->setEnabled( m_Current != m_history.begin() );
00804 m_forwardAction->setEnabled( m_Current != m_history.fromLast() );
00805 }
00806
00807 void PartController::slotRevertAllFiles()
00808 {
00809 revertAllFiles();
00810 }
00811
00812 void PartController::reloadFile( const KURL & url, bool )
00813 {
00814 KParts::ReadWritePart * part = dynamic_cast<KParts::ReadWritePart*>( partForURL( url ) );
00815 if ( part )
00816 {
00817 if ( part->isModified() )
00818 {
00819 if ( KMessageBox::warningYesNo( TopLevel::getInstance()->main(),
00820 i18n( "The file \"%1\" is modified in memory. Are you sure you want to reload it? (Local changes will be lost.)" ).arg( url.path() ),
00821 i18n( "File is Modified" ) ) == KMessageBox::Yes )
00822 {
00823 part->setModified( false );
00824 }
00825 else
00826 {
00827 return;
00828 }
00829 }
00830
00831 unsigned int line = 0; unsigned int col = 0;
00832 KTextEditor::ViewCursorInterface * iface = dynamic_cast<KTextEditor::ViewCursorInterface*>( part->widget() );
00833 if (iface)
00834 {
00835 iface->cursorPositionReal( &line, &col );
00836 }
00837
00838 part->openURL( url );
00839
00840 _dirtyDocuments.remove( part );
00841 emit documentChangedState( url, Clean );
00842
00843 if ( iface )
00844 {
00845 iface->setCursorPositionReal( line, col );
00846 }
00847 }
00848 }
00849
00850 void PartController::revertFiles( const KURL::List & list )
00851 {
00852 KURL::List::ConstIterator it = list.begin();
00853 while ( it != list.end() )
00854 {
00855 reloadFile( *it );
00856 ++it;
00857 }
00858 }
00859
00860 void PartController::revertAllFiles()
00861 {
00862 revertFiles( openURLs() );
00863 }
00864
00865 void PartController::slotCloseWindow()
00866 {
00867 closePart( activePart() );
00868 }
00869
00870 KURL::List PartController::modifiedDocuments()
00871 {
00872 KURL::List modFiles;
00873
00874 QPtrListIterator<KParts::Part> it( *parts() );
00875 while( it.current() )
00876 {
00877 KParts::ReadWritePart *rw_part = dynamic_cast<KParts::ReadWritePart*>(it.current());
00878 if ( rw_part && rw_part->isModified() )
00879 {
00880 modFiles << rw_part->url();
00881 }
00882 ++it;
00883 }
00884 return modFiles;
00885 }
00886
00887 void PartController::slotSave()
00888 {
00889 kdDebug(9000) << k_funcinfo << endl;
00890
00891 if ( KParts::ReadWritePart * part = dynamic_cast<KParts::ReadWritePart*>( activePart() ) )
00892 {
00893 saveFile( part->url() );
00894 }
00895 }
00896
00897 void PartController::slotReload()
00898 {
00899 kdDebug(9000) << k_funcinfo << endl;
00900
00901 if ( KParts::ReadWritePart * part = dynamic_cast<KParts::ReadWritePart*>( activePart() ) )
00902 {
00903 reloadFile( part->url() );
00904 }
00905 }
00906
00907 void PartController::slotSaveAllFiles()
00908 {
00909 saveAllFiles();
00910 }
00911
00912 bool PartController::saveFile( const KURL & url, bool force )
00913 {
00914 KParts::ReadWritePart * part = dynamic_cast<KParts::ReadWritePart*>( partForURL( url ) );
00915 if ( !part ) return true;
00916
00917 switch( documentState( url ) )
00918 {
00919 case Clean:
00920 if ( !force )
00921 {
00922 return true;
00923 }
00924 kdDebug(9000) << "Forced save" << endl;
00925 break;
00926
00927 case Modified:
00928 kdDebug(9000) << "Normal save" << endl;
00929 break;
00930
00931 case Dirty:
00932 case DirtyAndModified:
00933 {
00934 int code = KMessageBox::warningYesNoCancel( TopLevel::getInstance()->main(),
00935 i18n("The file \"%1\" is modified on disk.\n\nAre you sure you want to overwrite it? (External changes will be lost.)").arg( url.path() ),
00936 i18n("File Externally Modified") );
00937 if ( code == KMessageBox::Yes )
00938 {
00939 kdDebug(9000) << "Dirty save!!" << endl;
00940 }
00941 else if ( code == KMessageBox::No )
00942 {
00943 return true;
00944 }
00945 else
00946 {
00947 return false;
00948 }
00949 }
00950 break;
00951
00952 default:
00953 ;
00954 }
00955
00956 if ( part->save() )
00957 {
00958 _dirtyDocuments.remove( part );
00959 emit documentChangedState( url, Clean );
00960 emit savedFile( url );
00961 }
00962
00963 return true;
00964 }
00965
00966 void PartController::saveAllFiles()
00967 {
00968 saveFiles( openURLs() );
00969 }
00970
00971 void PartController::saveFiles( KURL::List const & filelist )
00972 {
00973 KURL::List::ConstIterator it = filelist.begin();
00974 while ( it != filelist.end() )
00975 {
00976 saveFile( *it );
00977 ++it;
00978 }
00979 }
00980
00981 bool PartController::querySaveFiles()
00982 {
00983 return saveFilesDialog( KURL::List() );
00984 }
00985
00986 void PartController::clearModified( KURL::List const & filelist )
00987 {
00988 KURL::List::ConstIterator it = filelist.begin();
00989 while ( it != filelist.end() )
00990 {
00991 KParts::ReadWritePart * rw_part = dynamic_cast<KParts::ReadWritePart*>( partForURL( *it ) );
00992 if ( rw_part )
00993 {
00994 rw_part->setModified( false );
00995 }
00996 ++it;
00997 }
00998 }
00999
01000 bool PartController::saveFilesDialog( KURL::List const & ignoreList )
01001 {
01002 KURL::List modList = modifiedDocuments();
01003
01004 if ( modList.count() > 0 && modList != ignoreList )
01005 {
01006 KSaveSelectDialog dlg( modList, ignoreList, TopLevel::getInstance()->main() );
01007 if ( dlg.exec() == QDialog::Accepted )
01008 {
01009 saveFiles( dlg.filesToSave() );
01010 clearModified( dlg.filesNotToSave() );
01011 }
01012 else
01013 {
01014 return false;
01015 }
01016 }
01017 return true;
01018 }
01019
01020 bool PartController::closeFilesDialog( KURL::List const & ignoreList )
01021 {
01022 if ( !saveFilesDialog( ignoreList ) ) return false;
01023
01024 QPtrList<KParts::Part> partList( *parts() );
01025 QPtrListIterator<KParts::Part> it( partList );
01026 while ( KParts::Part* part = it.current() )
01027 {
01028 KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart*>( part );
01029 if ( ro_part && !ignoreList.contains( ro_part->url() ) || !ro_part )
01030 {
01031 closePart( part );
01032 }
01033 ++it;
01034 }
01035 return true;
01036 }
01037
01038 bool PartController::closeFiles( const KURL::List & list )
01039 {
01040 KURL::List::ConstIterator it = list.begin();
01041 while ( it != list.end() )
01042 {
01043 if ( !closePart( partForURL( *it ) ) )
01044 {
01045 return false;
01046 }
01047 ++it;
01048 }
01049 return true;
01050 }
01051
01052 bool PartController::closeFile( const KURL & url )
01053 {
01054 return closePart( partForURL( url ) );
01055 }
01056
01057 bool PartController::closeAllFiles()
01058 {
01059 return closeFilesDialog( KURL::List() );
01060 }
01061
01062 void PartController::slotCloseAllWindows()
01063 {
01064 closeAllFiles();
01065 }
01066
01067 bool PartController::closeAllOthers( const KURL & url )
01068 {
01069 KURL::List ignoreList;
01070 ignoreList.append( url );
01071
01072 return closeFilesDialog( ignoreList );
01073 }
01074
01075
01076 void PartController::slotCloseOtherWindows()
01077 {
01078 KParts::ReadOnlyPart * active = dynamic_cast<KParts::ReadOnlyPart*>(activePart());
01079 if ( !active ) return;
01080
01081 closeAllOthers( active->url() );
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091 }
01092
01093 void PartController::slotOpenFile()
01094 {
01095 KEncodingFileDialog::Result result = KEncodingFileDialog::getOpenURLsAndEncoding(QString::null, QString::null,
01096 QString::null, TopLevel::getInstance()->main(), QString::null);
01097
01098 for ( KURL::List::Iterator it = result.URLs.begin(); it != result.URLs.end(); ++it )
01099 {
01100 m_presetEncoding = result.encoding;
01101 editDocument( *it );
01102 }
01103 }
01104
01105 void PartController::slotOpenRecent( const KURL& url )
01106 {
01107 editDocument( url );
01108
01109 m_openRecentAction->setCurrentItem( -1 );
01110 }
01111
01112 bool PartController::readyToClose()
01113 {
01114 blockSignals( true );
01115
01116 closeAllFiles();
01117
01118 return true;
01119 }
01120
01121 void PartController::slotActivePartChanged( KParts::Part * part )
01122 {
01123 kdDebug(9000) << k_funcinfo << endl;
01124
01125 updateMenuItems();
01126
01127 QTimer::singleShot( 100, this, SLOT(slotWaitForFactoryHack()) );
01128
01129 if ( m_isJumping ) return;
01130
01131 if ( _partURLMap.contains( m_latestPart ) )
01132 {
01133 addHistoryEntry( _partURLMap[ m_latestPart ] );
01134 }
01135
01136 if ( dynamic_cast<DocumentationPart*>( part ) ) return;
01137
01138 KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart*>( part );
01139 if ( ro_part )
01140 {
01141 m_latestPart = ro_part;
01142 }
01143 }
01144
01145 void PartController::slotSwitchTo()
01146 {
01147 QMap<QString,KParts::ReadOnlyPart*> parts_map;
01148 QStringList part_list;
01149 QPtrList<KParts::Part> pl = *parts();
01150 KParts::Part *part;
01151 for(part=pl.first();part;part=pl.next()) {
01152 kdDebug(9000) << "Part..." << endl;
01153 if (part->inherits("KParts::ReadOnlyPart")) {
01154 KParts::ReadOnlyPart *ro_part = static_cast<KParts::ReadOnlyPart*>(part);
01155 QString name = ro_part->url().fileName();
01156 part_list.append(name);
01157 parts_map[name] = ro_part;
01158 kdDebug(9000) << "Found part for URL " << ro_part->url().prettyURL() << endl;
01159 }
01160 }
01161
01162 KDialogBase dialog(KDialogBase::Plain, i18n("Switch To"), KDialogBase::Ok|KDialogBase::Cancel,
01163 KDialogBase::Ok, 0, "Switch to", true);
01164 QGridLayout *grid = new QGridLayout( dialog.plainPage(), 2, 1, 10, 10);
01165 KLineEdit *editbox = new KLineEdit(dialog.plainPage());
01166 grid->addWidget(new QLabel( i18n("Switch to buffer:"), dialog.plainPage() ), 0, 0);
01167 grid->addWidget(editbox, 1, 0);
01168 editbox->completionObject()->setItems( part_list );
01169 editbox->setFocus();
01170 int result = dialog.exec();
01171 if (result==KDialogBase::KDialogBase::Accepted) {
01172 if (parts_map.contains(editbox->text())) {
01173 activatePart(parts_map[editbox->text()]);
01174 }
01175 }
01176 }
01177
01178 void PartController::showPart( KParts::Part* part, const QString& name, const QString& shortDescription )
01179 {
01180 if (!part->widget()) {
01182 return;
01183 }
01184
01185 QPtrListIterator<KParts::Part> it(*parts());
01186 for ( ; it.current(); ++it)
01187 {
01188 if( it.current() == part ){
01189
01190 activatePart( it.current() );
01191 return;
01192 }
01193 }
01194
01195
01196 TopLevel::getInstance()->embedPartView( part->widget(), name, shortDescription );
01197 addPart( part );
01198 }
01199
01200 void PartController::slotDocumentDirty( Kate::Document * d, bool isModified, unsigned char reason )
01201 {
01202 kdDebug(9000) << k_funcinfo << endl;
01203
01204
01205 KTextEditor::Document * doc = 0;
01206
01207 QPtrListIterator<KParts::Part> it( *parts() );
01208 while( it.current() )
01209 {
01210 if ( (void*)it.current() == (void*)d )
01211 {
01212 doc = dynamic_cast<KTextEditor::Document*>( it.current() );
01213 break;
01214 }
01215 ++it;
01216 }
01217
01218 if ( !doc ) return;
01219 KURL url = storedURLForPart( doc );
01220 if ( url.isEmpty() )
01221 {
01222 kdDebug(9000) << "Warning!! the stored url is empty. Bailing out!" << endl;
01223 }
01224
01225 if ( reason > 0 )
01226 {
01227 if ( !_dirtyDocuments.contains( doc ) )
01228 {
01229 _dirtyDocuments.append( doc );
01230 }
01231
01232 if ( reactToDirty( url ) )
01233 {
01234
01235 emit documentChangedState( url, Clean );
01236 _dirtyDocuments.remove( doc );
01237 }
01238 else
01239 {
01240 emit doEmitState( url );
01241 }
01242 }
01243 else
01244 {
01245 _dirtyDocuments.remove( doc );
01246 emit documentChangedState( url, Clean );
01247 }
01248
01249 kdDebug(9000) << doc->url().url() << endl;
01250 kdDebug(9000) << isModified << endl;
01251 kdDebug(9000) << reason << endl;
01252 }
01253
01254 bool PartController::isDirty( KURL const & url )
01255 {
01256 return _dirtyDocuments.contains( static_cast<KTextEditor::Document*>( partForURL( url ) ) );
01257 }
01258
01259 bool PartController::reactToDirty( KURL const & url )
01260 {
01261 KConfig *config = kapp->config();
01262 config->setGroup("Editor");
01263 QString dirtyAction = config->readEntry( "DirtyAction" );
01264
01265 if ( dirtyAction == "nothing" ) return false;
01266
01267 bool isModified = true;
01268 if( KParts::ReadWritePart * part = dynamic_cast<KParts::ReadWritePart*>( partForURL( url ) ) )
01269 {
01270 isModified = part->isModified();
01271 }
01272 else
01273 {
01274 kdDebug(9000) << k_funcinfo << " Warning. Not a ReadWritePart." << endl;
01275 return false;
01276 }
01277
01278 if ( isModified )
01279 {
01280 KMessageBox::sorry( TopLevel::getInstance()->main(),
01281 i18n("Conflict: The file \"%1\" has changed on disc while being modified in memory.\n\n"
01282 "You should investigate before saving to make sure you are not losing data.").arg( url.path() ),
01283 i18n("Conflict") );
01284 return false;
01285 }
01286
01287 if ( dirtyAction == "alert" )
01288 {
01289 if ( KMessageBox::warningYesNo( TopLevel::getInstance()->main(),
01290 i18n("The file \"%1\" has changed on disk.\n\nDo you want to reload it?").arg( url.path() ),
01291 i18n("File Changed") ) == KMessageBox::No )
01292 {
01293 return false;
01294 }
01295 }
01296
01297
01298 reloadFile( url );
01299
01300 return true;
01301 }
01302
01303 void PartController::slotNewStatus( )
01304 {
01305 kdDebug(9000) << k_funcinfo << endl;
01306
01307 QObject * senderobj = const_cast<QObject*>( sender() );
01308 KTextEditor::View * view = dynamic_cast<KTextEditor::View*>( senderobj );
01309 if ( view )
01310 {
01311 doEmitState( view->document()->url() );
01312 }
01313 }
01314
01315 DocumentState PartController::documentState( KURL const & url )
01316 {
01317 KParts::ReadWritePart * rw_part = dynamic_cast<KParts::ReadWritePart*>( partForURL( url ) );
01318 if ( !rw_part ) return Clean;
01319
01320 DocumentState state = Clean;
01321 if ( rw_part->isModified() )
01322 {
01323 state = Modified;
01324 }
01325
01326 if ( isDirty( url ) )
01327 {
01328 if ( state == Modified )
01329 {
01330 state = DirtyAndModified;
01331 }
01332 else
01333 {
01334 state = Dirty;
01335 }
01336 }
01337
01338 return state;
01339 }
01340
01341 void PartController::doEmitState( KURL const & url )
01342 {
01343 emit documentChangedState( url, documentState( url ) );
01344 }
01345
01346 KURL::List PartController::openURLs( )
01347 {
01348 KURL::List list;
01349 QPtrListIterator<KParts::Part> it(*parts());
01350 for ( ; it.current(); ++it)
01351 {
01352 if ( KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(it.current()) )
01353 {
01354 list << ro_part->url();
01355 }
01356 }
01357 return list;
01358 }
01359
01361
01362
01363
01364 PartController::HistoryEntry::HistoryEntry( const KURL & u, int l, int c)
01365 : url(u), line(l), col(c)
01366 {
01367 id = abs( QTime::currentTime().msecsTo( QTime() ) );
01368 }
01369
01370 void PartController::slotBack()
01371 {
01372 if ( m_Current != m_history.begin() )
01373 {
01374 jumpTo( *(--m_Current) );
01375 }
01376 }
01377
01378 void PartController::slotForward()
01379 {
01380 if ( m_Current != m_history.fromLast() )
01381 {
01382 jumpTo( *(++m_Current) );
01383 }
01384 }
01385
01386 void PartController::slotBackAboutToShow()
01387 {
01388 KPopupMenu *popup = m_backAction->popupMenu();
01389 popup->clear();
01390
01391 if ( m_Current == m_history.begin() ) return;
01392
01393 QValueList<HistoryEntry>::Iterator it = m_Current;
01394 --it;
01395
01396 int i = 0;
01397 while( i < 10 )
01398 {
01399 if ( it == m_history.begin() )
01400 {
01401 popup->insertItem( (*it).url.fileName() + QString(" (%1,%2)").arg( (*it).line).arg((*it).col), (*it).id );
01402 return;
01403 }
01404
01405 popup->insertItem( (*it).url.fileName() + QString(" (%1,%2)").arg( (*it).line).arg((*it).col), (*it).id );
01406 ++i;
01407 --it;
01408 }
01409 }
01410
01411 void PartController::slotForwardAboutToShow()
01412 {
01413 KPopupMenu *popup = m_forwardAction->popupMenu();
01414 popup->clear();
01415
01416 if ( m_Current == m_history.fromLast() ) return;
01417
01418 QValueList<HistoryEntry>::Iterator it = m_Current;
01419 ++it;
01420
01421 int i = 0;
01422 while( i < 10 )
01423 {
01424 if ( it == m_history.fromLast() )
01425 {
01426 popup->insertItem( (*it).url.fileName() + QString(" (%1,%2)").arg( (*it).line).arg((*it).col), (*it).id );
01427 return;
01428 }
01429
01430 popup->insertItem( (*it).url.fileName() + QString(" (%1,%2)").arg( (*it).line).arg((*it).col), (*it).id );
01431 ++i;
01432 ++it;
01433 }
01434 }
01435
01436 void PartController::slotPopupActivated( int id )
01437 {
01438 QValueList<HistoryEntry>::Iterator it = m_history.begin();
01439 while( it != m_history.end() )
01440 {
01441 if ( (*it).id == id )
01442 {
01443 m_Current = it;
01444 jumpTo( *m_Current );
01445 return;
01446 }
01447 ++it;
01448 }
01449 }
01450
01451 void PartController::jumpTo( const HistoryEntry & entry )
01452 {
01453 m_isJumping = true;
01454 editDocument( entry.url, entry.line, entry.col );
01455 m_isJumping = false;
01456 }
01457
01458 void PartController::addHistoryEntry(const KURL & url, int line, int col )
01459 {
01460 if ( m_isJumping ) return;
01461
01462 QValueList<HistoryEntry>::Iterator it = m_Current;
01463
01464 if ( it != m_history.end() && it != m_history.fromLast() )
01465 {
01466 m_history.erase( ++it, m_history.end() );
01467 }
01468
01469 HistoryEntry newEntry( url, line, col );
01470
01471
01472 if ( newEntry.url == (*m_Current).url )
01473 {
01474 if ( newEntry.line == -1 )
01475 {
01476 return;
01477 }
01478 if ( (*m_Current).line == -1 )
01479 {
01480 (*m_Current).line = line;
01481 (*m_Current).col = col;
01482 return;
01483 }
01484 }
01485
01486
01487 m_history.append( newEntry );
01488 m_Current = m_history.fromLast();
01489
01490 updateMenuItems();
01491 }
01492
01493
01494
01495 void PartController::slotWaitForFactoryHack( )
01496 {
01497
01498
01499 if ( !activePart() ) return;
01500
01501 if ( dynamic_cast<KTextEditor::View*>( activePart()->widget() ) )
01502 {
01503 if ( !activePart()->factory() )
01504 {
01505 QTimer::singleShot( 100, this, SLOT(slotWaitForFactoryHack()) );
01506 }
01507 else
01508 {
01509 EditorProxy::getInstance()->installPopup( activePart() );
01510 }
01511 }
01512 }
01513
01514 KParts::ReadOnlyPart *PartController::qtDesignerPart()
01515 {
01516 QPtrListIterator<KParts::Part> it(*parts());
01517 for ( ; it.current(); ++it)
01518 {
01519 KInterfaceDesigner::Designer *des = dynamic_cast<KInterfaceDesigner::Designer*>(it.current());
01520 if (des && des->designerType() == KInterfaceDesigner::QtDesigner)
01521 return des;
01522 }
01523 return 0;
01524 }
01525
01526
01527 #include "partcontroller.moc"