KDevelop API Documentation

makewidget.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 1999-2001 by Bernd Gehrmann and the KDevelop Team       *
00003  *   bernd@kdevelop.org                                                    *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  ***************************************************************************/
00011 
00012 #include "makewidget.h"
00013 #include "kdevcore.h"
00014 #include "kdevmainwindow.h"
00015 #include "kdevproject.h"
00016 #include "kdevpartcontroller.h"
00017 #include "processlinemaker.h"
00018 #include "makeviewpart.h"
00019 #include "makeitem.h"
00020 #include "ktexteditor/document.h"
00021 #include "ktexteditor/cursorinterface.h"
00022 #include "ktexteditor/editinterface.h"
00023 #include "urlutil.h"
00024 
00025 #include <kdebug.h>
00026 #include <klocale.h>
00027 #include <knotifyclient.h>
00028 #include <kprocess.h>
00029 #include <kglobal.h>
00030 #include <kstandarddirs.h>
00031 #include <kinstance.h>
00032 #include <kstatusbar.h>
00033 #include <kapplication.h>
00034 #include <kconfig.h>
00035 
00036 #include <qmessagebox.h>
00037 #include <qapplication.h>
00038 #include <qdir.h>
00039 #include <qimage.h>
00040 #include <qstylesheet.h>
00041 #include <qtimer.h>
00042 #include <qfileinfo.h>
00043 #include <qclipboard.h>
00044 #include <qpopupmenu.h>
00045 #include <private/qrichtext_p.h>
00046 
00047 #include <stdlib.h>
00048 #include <limits.h>
00049 
00050 static const char *const error_xpm[] =
00051     {
00052         "11 11 5 1",
00053         ". c None",
00054         "# c #313062",
00055         "a c #6261cd",
00056         "b c #c50000",
00057         "c c #ff8583",
00058         "...........",
00059         "...####....",
00060         ".a#bbbb#a..",
00061         ".#ccbbbb#..",
00062         "#bccbbbbb#.",
00063         "#bbbbbbbb#.",
00064         "#bbbbbbcb#.",
00065         "#bbbbbccb#.",
00066         ".#bbbccb#..",
00067         ".a#bbbb#a..",
00068         "...####...."
00069     };
00070 
00071 
00072 static const char *const warning_xpm[] =
00073     {
00074         "11 11 5 1",
00075         ". c None",
00076         "# c #313062",
00077         "a c #6261cd",
00078         "b c #c5c600",
00079         "c c #ffff41",
00080         "...........",
00081         "...####....",
00082         ".a#bbbb#a..",
00083         ".#ccbbbb#..",
00084         "#bccbbbbb#.",
00085         "#bbbbbbbb#.",
00086         "#bbbbbbcb#.",
00087         "#bbbbbccb#.",
00088         ".#bbbccb#..",
00089         ".a#bbbb#a..",
00090         "...####...."
00091     };
00092 
00093 
00094 static const char *const message_xpm[] =
00095     {
00096         "11 11 5 1",
00097         ". c None",
00098         "b c #3100c5",
00099         "# c #313062",
00100         "c c #3189ff",
00101         "a c #6265cd",
00102         "...........",
00103         "...####....",
00104         ".a#bbbb#a..",
00105         ".#ccbbbb#..",
00106         "#bccbbbbb#.",
00107         "#bbbbbbbb#.",
00108         "#bbbbbbcb#.",
00109         "#bbbbbccb#.",
00110         ".#bbbccb#..",
00111         ".a#bbbb#a..",
00112         "...####...."
00113     };
00114 
00115 
00116 class SelectionPreserver
00117 {
00118 public:
00119     SelectionPreserver( QTextEdit& textEdit, bool stayAtEnd )
00120         : m_textEdit( textEdit )
00121         , m_atEnd( false )
00122     {
00123         int para, index;
00124         m_textEdit.getCursorPosition( &para, &index );
00125 
00126         m_atEnd = stayAtEnd
00127               && para == m_textEdit.paragraphs() - 1
00128               && index == m_textEdit.paragraphLength( para );
00129 
00130         m_textEdit.getSelection(&paraFrom, &indexFrom, &paraTo, &indexTo, 0);
00131     }
00132 
00133     ~SelectionPreserver()
00134     {
00135         m_textEdit.setSelection(paraFrom, indexFrom, paraTo, indexTo, 0);
00136 
00137         if ( m_atEnd )
00138         {
00139             m_textEdit.moveCursor(QTextEdit::MoveEnd, false);
00140             m_textEdit.moveCursor(QTextEdit::MoveLineStart, false);//if linewrap is off we must avoid the jumping of the vertical scrollbar
00141         }
00142     }
00143 
00144     QTextEdit& m_textEdit;
00145     bool m_atEnd;
00146     int paraFrom, indexFrom, paraTo, indexTo;
00147 };
00148 
00149 MakeWidget::MakeWidget(MakeViewPart *part)
00150     : QTextEdit(0, "make widget")
00151     , m_directoryStatusFilter( m_errorFilter )
00152     , m_errorFilter( m_continuationFilter )
00153     , m_continuationFilter( m_actionFilter )
00154     , m_actionFilter( m_otherFilter )
00155   , m_pendingItem(0)
00156     , m_paragraphs(0)
00157   , m_lastErrorSelected(-1)
00158     , m_part(part)
00159     , m_vertScrolling(false)
00160     , m_horizScrolling(false)
00161     , m_bCompiling(false)
00162 {
00163     updateSettingsFromConfig();
00164 
00165 /*  if ( m_compilerOutputLevel == eFull )
00166     {
00167         setTextFormat( Qt::LogText );
00168     }
00169     else
00170     {*/
00171         setTextFormat( Qt::RichText );
00172 //  }
00173     
00174     if ( m_bLineWrapping )
00175         setWordWrap(WidgetWidth);
00176     setWrapPolicy(Anywhere);
00177     setReadOnly(true);
00178     setMimeSourceFactory(new QMimeSourceFactory);
00179     mimeSourceFactory()->setImage("error", QImage((const char**)error_xpm));
00180     mimeSourceFactory()->setImage("warning", QImage((const char**)warning_xpm));
00181     mimeSourceFactory()->setImage("message", QImage((const char**)message_xpm));
00182 
00183     childproc = new KShellProcess("/bin/sh");
00184     procLineMaker = new ProcessLineMaker( childproc );
00185 
00186     connect( procLineMaker, SIGNAL(receivedStdoutLine(const QString&)),
00187              this, SLOT(insertStdoutLine(const QString&) ));
00188     connect( procLineMaker, SIGNAL(receivedStderrLine(const QString&)),
00189              this, SLOT(insertStderrLine(const QString&) ));
00190 
00191     connect( childproc, SIGNAL(processExited(KProcess*)),
00192              this, SLOT(slotProcessExited(KProcess*) )) ;
00193 
00194     connect( &m_directoryStatusFilter, SIGNAL(item(EnteringDirectoryItem*)),
00195              this, SLOT(slotEnteredDirectory(EnteringDirectoryItem*)) );
00196     connect( &m_directoryStatusFilter, SIGNAL(item(ExitingDirectoryItem*)),
00197              this, SLOT(slotExitedDirectory(ExitingDirectoryItem*)) );
00198     connect( &m_errorFilter, SIGNAL(item(MakeItem*)),
00199              this, SLOT(insertItem(MakeItem*)) );
00200     connect( &m_actionFilter, SIGNAL(item(MakeItem*)),
00201              this, SLOT(insertItem(MakeItem*)) );
00202     connect( &m_otherFilter, SIGNAL(item(MakeItem*)),
00203              this, SLOT(insertItem(MakeItem*)) );
00204 
00205     connect( verticalScrollBar(), SIGNAL(sliderPressed()),
00206              this, SLOT(verticScrollingOn()) );
00207     connect( verticalScrollBar(), SIGNAL(sliderReleased()),
00208              this, SLOT(verticScrollingOff()) );
00209     connect( horizontalScrollBar(), SIGNAL(sliderPressed()),
00210              this, SLOT(horizScrollingOn()) );
00211     connect( horizontalScrollBar(), SIGNAL(sliderReleased()),
00212              this, SLOT(horizScrollingOff()) );
00213 
00214     connect( m_part->partController(), SIGNAL(loadedFile(const KURL&)),
00215              this, SLOT(slotDocumentOpened(const KURL&)) );
00216 }
00217 
00218 MakeWidget::~MakeWidget()
00219 {
00220     delete mimeSourceFactory();
00221     delete childproc;
00222     delete procLineMaker;
00223 }
00224 
00225 void MakeWidget::queueJob(const QString &dir, const QString &command)
00226 {
00227     commandList.append(command);
00228     dirList.append(dir);
00229     if (!isRunning())
00230     {
00231         // Store the current output view so that it
00232         // can be restored after a successful compilation
00233         m_part->mainWindow()->storeOutputViewTab();
00234         startNextJob();
00235     }
00236 }
00237 
00238 void MakeWidget::startNextJob()
00239 {
00240     QStringList::Iterator it = commandList.begin();
00241     if ( it == commandList.end() )
00242         return;
00243 
00244     currentCommand = *it;
00245     commandList.remove(it);
00246 
00247     int i = currentCommand.findRev(" gmake");
00248     if ( i == -1 )
00249         i = currentCommand.findRev(" make");
00250     if ( i == -1 )
00251         m_bCompiling = false;
00252     else
00253     {
00254         QString s = currentCommand.right(currentCommand.length() - i);
00255         if ( s.contains("configure ")        ||
00256              s.contains(" Makefile.cvs")     ||
00257              s.contains(" clean")            ||
00258              s.contains(" distclean")        ||
00259              s.contains(" package-messages") ||
00260              s.contains(" install") )
00261         {
00262             m_bCompiling = false;
00263         }
00264         else {
00265             m_bCompiling = true;
00266         }
00267     }
00268 
00269     it = dirList.begin();
00270     QString dir = *it;
00271     dirList.remove(it);
00272 
00273     clear(); // clear the widget
00274     for ( QValueVector<MakeItem*>::iterator it = m_items.begin(); it != m_items.end(); ++it )
00275         delete *it;
00276     m_items.clear();
00277     m_paragraphToItem.clear();
00278     m_paragraphs = 0;
00279     m_lastErrorSelected = -1;
00280 
00281     insertItem( new CommandItem( currentCommand ) );
00282 
00283     childproc->clearArguments();
00284     *childproc << currentCommand;
00285     childproc->start(KProcess::NotifyOnExit, KProcess::AllOutput);
00286 
00287     dirstack.clear();
00288     dirstack.push(new QString(dir));
00289 
00290     m_part->mainWindow()->raiseView(this);
00291     m_part->core()->running(m_part, true);
00292 }
00293 
00294 void MakeWidget::killJob()
00295 {
00296     childproc->kill();
00297 }
00298 
00299 bool MakeWidget::isRunning()
00300 {
00301     return childproc->isRunning();
00302 }
00303 
00304 void MakeWidget::copy()
00305 {
00306     int parafrom=0, indexfrom=0, parato=0, indexto=0;
00307     getSelection(&parafrom, &indexfrom, &parato, &indexto);
00308     if( parafrom < 0 || indexfrom < 0 || parato < 0 || indexto < 0
00309     || ((parafrom == parato) && (indexfrom == indexto)) )
00310     {
00311         return;
00312     }
00313 
00314     QString selection;
00315     for(int i = parafrom; i<=parato; i++)
00316        selection += text(i) + "\n";
00317 
00318        
00319     if(m_compilerOutputLevel == eShort || 
00320        m_compilerOutputLevel == eVeryShort )
00321     {
00322        QRegExp regexp("<.*>");
00323        regexp.setMinimal(true);
00324        selection.remove(regexp);
00325     }
00326     else
00327     { //FIXME: Selections should be precise in the eShort and eVeryShort modes, too.
00328       selection.remove(0, indexfrom);
00329       int removeend = text(parato).length() - indexto;
00330 
00331       selection.remove((selection.length()-1) -  removeend, removeend);    
00332     }       
00333        
00334     selection.replace("&lt;","<");
00335     selection.replace("&gt;",">");
00336     selection.replace("&quot;","\"");
00337     selection.replace("&amp;","&"); 
00338        
00339     kapp->clipboard()->setText(selection, QClipboard::Clipboard);
00340 }
00341 
00342 void MakeWidget::nextError()
00343 {
00344     int parag;
00345     if (m_lastErrorSelected != -1)
00346         parag = m_lastErrorSelected;
00347     else
00348         parag = 0;
00349 
00350     //if there are no errors after m_lastErrorSelected try again from the beginning
00351     if (!scanErrorForward(parag))
00352         if (m_lastErrorSelected != -1)
00353         {
00354             m_lastErrorSelected = -1;
00355             if (!scanErrorForward(0))
00356                 KNotifyClient::beep();
00357         }
00358         else
00359             KNotifyClient::beep();
00360 }
00361 
00362 void MakeWidget::prevError()
00363 {
00364     int parag;
00365     if (m_lastErrorSelected != -1)
00366         parag = m_lastErrorSelected;
00367     else
00368         parag = 0;
00369 
00370     //if there are no errors before m_lastErrorSelected try again from the end
00371     if (!scanErrorBackward(parag))
00372         if (m_lastErrorSelected != -1)
00373         {
00374             m_lastErrorSelected = -1;
00375 #if QT_VERSION >= 0x030100
00376             parag = (int)m_items.count();
00377 #else
00378             parag = m_items.size();
00379 #endif
00380             if (!scanErrorBackward(parag))
00381                 KNotifyClient::beep();
00382         }
00383         else
00384             KNotifyClient::beep();
00385 }
00386 
00387 void MakeWidget::contentsMouseReleaseEvent( QMouseEvent* e )
00388 {
00389     QTextEdit::contentsMouseReleaseEvent(e);
00390     if ( e->button() != LeftButton )
00391         return;
00392     searchItem(paragraphAt(e->pos()));
00393 }
00394 
00395 void MakeWidget::keyPressEvent(QKeyEvent *e)
00396 {
00397     if (e->key() == Key_Return || e->key() == Key_Enter)
00398     {
00399         int parag, index;
00400         getCursorPosition(&parag, &index);
00401         searchItem(parag);
00402     }
00403     else
00404         QTextEdit::keyPressEvent(e);
00405 }
00406 
00407 // returns the current directory for parag
00408 QString MakeWidget::directory(int parag) const
00409 {
00410     QValueVector<MakeItem*>::const_iterator it = qFind( m_items.begin(), m_items.end(), m_paragraphToItem[parag] );
00411     if ( it == m_items.end() )
00412         return QString::null;
00413     // run backwards over directories and figure out where we are
00414     while ( it != m_items.begin() ) {
00415         --it;
00416         EnteringDirectoryItem* edi = dynamic_cast<EnteringDirectoryItem*>( *it );
00417         if ( edi )
00418             return edi->directory + "/";
00419     }
00420     return QString::null;
00421 }
00422 
00423 // hackish function that will return true and put string "file" in "fName" if the file
00424 // exists
00425 static bool checkFileExists( const QString& file, QString& fName )
00426 {
00427     if ( QFile::exists( file ) ) {
00428         fName = file;
00429         return true;
00430     }
00431     return false;
00432 }
00433 
00434 QString MakeWidget::guessFileName( const QString& fName, int parag ) const
00435 {
00436     // pathological case
00437     if ( ! m_part->project() ) return fName;
00438 
00439     QString name;
00440     QString dir = directory( parag );
00441 
00442     if ( fName.startsWith( "/" ) )
00443     {
00444         // absolute path given
00445         name = fName;
00446     }
00447     else if ( !dir.isEmpty() )
00448     {
00449         name = dir + fName;
00450     }
00451     else
00452     {
00453         // now it gets tricky - no directory navigation messages,
00454         // no absolute path - let's guess.
00455         name = fName;
00456         if ( !checkFileExists( m_part->project()->projectDirectory() + "/" + fName, name ) &&
00457          !checkFileExists( m_part->project()->projectDirectory() + "/" + m_part->project()->activeDirectory() + "/" + fName, name ) )
00458             checkFileExists( m_part->project()->buildDirectory() + "/" + fName, name );
00459     }
00460 
00461     kdDebug(9004) << "Opening file: " << fName << endl;
00462 
00463     // GNU make resolves symlinks. if "name" is a real path to a file the
00464     // project know by symlink path, we need to return the symlink path
00465 //    QStringList projectFiles = m_part->project()->allFiles();
00466     QStringList projectFiles = m_part->project()->symlinkProjectFiles();
00467     QStringList::iterator it = projectFiles.begin();
00468     while ( it != projectFiles.end() )
00469     {
00470         QString file = m_part->project()->projectDirectory() + "/" + *it;
00471         if ( name == URLUtil::canonicalPath( file ) )
00472         {
00473             kdDebug(9004) << "Found file in project - " << file << " == " << name << endl;
00474             return file;
00475         }
00476         ++it;
00477     }
00478 
00479     // this should only happen if the file is not in the project
00480     return name;
00481 }
00482 
00483 void MakeWidget::searchItem(int parag)
00484 {
00485     ErrorItem* item = dynamic_cast<ErrorItem*>( m_paragraphToItem[parag] );
00486     if ( item )
00487     {
00488         // open the file
00489         kdDebug(9004) << "Opening file: " << guessFileName(item->fileName, parag) << endl;
00490         if (item->m_cursor) {
00491             uint line, col;
00492             item->m_cursor->position(&line, &col);
00493             kdDebug() << "Cursor new position: " << col << endl;
00494             m_part->partController()->editDocument(KURL( guessFileName(item->fileName, parag) ), line, col);
00495         } else {
00496             m_part->partController()->editDocument(KURL( guessFileName(item->fileName, parag) ), item->lineNum);
00497         }
00498         m_part->mainWindow()->statusBar()->message( item->m_error, 10000 );
00499         m_part->mainWindow()->lowerView(this);
00500         m_lastErrorSelected = parag;
00501     }
00502 }
00503 
00504 void MakeWidget::insertStdoutLine( const QString& line )
00505 {
00506     if ( !appendToLastLine( line ) )
00507         m_directoryStatusFilter.processLine( line );
00508 }
00509 
00510 void MakeWidget::insertStderrLine( const QString& line )
00511 {
00512     if ( !appendToLastLine( line ) )
00513         {
00514             kdDebug() << "inserting stderr line: " << line << endl;
00515         m_errorFilter.processLine( line );
00516   }
00517 }
00518 
00519 void MakeWidget::slotProcessExited(KProcess *)
00520 {
00521     if (childproc->normalExit())
00522     {
00523         if (childproc->exitStatus())
00524         {
00525             KNotifyClient::event( "ProcessError", i18n("The process has finished with errors"));
00526             emit m_part->commandFailed(currentCommand);
00527         }
00528         else
00529         {
00530             KNotifyClient::event( "ProcessSuccess", i18n("The process has finished successfully"));
00531             emit m_part->commandFinished(currentCommand);
00532         }
00533     }
00534 
00535     MakeItem* item = new ExitStatusItem( childproc->normalExit(), childproc->exitStatus() );
00536     insertItem( item );
00537   displayPendingItem();
00538 
00539     m_part->mainWindow()->statusBar()->message( QString("%1: %2").arg(currentCommand).arg(item->m_text), 3000);
00540     m_part->core()->running(m_part, false);
00541 
00542     // Defensive programming: We emit this with a single shot timer so that we go once again
00543     // through the event loop. After that, we can be sure that the process is really finished
00544     // and its KProcess object can be reused.
00545     if (childproc->normalExit() && !childproc->exitStatus())
00546     {
00547         QTimer::singleShot(0, this, SLOT(startNextJob()));
00548         if (commandList.isEmpty())
00549             // The last command on the list was successful so restore the
00550             // output view to what it had before the compilation process started
00551             m_part->mainWindow()->restoreOutputViewTab();
00552     }
00553     else
00554     {
00555         commandList.clear();
00556         dirList.clear();
00557     }
00558 }
00559 
00560 void MakeWidget::slotEnteredDirectory( EnteringDirectoryItem* item )
00561 {
00562 //  kdDebug(9004) << "Entering dir: " << item->directory << endl;
00563     QString* dir = new QString( item->directory );
00564     dirstack.push( dir );
00565     insertItem( item );
00566 }
00567 
00568 void MakeWidget::slotExitedDirectory( ExitingDirectoryItem* item )
00569 {
00570     QString eDir = item->directory;
00571 //  kdDebug(9004) << "Leaving dir: " << eDir << endl;
00572     QString *dir = dirstack.pop();
00573     if (!dir)
00574     {
00575         kdWarning(9004) << "Left more directories than entered: " << eDir;
00576     }
00577     else if (dir->compare(eDir) != 0)
00578     {
00579         kdWarning(9004) << "Expected directory: \"" << *dir << "\" but got \"" << eDir << "\"" << endl;
00580     }
00581     insertItem( item );
00582     delete dir;
00583 }
00584 
00585 void MakeWidget::displayPendingItem()
00586 {
00587   if (!m_pendingItem) return;
00588   // this handles the case of ImmDisplay|Append
00589   // We call displayPendingItem once in insertItem
00590   // and the appends are handled directly in
00591   // appendToLastLine
00592   if (!m_items.empty() 
00593       && m_items.last() == m_pendingItem) return;
00594 
00595   m_items.push_back(m_pendingItem);
00596 
00597   if ( m_bCompiling && !m_pendingItem->visible( m_compilerOutputLevel ) )
00598     return;
00599 
00600   SelectionPreserver preserveSelection( *this, !m_vertScrolling && !m_horizScrolling );
00601   m_paragraphToItem.insert( m_paragraphs++, m_pendingItem );
00602   append( m_pendingItem->formattedText( m_compilerOutputLevel, brightBg() ) );
00603 }
00604 
00605 bool MakeWidget::appendToLastLine( const QString& text )
00606 {
00607     if ( !m_pendingItem ) return false;
00608     if ( !m_pendingItem->append( text ) )
00609   {
00610     displayPendingItem();
00611     m_pendingItem = 0;
00612         return false;
00613   }
00614 
00615   int mode = m_pendingItem -> displayMode();
00616   if ((mode & MakeItem::Append) && (mode & MakeItem::ImmDisplay))
00617   {
00618     removeParagraph(paragraphs() - 1);
00619     SelectionPreserver preserveSelection( *this, !m_vertScrolling && !m_horizScrolling );
00620     append( m_pendingItem->formattedText( m_compilerOutputLevel, brightBg() ) );
00621   }
00622 
00623     return true;
00624 }
00625 
00626 void MakeWidget::insertItem( MakeItem* new_item )
00627 {
00628     ErrorItem* e = dynamic_cast<ErrorItem*>(new_item);
00629     if (e)
00630         createCursor(e, 0L);
00631 
00632   displayPendingItem();
00633   m_pendingItem = new_item;
00634 
00635   if (!new_item) return;
00636 
00637   int mode = new_item -> displayMode();
00638   if (mode & MakeItem::ImmDisplay)
00639   {
00640     displayPendingItem();
00641     if (!(mode & MakeItem::Append))
00642       m_pendingItem = 0;
00643   }
00644 }
00645 
00646 void MakeWidget::slotDocumentOpened( const KURL & filename )
00647 {
00648     KParts::Part* part = m_part->partController()->partForURL(filename);
00649     KTextEditor::Document* doc = dynamic_cast<KTextEditor::Document*>(part);
00650 
00651     if (!doc) {
00652         kdWarning() << k_funcinfo << "Couldn't find the document that was just opened." << endl;
00653         return;
00654     }
00655 
00656     connect(part, SIGNAL(destroyed(QObject*)), this, SLOT(slotDocumentClosed(QObject*)) );
00657 
00658     for (QValueVector<MakeItem*>::iterator it = m_items.begin(); it != m_items.end(); ++it) {
00659         ErrorItem* e = dynamic_cast<ErrorItem*>(*it);
00660 
00661         if (!e || e->m_cursor) continue;
00662 
00663         if (filename.path().endsWith(e->fileName))
00664             createCursor(e, doc);
00665     }
00666 }
00667 
00668 void MakeWidget::createCursor(ErrorItem* e, KTextEditor::Document* doc)
00669 {
00670     // Disabled for now - comment out to test. You need an up-to-date cvs head katepart to avoid mem leaks
00671     return;
00672 
00673     // try to get a KTextEditor::Cursor, so that we can retain position in
00674     // a document even when it is edited
00675     if (!doc)
00676         doc = dynamic_cast<KTextEditor::Document*>(m_part->partController()->partForURL(KURL( guessFileName(e->fileName, m_paragraphs + 1 ))));
00677 
00678     if (doc) {
00679         KTextEditor::EditInterface* edit = dynamic_cast<KTextEditor::EditInterface*>(doc);
00680         KTextEditor::CursorInterface* cursor = dynamic_cast<KTextEditor::CursorInterface*>(doc);
00681         if (cursor) {
00682             e->m_cursor = cursor->createCursor();
00683             uint col = 0;
00684             static QRegExp startOfText("[\\S]");
00685             if (edit) {
00686                 int newcol = edit->textLine(e->lineNum).find(startOfText);
00687                 if (newcol != -1) col = uint(newcol);
00688             }
00689             e->m_cursor->setPosition(e->lineNum, col);
00690             e->m_doc = doc;
00691         }
00692     }
00693 }
00694 
00695 void MakeWidget::slotDocumentClosed(QObject* doc)
00696 {
00697     KTextEditor::Document* document = static_cast<KTextEditor::Document*>(doc);
00698 
00699     for (QValueVector<MakeItem*>::iterator it = m_items.begin(); it != m_items.end(); ++it) {
00700         ErrorItem* e = dynamic_cast<ErrorItem*>(*it);
00701 
00702         if (!e || e->m_doc != document) continue;
00703 
00704         e->m_cursor = 0L;
00705         e->m_doc = 0L;
00706     }
00707 }
00708 
00709 bool MakeWidget::brightBg()
00710 {
00711     int h,s,v;
00712     paletteBackgroundColor().hsv( &h, &s, &v );
00713     return (v > 127);
00714 }
00715 
00716 QPopupMenu* MakeWidget::createPopupMenu( const QPoint& pos )
00717 {
00718     QPopupMenu* pMenu = QTextEdit::createPopupMenu(pos);
00719     pMenu->setCheckable(true);
00720 
00721     pMenu->insertSeparator();
00722     int id = pMenu->insertItem(i18n("Line Wrapping"), this, SLOT(toggleLineWrapping()) );
00723     pMenu->setItemChecked(id, m_bLineWrapping);
00724     pMenu->setWhatsThis(id, i18n("<b>Line wrapping</b><p>Enables or disables wrapping of command lines displayed."));
00725 
00726     pMenu->insertSeparator();
00727     id = pMenu->insertItem(i18n("Very Short Compiler Output"), this, SLOT(slotVeryShortCompilerOutput()) );
00728     pMenu->setWhatsThis(id, i18n("<b>Very short compiler output</b><p>Displays only warnings, errors and the file names which are compiled."));
00729     pMenu->setItemChecked(id, m_compilerOutputLevel == eVeryShort);
00730     id = pMenu->insertItem(i18n("Short Compiler Output"), this, SLOT(slotShortCompilerOutput()) );
00731     pMenu->setWhatsThis(id, i18n("<b>Short compiler output</b><p>Suppresses all the compiler flags and formats to something readable."));
00732     pMenu->setItemChecked(id, m_compilerOutputLevel == eShort);
00733     id = pMenu->insertItem(i18n("Full Compiler Output"), this, SLOT(slotFullCompilerOutput()) );
00734     pMenu->setWhatsThis(id, i18n("<b>Full compiler output</b><p>Displays unmodified compiler output."));
00735     pMenu->setItemChecked(id, m_compilerOutputLevel == eFull);
00736 
00737     pMenu->insertSeparator();
00738     id = pMenu->insertItem(i18n("Show Directory Navigation Messages"), this, SLOT(toggleShowDirNavigMessages()));
00739     pMenu->setWhatsThis(id, i18n("<b>Show directory navigation messages</b><p>Shows <b>cd</b> commands that are executed while building."));
00740     pMenu->setItemChecked(id, DirectoryItem::getShowDirectoryMessages());
00741 
00742     return pMenu;
00743 }
00744 
00745 void MakeWidget::toggleLineWrapping()
00746 {
00747     m_bLineWrapping = !m_bLineWrapping;
00748     KConfig *pConfig = kapp->config();
00749     pConfig->setGroup("MakeOutputView");
00750     pConfig->writeEntry("LineWrapping", m_bLineWrapping);
00751     pConfig->sync();
00752     if (m_bLineWrapping) {
00753         setWordWrap(WidgetWidth);
00754     }
00755     else
00756     {
00757         setWordWrap(NoWrap);
00758     }
00759 }
00760 
00761 void MakeWidget::refill()
00762 {
00763     clear();
00764     m_paragraphToItem.clear();
00765     m_paragraphs = 0;
00766     for( uint i = 0; i < m_items.size(); i++ )
00767     {
00768         if ( m_bCompiling && !m_items[i]->visible( m_compilerOutputLevel ) )
00769             continue;
00770         m_paragraphToItem.insert( m_paragraphs++, m_items[i] );
00771         append( m_items[i]->formattedText( m_compilerOutputLevel, brightBg() ) );
00772     }
00773 
00774 }
00775 
00776 void MakeWidget::slotVeryShortCompilerOutput() { setTextFormat( Qt::RichText ); setCompilerOutputLevel(eVeryShort); }
00777 void MakeWidget::slotShortCompilerOutput() { setTextFormat( Qt::RichText ); setCompilerOutputLevel(eShort); }
00778 void MakeWidget::slotFullCompilerOutput() { setTextFormat( Qt::RichText ); setCompilerOutputLevel(eFull);  }
00779 
00780 void MakeWidget::setCompilerOutputLevel(EOutputLevel level)
00781 {
00782     m_compilerOutputLevel = level;
00783     KConfig *pConfig = kapp->config();
00784     pConfig->setGroup("MakeOutputView");
00785     pConfig->writeEntry("CompilerOutputLevel", (int) level);
00786     pConfig->sync();
00787     refill();
00788 }
00789 
00790 void MakeWidget::toggleShowDirNavigMessages()
00791 {
00792     DirectoryItem::setShowDirectoryMessages( !DirectoryItem::getShowDirectoryMessages() );
00793     KConfig *pConfig = kapp->config();
00794     pConfig->setGroup("MakeOutputView");
00795     pConfig->writeEntry("ShowDirNavigMsg", DirectoryItem::getShowDirectoryMessages());
00796     pConfig->sync();
00797     refill();
00798 }
00799 
00800 void MakeWidget::updateSettingsFromConfig()
00801 {
00802     KConfig *pConfig = kapp->config();
00803     pConfig->setGroup("MakeOutputView");
00804     setFont(pConfig->readFontEntry("Messages Font"));
00805     m_bLineWrapping = pConfig->readBoolEntry("LineWrapping", true);
00806     m_compilerOutputLevel = (EOutputLevel) pConfig->readNumEntry("CompilerOutputLevel", (int) eVeryShort);
00807     DirectoryItem::setShowDirectoryMessages( pConfig->readBoolEntry("ShowDirNavigMsg", false) );
00808 }
00809 
00810 bool MakeWidget::scanErrorForward( int parag )
00811 {
00812     for ( int it = parag + 1;
00813           it < (int)m_items.count();
00814           ++it )
00815     {
00816         ErrorItem* item = dynamic_cast<ErrorItem*>( m_paragraphToItem[it] );
00817         if ( !item )
00818             continue;
00819         parag = it;
00820         document()->removeSelection(0);
00821         setSelection(parag, 0, parag+1, 0, 0);
00822         setCursorPosition(parag, 0);
00823         ensureCursorVisible();
00824         searchItem( it );
00825         return true;
00826     }
00827     return false;
00828 }
00829 
00830 bool MakeWidget::scanErrorBackward( int parag )
00831 {
00832     for ( int it = parag - 1; it >= 0; --it)
00833     {
00834         ErrorItem* item = dynamic_cast<ErrorItem*>( m_paragraphToItem[it] );
00835         if ( !item )
00836             continue;
00837         parag = it;
00838         document()->removeSelection(0);
00839         setSelection(parag, 0, parag+1, 0, 0);
00840         setCursorPosition(parag, 0);
00841         ensureCursorVisible();
00842         searchItem( it );
00843         return true;
00844     }
00845     return false;
00846 }
00847 
00848 #include "makewidget.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:41 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003