KDevelop API Documentation

editorproxy.cpp

Go to the documentation of this file.
00001 // Ewww... need this to access KParts::Part::setWidget(), so that kdevelop
00002 // doesn't need to be rearchitected for multiple views before the lazy view
00003 // creation can go in
00004 #define protected public
00005 #include <kparts/part.h>
00006 #undef protected
00007 
00008 #include <qwidget.h>
00009 #include <qpopupmenu.h>
00010 #include <qtimer.h>
00011 
00012 #include <kdeversion.h>
00013 #include <kdebug.h>
00014 #include <kconfig.h>
00015 #include <kapplication.h>
00016 #include <kmdidefines.h>
00017 
00018 #include <ktexteditor/document.h>
00019 #include <ktexteditor/view.h>
00020 #include <ktexteditor/viewcursorinterface.h>
00021 #include <ktexteditor/popupmenuinterface.h>
00022 #include <ktexteditor/editinterface.h>
00023 #include <ktexteditor/selectioninterface.h>
00024 #include <ktexteditor/view.h>
00025 #include <kxmlguiclient.h>
00026 #include <kxmlguifactory.h>
00027 #include <kmainwindow.h>
00028 #include <kactioncollection.h>
00029 #include <klocale.h>
00030 #include <kstdaccel.h>
00031 
00032 #include "toplevel.h"
00033 #include "partcontroller.h"
00034 #include "core.h"
00035 #include "debugger.h"
00036 #include "newmainwindow.h"
00037 
00038 
00039 #include "editorproxy.h"
00040 
00041 
00042 using namespace KTextEditor;
00043 
00044 EditorProxy *EditorProxy::s_instance = 0;
00045 
00046 
00047 EditorProxy::EditorProxy()
00048   : QObject()
00049 {
00050     KConfig *config = kapp->config();
00051     config->setGroup("UI");
00052     int mdimode = config->readNumEntry("MDIMode", KMdi::IDEAlMode);
00053     
00054     m_delayedViewCreationCompatibleUI = (mdimode == KMdi::IDEAlMode || mdimode == KMdi::TabPageMode);
00055 
00056     KAction *ac = new KAction( i18n("Show Context Menu"), 0, this, 
00057         SLOT(showPopup()), TopLevel::getInstance()->main()->actionCollection(), "show_popup" );
00058         KShortcut cut ;/*= KStdAccel::shortcut(KStdAccel::PopupMenuContext);*/
00059         cut.append(KKey(CTRL+Key_Return));
00060         ac->setShortcut(cut);
00061 }
00062 
00063 
00064 EditorProxy *EditorProxy::getInstance()
00065 {
00066   if (!s_instance)
00067     s_instance = new EditorProxy;
00068 
00069   return s_instance;
00070 }
00071 
00072 
00073 void EditorProxy::setLineNumber(KParts::Part *part, int lineNum, int col)
00074 {
00075   if (!part || !part->inherits("KTextEditor::Document"))
00076     return;
00077 
00078   if ( lineNum < 0 )
00079     return;
00080 
00081   ViewCursorInterface *iface = dynamic_cast<ViewCursorInterface*>(part->widget());
00082   if (iface)
00083     iface->setCursorPositionReal(lineNum, col == -1 ? 0 : col);
00084   else {
00085     // Save the position for a rainy day (or when the view gets activated and wants its position)
00086     for (QValueList<EditorWrapper*>::ConstIterator it = m_editorParts.begin(); it != m_editorParts.end(); ++it)
00087       if ((*it)->document() == part) {
00088         (*it)->setLine(lineNum);
00089         (*it)->setCol(col);
00090         return;
00091       }
00092 
00093     // Shouldn't hit this?
00094     Q_ASSERT(false);
00095   }
00096 }
00097 
00098 void EditorProxy::installPopup( KParts::Part * part )
00099 {
00100 
00101     if ( part->inherits("KTextEditor::Document") && part->widget())
00102     {
00103         PopupMenuInterface *iface = dynamic_cast<PopupMenuInterface*>(part->widget());
00104         if (iface)
00105         {
00106             KTextEditor::View * view = static_cast<KTextEditor::View*>( part->widget() );
00107 
00108             QPopupMenu * popup = static_cast<QPopupMenu*>( part->factory()->container("ktexteditor_popup", view ) );
00109 
00110             if (!popup)
00111             {
00112                 kdWarning() << k_funcinfo << "Popup not found!" << endl;
00113                 return;
00114             }
00115 
00116             KAction * action = NULL;
00117             //If there is a tab for this file, we don't need to plug the closing menu entries here
00118             switch (dynamic_cast<NewMainWindow*>(TopLevel::getInstance())->getTabWidgetVisibility())
00119             {
00120             case KMdi::AlwaysShowTabs:
00121                 break;
00122             case KMdi::ShowWhenMoreThanOneTab:
00123                 if(PartController::getInstance()->parts()->count() > 1)
00124                     break;
00125             case KMdi::NeverShowTabs:
00126                 // I'm not sure if this is papering over a bug in xmlgui or not, but this test is
00127                 // needed in order to avoid multiple close actions in the popup menu in some cases
00128                 action = TopLevel::getInstance()->main()->actionCollection()->action( "file_close" );
00129                 if ( action && !action->isPlugged( popup ) )
00130                 {
00131                     popup->insertSeparator( 0 );
00132                     action->plug( popup, 0 );
00133                 }
00134                 action = TopLevel::getInstance()->main()->actionCollection()->action( "file_closeother" );
00135                 if ( action && !action->isPlugged( popup ) )
00136                     action->plug( popup, 1 );
00137                 break;
00138             default:
00139                 break;
00140             }
00141 
00142 
00143             iface->installPopup( popup );
00144 
00145             connect(popup, SIGNAL(aboutToShow()), this, SLOT(popupAboutToShow()));
00146 
00147             // ugly hack: mark the "original" items
00148             m_popupIds.resize(popup->count());
00149             for (uint index=0; index < popup->count(); ++index)
00150                 m_popupIds[index] = popup->idAt(index);
00151         }
00152     }
00153 }
00154 
00155 void EditorProxy::popupAboutToShow()
00156 {
00157   QPopupMenu *popup = (QPopupMenu*)sender();
00158   if (!popup)
00159     return;
00160 
00161   // ugly hack: remove all but the "original" items
00162   for (int index=popup->count()-1; index >= 0; --index)
00163   {
00164     int id = popup->idAt(index);
00165     if (m_popupIds.contains(id) == 0)
00166     {
00167       QMenuItem *item = popup->findItem(id);
00168       if (item->popup())
00169     delete item->popup();
00170       else
00171           popup->removeItemAt(index);
00172 //      kdDebug(9000) << "removed id " << id << " at index " << index << endl;
00173     } else {
00174 //        kdDebug(9000) << "leaving id " << id << endl;
00175     }
00176   }
00177 /*  // why twice !?!?
00178   // ugly hack: mark the "original" items
00179   m_popupIds.resize(popup->count());
00180   for (uint index=0; index < popup->count(); ++index)
00181     m_popupIds[index] = popup->idAt(index);
00182 */
00183 
00184   KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(PartController::getInstance()->activePart());
00185   if (!ro_part)
00186     return;
00187 /*  // I disagree.. the EditorContext shouldn't emit the filecontext event
00188   // fill the menu in the file context
00189   FileContext context(ro_part->url().path(), false);
00190   Core::getInstance()->fillContextMenu(popup, &context);
00191 */
00192   // fill the menu in the editor context
00193   if (!ro_part->widget())
00194     return;
00195 
00196   SelectionInterface *selectIface = dynamic_cast<SelectionInterface*>(ro_part);
00197   ViewCursorInterface *cursorIface = dynamic_cast<ViewCursorInterface*>(ro_part->widget());
00198   EditInterface *editIface = dynamic_cast<EditInterface*>(ro_part);
00199 
00200   QString wordstr, linestr;
00201   bool hasMultilineSelection = false;
00202   if( selectIface && selectIface->hasSelection() )
00203   {
00204     hasMultilineSelection = ( selectIface->selection().contains('\n') != 0 );
00205     if ( !hasMultilineSelection ) 
00206     {
00207       wordstr = selectIface->selection();
00208     }
00209   }
00210   if( cursorIface && editIface )
00211   {
00212     uint line, col;
00213     line = col = 0;
00214     cursorIface->cursorPositionReal(&line, &col);
00215     linestr = editIface->textLine(line);
00216     if( wordstr.isEmpty() && !hasMultilineSelection ) {
00217       int startPos = QMAX(QMIN((int)col, (int)linestr.length()-1), 0);
00218       int endPos = startPos;
00219       while (startPos >= 0 && ( linestr[startPos].isLetterOrNumber() || linestr[startPos] == '_' ) )
00220           startPos--;
00221       while (endPos < (int)linestr.length() && ( linestr[endPos].isLetterOrNumber() || linestr[endPos] == '_' ) )
00222           endPos++;
00223       wordstr = (startPos==endPos)?
00224           QString() : linestr.mid(startPos+1, endPos-startPos-1);
00225     }
00226     kdDebug(9000) << "Word:" << wordstr << ":" << endl;
00227     EditorContext context(ro_part->url(), line, col, linestr, wordstr);
00228     Core::getInstance()->fillContextMenu(popup, &context);
00229   } else {
00230     Core::getInstance()->fillContextMenu(popup, 0);
00231   }
00232 
00233   // Remove redundant separators (any that are first, last, or doubled)
00234   bool lastWasSeparator = true;
00235   for( uint i = 0; i < popup->count(); ) {
00236     int id = popup->idAt( i );
00237     if( lastWasSeparator && popup->findItem( id )->isSeparator() ) {
00238       popup->removeItem( id );
00239       // Since we removed an item, don't increment i
00240     } else {
00241       lastWasSeparator = false;
00242       i++;
00243     }
00244   }
00245   if( lastWasSeparator && popup->count() > 0 )
00246     popup->removeItem( popup->idAt( popup->count() - 1 ) );
00247 }
00248 
00249 void EditorProxy::showPopup( )
00250 {
00251     kdDebug(9000) << k_funcinfo << endl;
00252 
00253     if ( KParts::Part * part = PartController::getInstance()->activePart() )
00254     {
00255         ViewCursorInterface *iface = dynamic_cast<ViewCursorInterface*>( part->widget() );  
00256         if ( iface )
00257         {
00258             KTextEditor::View * view = static_cast<KTextEditor::View*>( part->widget() );
00259             QPopupMenu * popup = static_cast<QPopupMenu*>( view->factory()->container("ktexteditor_popup", view ) );
00260             
00261             popup->exec( view->mapToGlobal( iface->cursorCoordinates() ) );
00262         }
00263     }
00264     
00265 }
00266 
00267 void EditorProxy::registerEditor(EditorWrapper* wrapper)
00268 {
00269   m_editorParts.append(wrapper);
00270 }
00271 
00272 void EditorProxy::deregisterEditor(EditorWrapper* wrapper)
00273 {
00274   m_editorParts.remove(wrapper);
00275 }
00276 
00277 EditorWrapper::EditorWrapper(KTextEditor::Document* editor, bool activate, QWidget* parent, const char* name)
00278   : QWidgetStack(parent, name)
00279   , m_doc(editor)
00280   , m_view(0L)
00281   , m_line(0)
00282   , m_col(0)
00283   , m_first(!activate && EditorProxy::getInstance()->isDelayedViewCapable())
00284 {
00285   EditorProxy::getInstance()->registerEditor(this);
00286 }
00287 
00288 EditorWrapper::~EditorWrapper()
00289 {
00290   kdDebug() << k_funcinfo << this << endl;
00291   EditorProxy::getInstance()->deregisterEditor(this);
00292 }
00293 
00294 KTextEditor::Document* EditorWrapper::document() const
00295 {
00296   return m_doc;
00297 }
00298 
00299 void EditorWrapper::setLine(int line)
00300 {
00301   m_line = line;
00302 }
00303 
00304 void EditorWrapper::setCol(int col)
00305 {
00306   m_col = col;
00307 }
00308 
00309 void EditorWrapper::show()
00310 {
00311   if ( !m_doc ) {
00312     QWidgetStack::show();
00313     return;
00314   }
00315   
00316   if (m_first) {
00317     m_first = false;
00318     QWidgetStack::show();
00319     return;
00320   }
00321 
00322   if (m_doc->widget()) {
00323     QWidgetStack::show();
00324     return;
00325   }
00326 
00327   m_view = m_doc->createView(this);
00328   
00329   addWidget(m_view);
00330   
00331   m_doc->setWidget(m_view);
00332   // FIXME assumption check
00333   // We're managing the view deletion by being its parent, don't let the part self-destruct
00334   disconnect( m_view, SIGNAL( destroyed() ), m_doc, SLOT( slotWidgetDestroyed() ) );
00335   //connect( m_view, SIGNAL( destroyed() ), this, SLOT( deleteLater() ) );
00336   
00337   m_doc->insertChildClient(m_view);
00338 
00339   PartController::getInstance()->integrateTextEditorPart(m_doc);
00340 
00341   ViewCursorInterface *iface = dynamic_cast<ViewCursorInterface*>(static_cast<KTextEditor::View*>(m_view));
00342   if (iface) {
00343     iface->setCursorPositionReal(m_line, m_col == -1 ? 0 : m_col);
00344 
00345   } else {
00346     // Shouldn't get here
00347     Q_ASSERT(false);
00348   }
00349 
00350   QWidgetStack::show();
00351 }
00352 
00353 QWidget * EditorProxy::widgetForPart( KParts::Part * part )
00354 {
00355     if ( !part ) return 0;
00356     
00357     if (part->widget())
00358         return part->widget();
00359     
00360     for (QValueList<EditorWrapper*>::ConstIterator it = m_editorParts.begin(); it != m_editorParts.end(); ++it)
00361         if ((*it)->document() == part)
00362             return *it;
00363     
00364     return 0L;
00365 }
00366 
00367 QWidget * EditorProxy::topWidgetForPart( KParts::Part * part )
00368 {
00369     if ( !part ) return 0;
00370     
00371     for (QValueList<EditorWrapper*>::ConstIterator it = m_editorParts.begin(); it != m_editorParts.end(); ++it)
00372         if ((*it)->document() == part)
00373             return *it;
00374     
00375     if (part->widget())
00376         return part->widget();
00377     
00378     return 0L;
00379 }
00380 
00381 bool EditorProxy::isDelayedViewCapable( )
00382 {
00383     return m_delayedViewCreationCompatibleUI;
00384 }
00385 
00386 #include "editorproxy.moc"
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Feb 22 09:22:42 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003