|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 1999-2001 by Bernd Gehrmann and the KDevelop Team *
|
|
|
|
* bernd@kdevelop.org *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "makewidget.h"
|
|
|
|
#include "kdevcore.h"
|
|
|
|
#include "kdevmainwindow.h"
|
|
|
|
#include "kdevproject.h"
|
|
|
|
#include "kdevpartcontroller.h"
|
|
|
|
#include "processlinemaker.h"
|
|
|
|
#include "makeviewpart.h"
|
|
|
|
#include "makeitem.h"
|
|
|
|
#include "ktexteditor/document.h"
|
|
|
|
#include "ktexteditor/cursorinterface.h"
|
|
|
|
#include "ktexteditor/editinterface.h"
|
|
|
|
#include "urlutil.h"
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <knotifyclient.h>
|
|
|
|
#include <kprocess.h>
|
|
|
|
#include <kglobal.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kinstance.h>
|
|
|
|
#include <kstatusbar.h>
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kconfig.h>
|
|
|
|
|
|
|
|
#include <tqmessagebox.h>
|
|
|
|
#include <tqapplication.h>
|
|
|
|
#include <tqdir.h>
|
|
|
|
#include <tqimage.h>
|
|
|
|
#include <tqstylesheet.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqfileinfo.h>
|
|
|
|
#include <tqclipboard.h>
|
|
|
|
#include <tqpopupmenu.h>
|
|
|
|
#include <tqrichtext_p.h>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
static const char *const error_xpm[] =
|
|
|
|
{
|
|
|
|
"11 11 5 1",
|
|
|
|
". c None",
|
|
|
|
"# c #313062",
|
|
|
|
"a c #6261cd",
|
|
|
|
"b c #c50000",
|
|
|
|
"c c #ff8583",
|
|
|
|
"...........",
|
|
|
|
"...####....",
|
|
|
|
".a#bbbb#a..",
|
|
|
|
".#ccbbbb#..",
|
|
|
|
"#bccbbbbb#.",
|
|
|
|
"#bbbbbbbb#.",
|
|
|
|
"#bbbbbbcb#.",
|
|
|
|
"#bbbbbccb#.",
|
|
|
|
".#bbbccb#..",
|
|
|
|
".a#bbbb#a..",
|
|
|
|
"...####...."
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const char *const warning_xpm[] =
|
|
|
|
{
|
|
|
|
"11 11 5 1",
|
|
|
|
". c None",
|
|
|
|
"# c #313062",
|
|
|
|
"a c #6261cd",
|
|
|
|
"b c #c5c600",
|
|
|
|
"c c #ffff41",
|
|
|
|
"...........",
|
|
|
|
"...####....",
|
|
|
|
".a#bbbb#a..",
|
|
|
|
".#ccbbbb#..",
|
|
|
|
"#bccbbbbb#.",
|
|
|
|
"#bbbbbbbb#.",
|
|
|
|
"#bbbbbbcb#.",
|
|
|
|
"#bbbbbccb#.",
|
|
|
|
".#bbbccb#..",
|
|
|
|
".a#bbbb#a..",
|
|
|
|
"...####...."
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const char *const message_xpm[] =
|
|
|
|
{
|
|
|
|
"11 11 5 1",
|
|
|
|
". c None",
|
|
|
|
"b c #3100c5",
|
|
|
|
"# c #313062",
|
|
|
|
"c c #3189ff",
|
|
|
|
"a c #6265cd",
|
|
|
|
"...........",
|
|
|
|
"...####....",
|
|
|
|
".a#bbbb#a..",
|
|
|
|
".#ccbbbb#..",
|
|
|
|
"#bccbbbbb#.",
|
|
|
|
"#bbbbbbbb#.",
|
|
|
|
"#bbbbbbcb#.",
|
|
|
|
"#bbbbbccb#.",
|
|
|
|
".#bbbccb#..",
|
|
|
|
".a#bbbb#a..",
|
|
|
|
"...####...."
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class SelectionPreserver
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SelectionPreserver( TQTextEdit& textEdit, bool stayAtEnd )
|
|
|
|
: m_textEdit( textEdit )
|
|
|
|
, m_atEnd( false )
|
|
|
|
{
|
|
|
|
int para, index;
|
|
|
|
m_textEdit.getCursorPosition( ¶, &index );
|
|
|
|
|
|
|
|
m_atEnd = stayAtEnd
|
|
|
|
&& para == m_textEdit.paragraphs() - 1
|
|
|
|
&& index == m_textEdit.paragraphLength( para );
|
|
|
|
|
|
|
|
m_textEdit.getSelection(¶From, &indexFrom, ¶To, &indexTo, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
~SelectionPreserver()
|
|
|
|
{
|
|
|
|
m_textEdit.setSelection(paraFrom, indexFrom, paraTo, indexTo, 0);
|
|
|
|
|
|
|
|
if ( m_atEnd )
|
|
|
|
{
|
|
|
|
m_textEdit.moveCursor(TQTextEdit::MoveEnd, false);
|
|
|
|
m_textEdit.moveCursor(TQTextEdit::MoveLineStart, false);//if linewrap is off we must avoid the jumping of the vertical scrollbar
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQTextEdit& m_textEdit;
|
|
|
|
bool m_atEnd;
|
|
|
|
int paraFrom, indexFrom, paraTo, indexTo;
|
|
|
|
};
|
|
|
|
|
|
|
|
MakeWidget::MakeWidget(MakeViewPart *part)
|
|
|
|
: TQTextEdit(0, "make widget")
|
|
|
|
, m_directoryStatusFilter( m_errorFilter )
|
|
|
|
, m_errorFilter( m_continuationFilter )
|
|
|
|
, m_continuationFilter( m_actionFilter )
|
|
|
|
, m_actionFilter( m_otherFilter )
|
|
|
|
, m_pendingItem(0)
|
|
|
|
, m_paragraphs(0)
|
|
|
|
, m_lastErrorSelected(-1)
|
|
|
|
, m_part(part)
|
|
|
|
, m_vertScrolling(false)
|
|
|
|
, m_horizScrolling(false)
|
|
|
|
, m_bCompiling(false)
|
|
|
|
{
|
|
|
|
updateSettingsFromConfig();
|
|
|
|
|
|
|
|
setTextFormat( TQt::RichText );
|
|
|
|
|
|
|
|
if ( m_bLineWrapping )
|
|
|
|
setWordWrap(WidgetWidth);
|
|
|
|
else
|
|
|
|
setWordWrap(NoWrap);
|
|
|
|
|
|
|
|
setWrapPolicy(Anywhere);
|
|
|
|
setReadOnly(true);
|
|
|
|
setMimeSourceFactory(new TQMimeSourceFactory);
|
|
|
|
mimeSourceFactory()->setImage("error", TQImage((const char**)error_xpm));
|
|
|
|
mimeSourceFactory()->setImage("warning", TQImage((const char**)warning_xpm));
|
|
|
|
mimeSourceFactory()->setImage("message", TQImage((const char**)message_xpm));
|
|
|
|
|
|
|
|
dirstack.setAutoDelete(true);
|
|
|
|
|
|
|
|
childproc = new KProcess(TQT_TQOBJECT(this));
|
|
|
|
procLineMaker = new ProcessLineMaker( childproc );
|
|
|
|
|
|
|
|
connect( procLineMaker, TQT_SIGNAL(receivedStdoutLine(const TQCString&)),
|
|
|
|
this, TQT_SLOT(insertStdoutLine(const TQCString&) ));
|
|
|
|
connect( procLineMaker, TQT_SIGNAL(receivedStderrLine(const TQCString&)),
|
|
|
|
this, TQT_SLOT(insertStderrLine(const TQCString&) ));
|
|
|
|
connect( procLineMaker, TQT_SIGNAL(receivedPartialStdoutLine(const TQCString&)),
|
|
|
|
this, TQT_SLOT(storePartialStdoutLine(const TQCString&) ));
|
|
|
|
connect( procLineMaker, TQT_SIGNAL(receivedPartialStderrLine(const TQCString&)),
|
|
|
|
this, TQT_SLOT(storePartialStderrLine(const TQCString&) ));
|
|
|
|
|
|
|
|
connect( childproc, TQT_SIGNAL(processExited(KProcess*)),
|
|
|
|
this, TQT_SLOT(slotProcessExited(KProcess*) )) ;
|
|
|
|
|
|
|
|
connect( &m_directoryStatusFilter, TQT_SIGNAL(item(EnteringDirectoryItem*)),
|
|
|
|
this, TQT_SLOT(slotEnteredDirectory(EnteringDirectoryItem*)) );
|
|
|
|
connect( &m_directoryStatusFilter, TQT_SIGNAL(item(ExitingDirectoryItem*)),
|
|
|
|
this, TQT_SLOT(slotExitedDirectory(ExitingDirectoryItem*)) );
|
|
|
|
connect( &m_errorFilter, TQT_SIGNAL(item(MakeItem*)),
|
|
|
|
this, TQT_SLOT(insertItem(MakeItem*)) );
|
|
|
|
connect( &m_actionFilter, TQT_SIGNAL(item(MakeItem*)),
|
|
|
|
this, TQT_SLOT(insertItem(MakeItem*)) );
|
|
|
|
connect( &m_otherFilter, TQT_SIGNAL(item(MakeItem*)),
|
|
|
|
this, TQT_SLOT(insertItem(MakeItem*)) );
|
|
|
|
|
|
|
|
connect( verticalScrollBar(), TQT_SIGNAL(sliderPressed()),
|
|
|
|
this, TQT_SLOT(verticScrollingOn()) );
|
|
|
|
connect( verticalScrollBar(), TQT_SIGNAL(sliderReleased()),
|
|
|
|
this, TQT_SLOT(verticScrollingOff()) );
|
|
|
|
connect( horizontalScrollBar(), TQT_SIGNAL(sliderPressed()),
|
|
|
|
this, TQT_SLOT(horizScrollingOn()) );
|
|
|
|
connect( horizontalScrollBar(), TQT_SIGNAL(sliderReleased()),
|
|
|
|
this, TQT_SLOT(horizScrollingOff()) );
|
|
|
|
|
|
|
|
// this slot doesn't exist anymore
|
|
|
|
// connect( m_part->partController(), TQT_SIGNAL(loadedFile(const KURL&)),
|
|
|
|
// this, TQT_SLOT(slotDocumentOpened(const KURL&)) );
|
|
|
|
}
|
|
|
|
|
|
|
|
MakeWidget::~MakeWidget()
|
|
|
|
{
|
|
|
|
delete mimeSourceFactory();
|
|
|
|
delete childproc;
|
|
|
|
delete procLineMaker;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::queueJob(const TQString &dir, const TQString &command)
|
|
|
|
{
|
|
|
|
commandList.append(command);
|
|
|
|
dirList.append(dir);
|
|
|
|
if (!isRunning())
|
|
|
|
{
|
|
|
|
// Store the current output view so that it
|
|
|
|
// can be restored after a successful compilation
|
|
|
|
// m_part->mainWindow()->storeOutputViewTab();
|
|
|
|
startNextJob();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::startNextJob()
|
|
|
|
{
|
|
|
|
TQStringList::Iterator it = commandList.begin();
|
|
|
|
if ( it == commandList.end() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
currentCommand = *it;
|
|
|
|
commandList.remove(it);
|
|
|
|
|
|
|
|
int i = currentCommand.tqfindRev(" gmake");
|
|
|
|
if ( i == -1 )
|
|
|
|
i = currentCommand.tqfindRev(" make");
|
|
|
|
if ( i == -1 )
|
|
|
|
m_bCompiling = false;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TQString s = currentCommand.right(currentCommand.length() - i);
|
|
|
|
if ( s.tqcontains("configure ") ||
|
|
|
|
s.tqcontains(" Makefile.cvs") ||
|
|
|
|
s.tqcontains(" clean") ||
|
|
|
|
s.tqcontains(" distclean") ||
|
|
|
|
s.tqcontains(" package-messages") ||
|
|
|
|
s.tqcontains(" install") )
|
|
|
|
{
|
|
|
|
m_bCompiling = false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_bCompiling = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
it = dirList.begin();
|
|
|
|
TQString dir = *it;
|
|
|
|
m_lastBuildDir = dir;
|
|
|
|
dirList.remove(it);
|
|
|
|
|
|
|
|
clear(); // clear the widget
|
|
|
|
for ( TQValueVector<MakeItem*>::iterator it = m_items.begin(); it != m_items.end(); ++it )
|
|
|
|
delete *it;
|
|
|
|
m_items.clear();
|
|
|
|
m_paragraphToItem.clear();
|
|
|
|
m_paragraphs = 0;
|
|
|
|
m_lastErrorSelected = -1;
|
|
|
|
|
|
|
|
insertItem( new CommandItem( currentCommand ) );
|
|
|
|
|
|
|
|
childproc->clearArguments();
|
|
|
|
*childproc << currentCommand;
|
|
|
|
childproc->setUseShell(true);
|
|
|
|
childproc->start(KProcess::OwnGroup, KProcess::AllOutput);
|
|
|
|
|
|
|
|
dirstack.clear();
|
|
|
|
dirstack.push(new TQString(dir));
|
|
|
|
|
|
|
|
m_part->mainWindow()->raiseView(this);
|
|
|
|
m_part->core()->running(m_part, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::killJob()
|
|
|
|
{
|
|
|
|
if (!childproc->kill(SIGINT))
|
|
|
|
childproc->kill();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MakeWidget::isRunning()
|
|
|
|
{
|
|
|
|
return childproc->isRunning();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::copy()
|
|
|
|
{
|
|
|
|
int parafrom=0, indexfrom=0, parato=0, indexto=0;
|
|
|
|
getSelection(¶from, &indexfrom, ¶to, &indexto);
|
|
|
|
if( parafrom < 0 || indexfrom < 0 || parato < 0 || indexto < 0
|
|
|
|
|| ((parafrom == parato) && (indexfrom == indexto)) )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString selection;
|
|
|
|
for(int i = parafrom; i<=parato; i++)
|
|
|
|
selection += text(i) + "\n";
|
|
|
|
|
|
|
|
|
|
|
|
if(m_compilerOutputLevel == eShort ||
|
|
|
|
m_compilerOutputLevel == eVeryShort )
|
|
|
|
{
|
|
|
|
TQRegExp regexp("<.*>");
|
|
|
|
regexp.setMinimal(true);
|
|
|
|
selection.remove(regexp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ //FIXME: Selections should be precise in the eShort and eVeryShort modes, too.
|
|
|
|
selection.remove(0, indexfrom);
|
|
|
|
int removeend = text(parato).length() - indexto;
|
|
|
|
|
|
|
|
selection.remove((selection.length()-1) - removeend, removeend);
|
|
|
|
}
|
|
|
|
|
|
|
|
selection.tqreplace("<","<");
|
|
|
|
selection.tqreplace(">",">");
|
|
|
|
selection.tqreplace(""","\"");
|
|
|
|
selection.tqreplace("&","&");
|
|
|
|
|
|
|
|
kapp->tqclipboard()->setText(selection, TQClipboard::Clipboard);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::nextError()
|
|
|
|
{
|
|
|
|
int parag;
|
|
|
|
if (m_lastErrorSelected != -1)
|
|
|
|
parag = m_lastErrorSelected;
|
|
|
|
else
|
|
|
|
parag = 0;
|
|
|
|
|
|
|
|
//if there are no errors after m_lastErrorSelected try again from the beginning
|
|
|
|
if (!scanErrorForward(parag))
|
|
|
|
if (m_lastErrorSelected != -1)
|
|
|
|
{
|
|
|
|
m_lastErrorSelected = -1;
|
|
|
|
if (!scanErrorForward(0))
|
|
|
|
KNotifyClient::beep();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
KNotifyClient::beep();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::prevError()
|
|
|
|
{
|
|
|
|
int parag;
|
|
|
|
if (m_lastErrorSelected != -1)
|
|
|
|
parag = m_lastErrorSelected;
|
|
|
|
else
|
|
|
|
parag = 0;
|
|
|
|
|
|
|
|
//if there are no errors before m_lastErrorSelected try again from the end
|
|
|
|
if (!scanErrorBackward(parag))
|
|
|
|
if (m_lastErrorSelected != -1)
|
|
|
|
{
|
|
|
|
m_lastErrorSelected = -1;
|
|
|
|
parag = (int)m_items.count();
|
|
|
|
if (!scanErrorBackward(parag))
|
|
|
|
KNotifyClient::beep();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
KNotifyClient::beep();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::contentsMouseReleaseEvent( TQMouseEvent* e )
|
|
|
|
{
|
|
|
|
TQTextEdit::contentsMouseReleaseEvent(e);
|
|
|
|
if ( e->button() != Qt::LeftButton )
|
|
|
|
return;
|
|
|
|
searchItem(paragraphAt(e->pos()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::keyPressEvent(TQKeyEvent *e)
|
|
|
|
{
|
|
|
|
if (e->key() == Key_Return || e->key() == Key_Enter)
|
|
|
|
{
|
|
|
|
int parag, index;
|
|
|
|
getCursorPosition(¶g, &index);
|
|
|
|
searchItem(parag);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
TQTextEdit::keyPressEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns the current directory for parag
|
|
|
|
TQString MakeWidget::directory(int parag) const
|
|
|
|
{
|
|
|
|
TQValueVector<MakeItem*>::const_iterator it = tqFind( m_items.begin(), m_items.end(), m_paragraphToItem[parag] );
|
|
|
|
if ( it == m_items.end() )
|
|
|
|
return TQString();
|
|
|
|
// run backwards over directories and figure out where we are
|
|
|
|
while ( it != m_items.begin() ) {
|
|
|
|
--it;
|
|
|
|
EnteringDirectoryItem* edi = dynamic_cast<EnteringDirectoryItem*>( *it );
|
|
|
|
if ( edi )
|
|
|
|
return edi->directory + "/";
|
|
|
|
}
|
|
|
|
return TQString();
|
|
|
|
}
|
|
|
|
|
|
|
|
// hackish function that will return true and put string "file" in "fName" if the file
|
|
|
|
// exists
|
|
|
|
static bool checkFileExists( const TQString& file, TQString& fName )
|
|
|
|
{
|
|
|
|
if ( TQFile::exists( file ) ) {
|
|
|
|
fName = file;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::specialCheck( const TQString& file, TQString& fName ) const
|
|
|
|
{
|
|
|
|
TQString firstLine = text(0);
|
|
|
|
TQRegExp rx("cd \\'(.*)\\'.*");
|
|
|
|
if (rx.search(firstLine) != -1)
|
|
|
|
{
|
|
|
|
KURL url(rx.cap(1)+"/", file);
|
|
|
|
if (url.isValid())
|
|
|
|
{
|
|
|
|
kdDebug(9004) << "MakeWidget::specialCheck thinks that url is: " << url.url()
|
|
|
|
<< " origin: " << file << endl;
|
|
|
|
fName = url.url();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Ok the "worst case", lets see if we can find a file in the project that has the same name
|
|
|
|
// obviously this will pick always the wrong file when you've got the same filename multiple times.
|
|
|
|
TQStringList files = m_part->project()->allFiles();
|
|
|
|
for( TQStringList::iterator it = files.begin() ; it != files.end(); ++it)
|
|
|
|
{
|
|
|
|
if( (*it).tqcontains( file ) )
|
|
|
|
{
|
|
|
|
fName = URLUtil::canonicalPath( m_part->project()->projectDirectory() + "/" + *it );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString MakeWidget::guessFileName( const TQString& fName, int parag ) const
|
|
|
|
{
|
|
|
|
// pathological case
|
|
|
|
if ( ! m_part->project() ) return fName;
|
|
|
|
|
|
|
|
TQString name;
|
|
|
|
TQString dir = directory( parag );
|
|
|
|
|
|
|
|
if ( fName.startsWith( "/" ) )
|
|
|
|
{
|
|
|
|
// absolute path given
|
|
|
|
name = fName;
|
|
|
|
}
|
|
|
|
else if ( !dir.isEmpty() )
|
|
|
|
{
|
|
|
|
name = dir + fName;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// now it gets tricky - no directory navigation messages,
|
|
|
|
// no absolute path - let's guess.
|
|
|
|
name = fName;
|
|
|
|
if ( !checkFileExists( m_lastBuildDir + "/" + fName, name) &&
|
|
|
|
!checkFileExists( m_part->project()->projectDirectory() + "/" + fName, name ) &&
|
|
|
|
!checkFileExists( m_part->project()->projectDirectory() + "/" + m_part->project()->activeDirectory() + "/" + fName, name ) &&
|
|
|
|
!checkFileExists( m_part->project()->buildDirectory() + "/" + fName, name ) )
|
|
|
|
specialCheck(fName, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
kdDebug(9004) << "Opening file: " << name << endl;
|
|
|
|
|
|
|
|
// GNU make resolves symlinks. if "name" is a real path to a file the
|
|
|
|
// project know by symlink path, we need to return the symlink path
|
|
|
|
// TQStringList projectFiles = m_part->project()->allFiles();
|
|
|
|
TQStringList projectFiles = m_part->project()->symlinkProjectFiles();
|
|
|
|
TQStringList::iterator it = projectFiles.begin();
|
|
|
|
while ( it != projectFiles.end() )
|
|
|
|
{
|
|
|
|
TQString file = m_part->project()->projectDirectory() + "/" + *it;
|
|
|
|
if ( name == URLUtil::canonicalPath( file ) )
|
|
|
|
{
|
|
|
|
kdDebug(9004) << "Found file in project - " << file << " == " << name << endl;
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
|
|
|
|
// this should only happen if the file is not in the project
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::searchItem(int parag)
|
|
|
|
{
|
|
|
|
ErrorItem* item = dynamic_cast<ErrorItem*>( m_paragraphToItem[parag] );
|
|
|
|
if ( item )
|
|
|
|
{
|
|
|
|
// open the file
|
|
|
|
kdDebug(9004) << "Opening file: " << guessFileName(item->fileName, parag) << endl;
|
|
|
|
m_part->partController()->editDocument(KURL( guessFileName(item->fileName, parag) ), item->lineNum);
|
|
|
|
m_part->mainWindow()->statusBar()->message( item->m_error, 10000 );
|
|
|
|
m_lastErrorSelected = parag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::insertStdoutLine( const TQCString& line )
|
|
|
|
{
|
|
|
|
TQString sline;
|
|
|
|
bool forceCLocale = KConfigGroup( kapp->config(), "MakeOutputWidget" ).readBoolEntry( "ForceCLocale", true );
|
|
|
|
|
|
|
|
if( forceCLocale )
|
|
|
|
sline = TQString::fromAscii( stdoutbuf+line );
|
|
|
|
else
|
|
|
|
sline = TQString::fromLocal8Bit( stdoutbuf+line );
|
|
|
|
|
|
|
|
if ( !appendToLastLine( sline ) )
|
|
|
|
m_directoryStatusFilter.processLine( sline );
|
|
|
|
stdoutbuf.truncate(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::insertStderrLine( const TQCString& line )
|
|
|
|
{
|
|
|
|
TQString sline;
|
|
|
|
bool forceCLocale = KConfigGroup( kapp->config(), "MakeOutputWidget" ).readBoolEntry( "ForceCLocale", true );
|
|
|
|
|
|
|
|
if( forceCLocale ) {
|
|
|
|
sline = TQString( stderrbuf+line );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sline = TQString::fromLocal8Bit( stderrbuf+line );
|
|
|
|
|
|
|
|
if ( !appendToLastLine( sline ) )
|
|
|
|
m_errorFilter.processLine( sline );
|
|
|
|
stderrbuf.truncate(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::slotProcessExited(KProcess *)
|
|
|
|
{
|
|
|
|
procLineMaker->flush();
|
|
|
|
if( !stderrbuf.isEmpty() )
|
|
|
|
insertStderrLine("");
|
|
|
|
if( !stdoutbuf.isEmpty() )
|
|
|
|
insertStdoutLine("");
|
|
|
|
if (childproc->normalExit())
|
|
|
|
{
|
|
|
|
if (childproc->exitStatus())
|
|
|
|
{
|
|
|
|
KNotifyClient::event( tqtopLevelWidget()->winId(), "ProcessError", i18n("The process has finished with errors"));
|
|
|
|
emit m_part->commandFailed(currentCommand);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
KNotifyClient::event( tqtopLevelWidget()->winId(), "ProcessSuccess", i18n("The process has finished successfully"));
|
|
|
|
emit m_part->commandFinished(currentCommand);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MakeItem* item = new ExitStatusItem( childproc->normalExit(), childproc->exitStatus() );
|
|
|
|
insertItem( item );
|
|
|
|
displayPendingItem();
|
|
|
|
|
|
|
|
m_part->mainWindow()->statusBar()->message( TQString("%1: %2").tqarg(currentCommand).tqarg(item->m_text), 3000);
|
|
|
|
m_part->core()->running(m_part, false);
|
|
|
|
|
|
|
|
// Defensive programming: We emit this with a single shot timer so that we go once again
|
|
|
|
// through the event loop. After that, we can be sure that the process is really finished
|
|
|
|
// and its KProcess object can be reused.
|
|
|
|
if (childproc->normalExit() && !childproc->exitStatus())
|
|
|
|
{
|
|
|
|
TQTimer::singleShot(0, this, TQT_SLOT(startNextJob()));
|
|
|
|
// if (commandList.isEmpty())
|
|
|
|
// The last command on the list was successful so restore the
|
|
|
|
// output view to what it had before the compilation process started
|
|
|
|
// m_part->mainWindow()->restoreOutputViewTab();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
commandList.clear();
|
|
|
|
dirList.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::slotEnteredDirectory( EnteringDirectoryItem* item )
|
|
|
|
{
|
|
|
|
// kdDebug(9004) << "Entering dir: " << item->directory << endl;
|
|
|
|
TQString* dir = new TQString( item->directory );
|
|
|
|
dirstack.push( dir );
|
|
|
|
insertItem( item );
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::slotExitedDirectory( ExitingDirectoryItem* item )
|
|
|
|
{
|
|
|
|
TQString eDir = item->directory;
|
|
|
|
// kdDebug(9004) << "Leaving dir: " << eDir << endl;
|
|
|
|
TQString *dir = dirstack.pop();
|
|
|
|
if (!dir)
|
|
|
|
{
|
|
|
|
kdWarning(9004) << "Left more directories than entered: " << eDir;
|
|
|
|
}
|
|
|
|
else if (dir->compare(eDir) != 0)
|
|
|
|
{
|
|
|
|
kdWarning(9004) << "Expected directory: \"" << *dir << "\" but got \"" << eDir << "\"" << endl;
|
|
|
|
}
|
|
|
|
insertItem( item );
|
|
|
|
if (dirstack.top())
|
|
|
|
insertItem( new EnteringDirectoryItem( *dirstack.top(), "" ) );
|
|
|
|
delete dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::displayPendingItem()
|
|
|
|
{
|
|
|
|
if (!m_pendingItem) return;
|
|
|
|
// this handles the case of ImmDisplay|Append
|
|
|
|
// We call displayPendingItem once in insertItem
|
|
|
|
// and the appends are handled directly in
|
|
|
|
// appendToLastLine
|
|
|
|
if (!m_items.empty()
|
|
|
|
&& m_items.last() == m_pendingItem) return;
|
|
|
|
|
|
|
|
m_items.push_back(m_pendingItem);
|
|
|
|
|
|
|
|
if ( m_bCompiling && !m_pendingItem->visible( m_compilerOutputLevel ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
SelectionPreserver preserveSelection( *this, !m_vertScrolling && !m_horizScrolling );
|
|
|
|
m_paragraphToItem.insert( m_paragraphs++, m_pendingItem );
|
|
|
|
append( m_pendingItem->formattedText( m_compilerOutputLevel, brightBg() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MakeWidget::appendToLastLine( const TQString& text )
|
|
|
|
{
|
|
|
|
if ( !m_pendingItem ) return false;
|
|
|
|
if ( !m_pendingItem->append( text ) )
|
|
|
|
{
|
|
|
|
displayPendingItem();
|
|
|
|
m_pendingItem = 0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mode = m_pendingItem -> displayMode();
|
|
|
|
if ((mode & MakeItem::Append) && (mode & MakeItem::ImmDisplay))
|
|
|
|
{
|
|
|
|
removeParagraph(paragraphs() - 1);
|
|
|
|
SelectionPreserver preserveSelection( *this, !m_vertScrolling && !m_horizScrolling );
|
|
|
|
append( m_pendingItem->formattedText( m_compilerOutputLevel, brightBg() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::insertItem( MakeItem* new_item )
|
|
|
|
{
|
|
|
|
displayPendingItem();
|
|
|
|
m_pendingItem = new_item;
|
|
|
|
|
|
|
|
if (!new_item) return;
|
|
|
|
|
|
|
|
int mode = new_item -> displayMode();
|
|
|
|
if (mode & MakeItem::ImmDisplay)
|
|
|
|
{
|
|
|
|
displayPendingItem();
|
|
|
|
if (!(mode & MakeItem::Append))
|
|
|
|
m_pendingItem = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MakeWidget::brightBg()
|
|
|
|
{
|
|
|
|
int h,s,v;
|
|
|
|
TQColor(paletteBackgroundColor()).hsv( &h, &s, &v );
|
|
|
|
return (v > 127);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPopupMenu* MakeWidget::createPopupMenu( const TQPoint& pos )
|
|
|
|
{
|
|
|
|
TQPopupMenu* pMenu = TQTextEdit::createPopupMenu(pos);
|
|
|
|
pMenu->setCheckable(true);
|
|
|
|
|
|
|
|
pMenu->insertSeparator();
|
|
|
|
int id = pMenu->insertItem(i18n("Line Wrapping"), this, TQT_SLOT(toggleLineWrapping()) );
|
|
|
|
pMenu->setItemChecked(id, m_bLineWrapping);
|
|
|
|
pMenu->tqsetWhatsThis(id, i18n("<b>Line wrapping</b><p>Enables or disables wrapping of command lines displayed."));
|
|
|
|
|
|
|
|
pMenu->insertSeparator();
|
|
|
|
id = pMenu->insertItem(i18n("Very Short Compiler Output"), this, TQT_SLOT(slotVeryShortCompilerOutput()) );
|
|
|
|
pMenu->tqsetWhatsThis(id, i18n("<b>Very short compiler output</b><p>Displays only warnings, errors and the file names which are compiled."));
|
|
|
|
pMenu->setItemChecked(id, m_compilerOutputLevel == eVeryShort);
|
|
|
|
id = pMenu->insertItem(i18n("Short Compiler Output"), this, TQT_SLOT(slotShortCompilerOutput()) );
|
|
|
|
pMenu->tqsetWhatsThis(id, i18n("<b>Short compiler output</b><p>Suppresses all the compiler flags and formats to something readable."));
|
|
|
|
pMenu->setItemChecked(id, m_compilerOutputLevel == eShort);
|
|
|
|
id = pMenu->insertItem(i18n("Full Compiler Output"), this, TQT_SLOT(slotFullCompilerOutput()) );
|
|
|
|
pMenu->tqsetWhatsThis(id, i18n("<b>Full compiler output</b><p>Displays unmodified compiler output."));
|
|
|
|
pMenu->setItemChecked(id, m_compilerOutputLevel == eFull);
|
|
|
|
|
|
|
|
pMenu->insertSeparator();
|
|
|
|
id = pMenu->insertItem(i18n("Show Directory Navigation Messages"), this, TQT_SLOT(toggleShowDirNavigMessages()));
|
|
|
|
pMenu->tqsetWhatsThis(id, i18n("<b>Show directory navigation messages</b><p>Shows <b>cd</b> commands that are executed while building."));
|
|
|
|
pMenu->setItemChecked(id, DirectoryItem::getShowDirectoryMessages());
|
|
|
|
|
|
|
|
return pMenu;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::toggleLineWrapping()
|
|
|
|
{
|
|
|
|
m_bLineWrapping = !m_bLineWrapping;
|
|
|
|
KConfig *pConfig = kapp->config();
|
|
|
|
pConfig->setGroup("MakeOutputView");
|
|
|
|
pConfig->writeEntry("LineWrapping", m_bLineWrapping);
|
|
|
|
pConfig->sync();
|
|
|
|
if (m_bLineWrapping) {
|
|
|
|
setWordWrap(WidgetWidth);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setWordWrap(NoWrap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::refill()
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
m_paragraphToItem.clear();
|
|
|
|
m_paragraphs = 0;
|
|
|
|
for( uint i = 0; i < m_items.size(); i++ )
|
|
|
|
{
|
|
|
|
if ( m_bCompiling && !m_items[i]->visible( m_compilerOutputLevel ) )
|
|
|
|
continue;
|
|
|
|
m_paragraphToItem.insert( m_paragraphs++, m_items[i] );
|
|
|
|
append( m_items[i]->formattedText( m_compilerOutputLevel, brightBg() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::slotVeryShortCompilerOutput() { setTextFormat( TQt::RichText ); setCompilerOutputLevel(eVeryShort); }
|
|
|
|
void MakeWidget::slotShortCompilerOutput() { setTextFormat( TQt::RichText ); setCompilerOutputLevel(eShort); }
|
|
|
|
void MakeWidget::slotFullCompilerOutput() { setTextFormat( TQt::RichText ); setCompilerOutputLevel(eFull); }
|
|
|
|
|
|
|
|
void MakeWidget::setCompilerOutputLevel(EOutputLevel level)
|
|
|
|
{
|
|
|
|
m_compilerOutputLevel = level;
|
|
|
|
KConfig *pConfig = kapp->config();
|
|
|
|
pConfig->setGroup("MakeOutputView");
|
|
|
|
pConfig->writeEntry("CompilerOutputLevel", (int) level);
|
|
|
|
pConfig->sync();
|
|
|
|
refill();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::toggleShowDirNavigMessages()
|
|
|
|
{
|
|
|
|
DirectoryItem::setShowDirectoryMessages( !DirectoryItem::getShowDirectoryMessages() );
|
|
|
|
KConfig *pConfig = kapp->config();
|
|
|
|
pConfig->setGroup("MakeOutputView");
|
|
|
|
pConfig->writeEntry("ShowDirNavigMsg", DirectoryItem::getShowDirectoryMessages());
|
|
|
|
pConfig->sync();
|
|
|
|
refill();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::updateSettingsFromConfig()
|
|
|
|
{
|
|
|
|
KConfig *pConfig = kapp->config();
|
|
|
|
pConfig->setGroup("General Options");
|
|
|
|
TQFont outputFont = pConfig->readFontEntry("OutputViewFont");
|
|
|
|
setFont(outputFont);
|
|
|
|
pConfig->setGroup("MakeOutputView");
|
|
|
|
m_bLineWrapping = pConfig->readBoolEntry("LineWrapping", true);
|
|
|
|
m_compilerOutputLevel = (EOutputLevel) pConfig->readNumEntry("CompilerOutputLevel", (int) eShort);
|
|
|
|
DirectoryItem::setShowDirectoryMessages( pConfig->readBoolEntry("ShowDirNavigMsg", false) );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MakeWidget::scanErrorForward( int parag )
|
|
|
|
{
|
|
|
|
for ( int it = parag + 1;
|
|
|
|
it < (int)m_items.count();
|
|
|
|
++it )
|
|
|
|
{
|
|
|
|
ErrorItem* item = dynamic_cast<ErrorItem*>( m_paragraphToItem[it] );
|
|
|
|
if ( !item )
|
|
|
|
continue;
|
|
|
|
if( item->m_isWarning )
|
|
|
|
continue;
|
|
|
|
parag = it;
|
|
|
|
document()->removeSelection(0);
|
|
|
|
setSelection(parag, 0, parag+1, 0, 0);
|
|
|
|
setCursorPosition(parag, 0);
|
|
|
|
ensureCursorVisible();
|
|
|
|
searchItem( it );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MakeWidget::scanErrorBackward( int parag )
|
|
|
|
{
|
|
|
|
for ( int it = parag - 1; it >= 0; --it)
|
|
|
|
{
|
|
|
|
ErrorItem* item = dynamic_cast<ErrorItem*>( m_paragraphToItem[it] );
|
|
|
|
if ( !item )
|
|
|
|
continue;
|
|
|
|
if( item->m_isWarning )
|
|
|
|
continue;
|
|
|
|
parag = it;
|
|
|
|
document()->removeSelection(0);
|
|
|
|
setSelection(parag, 0, parag+1, 0, 0);
|
|
|
|
setCursorPosition(parag, 0);
|
|
|
|
ensureCursorVisible();
|
|
|
|
searchItem( it );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::storePartialStderrLine(const TQCString & line)
|
|
|
|
{
|
|
|
|
stderrbuf += line;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeWidget::storePartialStdoutLine(const TQCString & line)
|
|
|
|
{
|
|
|
|
stdoutbuf += line;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "makewidget.moc"
|