|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 1999-2001 by Bernd Gehrmann *
|
|
|
|
* bernd@kdevelop.org *
|
|
|
|
* *
|
|
|
|
* Copyright (C) 2003 by Hamish Rodda *
|
|
|
|
* meddie@yoyo.its.monash.edu.au *
|
|
|
|
* *
|
|
|
|
* 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 "appoutputwidget.h"
|
|
|
|
|
|
|
|
#include <tqregexp.h>
|
|
|
|
#include <tqbuttongroup.h>
|
|
|
|
#include <tqcheckbox.h>
|
|
|
|
#include <tqradiobutton.h>
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqtextstream.h>
|
|
|
|
#include <tqclipboard.h>
|
|
|
|
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kstatusbar.h>
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kconfig.h>
|
|
|
|
#include <kpopupmenu.h>
|
|
|
|
#include <klineedit.h>
|
|
|
|
#include <kfiledialog.h>
|
|
|
|
|
|
|
|
#include "appoutputviewpart.h"
|
|
|
|
#include "filterdlg.h"
|
|
|
|
#include "kdevpartcontroller.h"
|
|
|
|
#include "kdevmainwindow.h"
|
|
|
|
#include "kdevproject.h"
|
|
|
|
|
|
|
|
AppOutputWidget::AppOutputWidget(AppOutputViewPart* part)
|
|
|
|
: ProcessWidget(0, "app output widget"), m_part(part)
|
|
|
|
{
|
|
|
|
connect(this, TQT_SIGNAL(executed(TQListBoxItem*)), TQT_SLOT(slotRowSelected(TQListBoxItem*)));
|
|
|
|
connect(this, TQT_SIGNAL(rightButtonClicked( TQListBoxItem *, const TQPoint & )),
|
|
|
|
TQT_SLOT(slotContextMenu( TQListBoxItem *, const TQPoint & )));
|
|
|
|
KConfig *config = kapp->config();
|
|
|
|
config->setGroup("General Options");
|
|
|
|
setFont(config->readFontEntry("OutputViewFont"));
|
|
|
|
setSelectionMode(TQListBox::Extended);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppOutputWidget::clearViewAndContents()
|
|
|
|
{
|
|
|
|
m_contentList.clear();
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
AppOutputWidget::~AppOutputWidget()
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
void AppOutputWidget::childFinished(bool normal, int status)
|
|
|
|
{
|
|
|
|
if( !stdoutbuf.isEmpty() )
|
|
|
|
insertStdoutLine("");
|
|
|
|
if( !stderrbuf.isEmpty() )
|
|
|
|
insertStderrLine("");
|
|
|
|
|
|
|
|
ProcessWidget::childFinished(normal, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AppOutputWidget::slotRowSelected(TQListBoxItem* row)
|
|
|
|
{
|
|
|
|
static TQRegExp assertMatch("ASSERT: \\\"([^\\\"]+)\\\" in ([^\\( ]+) \\(([\\d]+)\\)");
|
|
|
|
static TQRegExp lineInfoMatch("\\[([^:]+):([\\d]+)\\]");
|
|
|
|
static TQRegExp rubyErrorMatch("([^:\\s]+\\.rb):([\\d]+):?.*$");
|
|
|
|
|
|
|
|
if (row) {
|
|
|
|
if (assertMatch.exactMatch(row->text())) {
|
|
|
|
m_part->partController()->editDocument(KURL( assertMatch.cap(2) ), assertMatch.cap(3).toInt() - 1);
|
|
|
|
m_part->mainWindow()->statusBar()->message(i18n("Assertion failed: %1").tqarg(assertMatch.cap(1)), 10000);
|
|
|
|
m_part->mainWindow()->lowerView(this);
|
|
|
|
|
|
|
|
} else if (lineInfoMatch.search(row->text()) != -1) {
|
|
|
|
m_part->partController()->editDocument(KURL( lineInfoMatch.cap(1) ), lineInfoMatch.cap(2).toInt() - 1);
|
|
|
|
m_part->mainWindow()->statusBar()->message(row->text(), 10000);
|
|
|
|
m_part->mainWindow()->lowerView(this);
|
|
|
|
} else if (rubyErrorMatch.search(row->text()) != -1) {
|
|
|
|
TQString file;
|
|
|
|
if (rubyErrorMatch.cap(1).startsWith("/")) {
|
|
|
|
file = rubyErrorMatch.cap(1);
|
|
|
|
} else {
|
|
|
|
file = m_part->project()->projectDirectory() + "/" + rubyErrorMatch.cap(1);
|
|
|
|
}
|
|
|
|
m_part->partController()->editDocument(KURL(rubyErrorMatch.cap(1)), rubyErrorMatch.cap(2).toInt() - 1);
|
|
|
|
m_part->mainWindow()->statusBar()->message(row->text(), 10000);
|
|
|
|
m_part->mainWindow()->lowerView(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AppOutputWidget::insertStdoutLine(const TQCString &line)
|
|
|
|
{
|
|
|
|
// kdDebug(9004) << k_funcinfo << line << endl;
|
|
|
|
|
|
|
|
if ( !m_part->isViewVisible() )
|
|
|
|
{
|
|
|
|
m_part->showView();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString sline;
|
|
|
|
if( !stdoutbuf.isEmpty() )
|
|
|
|
{
|
|
|
|
sline = TQString::fromLocal8Bit( stdoutbuf+line );
|
|
|
|
stdoutbuf.truncate( 0 );
|
|
|
|
}else
|
|
|
|
{
|
|
|
|
sline = TQString::fromLocal8Bit( line );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_contentList.append(TQString("o-")+sline);
|
|
|
|
if ( filterSingleLine( sline ) )
|
|
|
|
{
|
|
|
|
ProcessWidget::insertStdoutLine( sline.local8Bit() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AppOutputWidget::insertStderrLine(const TQCString &line)
|
|
|
|
{
|
|
|
|
// kdDebug(9004) << k_funcinfo << line << endl;
|
|
|
|
|
|
|
|
if ( !m_part->isViewVisible() )
|
|
|
|
{
|
|
|
|
m_part->showView();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQString sline;
|
|
|
|
if( !stderrbuf.isEmpty() )
|
|
|
|
{
|
|
|
|
sline = TQString::fromLocal8Bit( stderrbuf+line );
|
|
|
|
stderrbuf.truncate( 0 );
|
|
|
|
}else
|
|
|
|
{
|
|
|
|
sline = TQString::fromLocal8Bit( line );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_contentList.append(TQString("e-")+sline);
|
|
|
|
if ( filterSingleLine( sline ) )
|
|
|
|
{
|
|
|
|
ProcessWidget::insertStderrLine( sline.local8Bit() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppOutputWidget::editFilter()
|
|
|
|
{
|
|
|
|
FilterDlg dlg( this );
|
|
|
|
dlg.caseSensitive->setChecked( m_filter.m_caseSensitive );
|
|
|
|
dlg.regularExpression->setChecked( m_filter.m_isRegExp );
|
|
|
|
dlg.filterString->setText( m_filter.m_filterString );
|
|
|
|
|
|
|
|
if ( dlg.exec() == TQDialog::Accepted )
|
|
|
|
{
|
|
|
|
m_filter.m_caseSensitive = dlg.caseSensitive->isChecked();
|
|
|
|
m_filter.m_isRegExp = dlg.regularExpression->isChecked();
|
|
|
|
m_filter.m_filterString = dlg.filterString->text();
|
|
|
|
|
|
|
|
m_filter.m_isActive = !m_filter.m_filterString.isEmpty();
|
|
|
|
|
|
|
|
reinsertAndFilter();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
bool AppOutputWidget::filterSingleLine(const TQString & line)
|
|
|
|
{
|
|
|
|
if ( !m_filter.m_isActive ) return true;
|
|
|
|
|
|
|
|
if ( m_filter.m_isRegExp )
|
|
|
|
{
|
|
|
|
return ( line.find( TQRegExp( m_filter.m_filterString, m_filter.m_caseSensitive, false ) ) != -1 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return ( line.find( m_filter.m_filterString, 0, m_filter.m_caseSensitive ) != -1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppOutputWidget::reinsertAndFilter()
|
|
|
|
{
|
|
|
|
//copy the first item from the listbox
|
|
|
|
//if a programm was started, this contains the issued command
|
|
|
|
TQString issuedCommand;
|
|
|
|
if ( count() > 0 )
|
|
|
|
{
|
|
|
|
setTopItem(0);
|
|
|
|
issuedCommand = item(topItem())->text();
|
|
|
|
}
|
|
|
|
|
|
|
|
clear();
|
|
|
|
|
|
|
|
//write back the issued command
|
|
|
|
if ( !issuedCommand.isEmpty() )
|
|
|
|
{
|
|
|
|
insertItem( new ProcessListBoxItem( issuedCommand, ProcessListBoxItem::Diagnostic ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
//grep through the list for items matching the filter...
|
|
|
|
TQStringList strListFound;
|
|
|
|
if ( m_filter.m_isActive )
|
|
|
|
{
|
|
|
|
if ( m_filter.m_isRegExp )
|
|
|
|
{
|
|
|
|
strListFound = m_contentList.grep( TQRegExp(m_filter.m_filterString, m_filter.m_caseSensitive, false ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strListFound = m_contentList.grep( m_filter.m_filterString, m_filter.m_caseSensitive );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strListFound = m_contentList;
|
|
|
|
}
|
|
|
|
|
|
|
|
//... and reinsert the found items into the listbox
|
|
|
|
for ( TQStringList::Iterator it = strListFound.begin(); it != strListFound.end(); ++it )
|
|
|
|
{
|
|
|
|
if ((*it).startsWith("o-"))
|
|
|
|
{
|
|
|
|
(*it).remove(0,2);
|
|
|
|
insertItem(new ProcessListBoxItem(*it, ProcessListBoxItem::Normal));
|
|
|
|
}
|
|
|
|
else if ((*it).startsWith("e-"))
|
|
|
|
{
|
|
|
|
(*it).remove(0,2);
|
|
|
|
insertItem(new ProcessListBoxItem(*it, ProcessListBoxItem::Error));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppOutputWidget::clearFilter()
|
|
|
|
{
|
|
|
|
m_filter.m_isActive = false;
|
|
|
|
reinsertAndFilter();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppOutputWidget::slotContextMenu( TQListBoxItem *, const TQPoint &p )
|
|
|
|
{
|
|
|
|
KPopupMenu popup(this, "filter output");
|
|
|
|
|
|
|
|
int id = popup.insertItem( i18n("Clear output"), this, TQT_SLOT(clearViewAndContents()) );
|
|
|
|
popup.setItemEnabled( id, m_contentList.size() > 0 );
|
|
|
|
|
|
|
|
popup.insertItem( i18n("Copy selected lines"), this, TQT_SLOT(copySelected()) );
|
|
|
|
popup.insertSeparator();
|
|
|
|
|
|
|
|
popup.insertItem( i18n("Save unfiltered"), this, TQT_SLOT(saveAll()) );
|
|
|
|
id = popup.insertItem( i18n("Save filtered output"), this, TQT_SLOT(saveFiltered()) );
|
|
|
|
popup.setItemEnabled( id, m_filter.m_isActive );
|
|
|
|
popup.insertSeparator();
|
|
|
|
|
|
|
|
id = popup.insertItem( i18n("Clear filter"), this, TQT_SLOT(clearFilter()) );
|
|
|
|
popup.setItemEnabled( id, m_filter.m_isActive );
|
|
|
|
|
|
|
|
popup.insertItem( i18n("Edit filter"), this, TQT_SLOT(editFilter() ) );
|
|
|
|
|
|
|
|
popup.insertSeparator();
|
|
|
|
popup.insertItem( i18n("Hide view"), this, TQT_SLOT(hideView()) );
|
|
|
|
|
|
|
|
popup.exec(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppOutputWidget::hideView()
|
|
|
|
{
|
|
|
|
m_part->hideView();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppOutputWidget::saveAll()
|
|
|
|
{
|
|
|
|
saveOutputToFile( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppOutputWidget::saveFiltered()
|
|
|
|
{
|
|
|
|
saveOutputToFile( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppOutputWidget::saveOutputToFile(bool useFilter)
|
|
|
|
{
|
|
|
|
TQString filename = KFileDialog::getSaveFileName();
|
|
|
|
|
|
|
|
if ( filename.isEmpty() ) return;
|
|
|
|
|
|
|
|
TQStringList contents;
|
|
|
|
if ( useFilter && m_filter.m_isActive )
|
|
|
|
{
|
|
|
|
if ( m_filter.m_isRegExp )
|
|
|
|
{
|
|
|
|
contents = m_contentList.grep( TQRegExp(m_filter.m_filterString, m_filter.m_caseSensitive, false ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
contents = m_contentList.grep( m_filter.m_filterString, m_filter.m_caseSensitive );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
contents = m_contentList;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQFile file( filename );
|
|
|
|
if ( file.open( IO_WriteOnly ) )
|
|
|
|
{
|
|
|
|
TQTextStream ostream( &file );
|
|
|
|
TQStringList::ConstIterator it = contents.begin();
|
|
|
|
while( it != contents.end() )
|
|
|
|
{
|
|
|
|
TQString line = *it;
|
|
|
|
if ( line.startsWith("o-") || line.startsWith("e-") )
|
|
|
|
{
|
|
|
|
line.remove( 0, 2 );
|
|
|
|
}
|
|
|
|
ostream << line << endl;
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
file.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppOutputWidget::copySelected()
|
|
|
|
{
|
|
|
|
uint n = count();
|
|
|
|
TQString buffer;
|
|
|
|
for (uint i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
if (isSelected(i))
|
|
|
|
buffer += item(i)->text() + "\n";
|
|
|
|
}
|
|
|
|
kapp->tqclipboard()->setText(buffer, TQClipboard::Clipboard);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppOutputWidget::addPartialStderrLine(const TQCString & line)
|
|
|
|
{
|
|
|
|
stderrbuf += line;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AppOutputWidget::addPartialStdoutLine(const TQCString & line)
|
|
|
|
{
|
|
|
|
stdoutbuf += line;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "appoutputwidget.moc"
|