|
|
|
/*
|
|
|
|
cwbuglistcontainer.cpp - Container for the bug list
|
|
|
|
|
|
|
|
copyright : (c) 2001 by Martijn Klingens
|
|
|
|
email : klingens@kde.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 <tqpushbutton.h>
|
|
|
|
#include <tqlabel.h>
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqwidgetstack.h>
|
|
|
|
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <klistview.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kdialog.h>
|
|
|
|
#if KDE_IS_VERSION( 3, 2, 90 )
|
|
|
|
#include <klistviewsearchline.h>
|
|
|
|
#endif
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
#include "bugsystem.h"
|
|
|
|
|
|
|
|
#include "cwloadingwidget.h"
|
|
|
|
#include "buglvi.h"
|
|
|
|
#include "kbbprefs.h"
|
|
|
|
#include "kfind.h"
|
|
|
|
|
|
|
|
#include "cwbuglistcontainer.h"
|
|
|
|
#include <kfinddialog.h>
|
|
|
|
|
|
|
|
using namespace KBugBusterMainWindow;
|
|
|
|
|
|
|
|
CWBugListContainer::CWBugListContainer( TQWidget *tqparent , const char * name )
|
|
|
|
: TQWidget( tqparent, name ), m_tqfind(0), m_findItem(0)
|
|
|
|
{
|
|
|
|
TQBoxLayout *topLayout = new TQVBoxLayout( this );
|
|
|
|
topLayout->setSpacing( KDialog::spacingHint() );
|
|
|
|
topLayout->setMargin( KDialog::marginHint() );
|
|
|
|
|
|
|
|
m_listLabel = new TQLabel( this );
|
|
|
|
topLayout->addWidget( m_listLabel );
|
|
|
|
topLayout->setStretchFactor( m_listLabel, 0 );
|
|
|
|
|
|
|
|
TQFont f = m_listLabel->font();
|
|
|
|
f.setBold( true );
|
|
|
|
m_listLabel->setFont( f );
|
|
|
|
|
|
|
|
m_listStack = new TQWidgetStack( this );
|
|
|
|
|
|
|
|
// Create Outstanding Bugs listview
|
|
|
|
m_listBugs = new KListView( m_listStack );
|
|
|
|
|
|
|
|
topLayout->addWidget( new KListViewSearchLineWidget( m_listBugs, this ) );
|
|
|
|
topLayout->addWidget( m_listStack );
|
|
|
|
topLayout->setStretchFactor( m_listStack, 1 );
|
|
|
|
|
|
|
|
m_listBugs->addColumn( i18n( "Number" ) );
|
|
|
|
m_listBugs->addColumn( i18n( "Age" ) );
|
|
|
|
m_listBugs->addColumn( i18n( "Title" ), 500 ); // so that the widthmode isn't "Maximum"
|
|
|
|
m_listBugs->addColumn( i18n( "tqStatus" ) );
|
|
|
|
m_listBugs->addColumn( i18n( "Severity" ) );
|
|
|
|
m_listBugs->addColumn( i18n( "Sender" ), 150 ); // idem. hardcoded widths suck a bit, but...
|
|
|
|
m_listBugs->setAllColumnsShowFocus( true );
|
|
|
|
m_listBugs->setColumnAlignment( 0, AlignRight );
|
|
|
|
m_listBugs->setSorting( 0, false );
|
|
|
|
m_listBugs->setShowSortIndicator( true );
|
|
|
|
m_listBugs->setSelectionMode( TQListView::Extended ); // needed for merging bugs
|
|
|
|
|
|
|
|
m_listBugs->restoreLayout( KBBPrefs::instance()->config(), "BugListLayout" );
|
|
|
|
|
|
|
|
connect( m_listBugs, TQT_SIGNAL( executed( TQListViewItem * ) ),
|
|
|
|
TQT_SLOT( execute( TQListViewItem * ) ) );
|
|
|
|
connect( m_listBugs, TQT_SIGNAL( returnPressed( TQListViewItem * ) ),
|
|
|
|
TQT_SLOT( execute( TQListViewItem * ) ) );
|
|
|
|
connect( m_listBugs, TQT_SIGNAL( currentChanged( TQListViewItem * ) ),
|
|
|
|
TQT_SLOT( changeCurrent( TQListViewItem * ) ) );
|
|
|
|
|
|
|
|
// Fill WidgetStack in Outstanding Bugs pane
|
|
|
|
m_listLoading = new CWLoadingWidget( CWLoadingWidget::TopFrame,
|
|
|
|
m_listStack );
|
|
|
|
connect( m_listLoading, TQT_SIGNAL( clicked() ), TQT_SIGNAL( searchPackage() ) );
|
|
|
|
|
|
|
|
m_listStack->addWidget( m_listBugs, 0 );
|
|
|
|
m_listStack->addWidget( m_listLoading, 1 );
|
|
|
|
|
|
|
|
setNoList();
|
|
|
|
|
|
|
|
connect( BugSystem::self(), TQT_SIGNAL( bugListLoading( const Package &, const TQString & ) ),
|
|
|
|
TQT_SLOT( setLoading( const Package &, const TQString & ) ) );
|
|
|
|
connect( BugSystem::self(), TQT_SIGNAL( bugListLoading( const TQString & ) ),
|
|
|
|
TQT_SLOT( setLoading( const TQString & ) ) );
|
|
|
|
connect( BugSystem::self(), TQT_SIGNAL( bugListCacheMiss( const Package & ) ),
|
|
|
|
TQT_SLOT( setCacheMiss( const Package & ) ) );
|
|
|
|
connect( BugSystem::self(), TQT_SIGNAL( bugListCacheMiss( const TQString & ) ),
|
|
|
|
TQT_SLOT( setCacheMiss( const TQString & ) ) );
|
|
|
|
connect( BugSystem::self(), TQT_SIGNAL( commandQueued( BugCommand * ) ),
|
|
|
|
TQT_SLOT( markBugCommand( BugCommand * ) ) );
|
|
|
|
connect( BugSystem::self(), TQT_SIGNAL( commandCanceled( const TQString & ) ),
|
|
|
|
TQT_SLOT( clearCommand( const TQString & ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
CWBugListContainer::~CWBugListContainer()
|
|
|
|
{
|
|
|
|
m_listBugs->saveLayout( KBBPrefs::instance()->config(), "BugListLayout" );
|
|
|
|
KBBPrefs::instance()->writeConfig();
|
|
|
|
delete m_tqfind;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWBugListContainer::setBugList( const TQString &label, const Bug::List &bugs )
|
|
|
|
{
|
|
|
|
// List pane is invisible by default, make visible
|
|
|
|
show();
|
|
|
|
|
|
|
|
m_listBugs->clear();
|
|
|
|
emit resetProgressBar();
|
|
|
|
bool showClosed = KBBPrefs::instance()->mShowClosedBugs;
|
|
|
|
bool showWishes = KBBPrefs::instance()->mShowWishes;
|
|
|
|
uint noBugs = 0;
|
|
|
|
uint noWishes = 0;
|
|
|
|
|
|
|
|
for ( Bug::List::ConstIterator it = bugs.begin(); it != bugs.end(); ++it )
|
|
|
|
{
|
|
|
|
if ( ( *it ).status() != Bug::Closed || showClosed )
|
|
|
|
{
|
|
|
|
if ( ( *it ).severity() != Bug::Wishlist || showWishes )
|
|
|
|
new BugLVI( m_listBugs, *it );
|
|
|
|
|
|
|
|
if ( ( *it ).severity() != Bug::Wishlist )
|
|
|
|
noBugs++;
|
|
|
|
else
|
|
|
|
noWishes++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_listLabel->setText( i18n( "%1 (%2 bugs, %3 wishes)" ).tqarg( label ).tqarg( noBugs ).tqarg( noWishes ) );
|
|
|
|
m_listStack->raiseWidget( 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWBugListContainer::setBugList( const Package &package, const TQString &component, const Bug::List &bugs )
|
|
|
|
{
|
|
|
|
TQString listLabel;
|
|
|
|
if ( component.isEmpty() )
|
|
|
|
{
|
|
|
|
if ( package.components().count() > 1 )
|
|
|
|
listLabel = i18n( "Product '%1', all components" ).tqarg( package.name() );
|
|
|
|
else
|
|
|
|
listLabel = i18n( "Product '%1'" ).tqarg( package.name() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
listLabel = i18n( "Product '%1', component '%2'" ).tqarg( package.name(), component );
|
|
|
|
}
|
|
|
|
|
|
|
|
setBugList( listLabel, bugs );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWBugListContainer::execute( TQListViewItem *lvi )
|
|
|
|
{
|
|
|
|
BugLVI *item = dynamic_cast<BugLVI *>( lvi );
|
|
|
|
if( !item )
|
|
|
|
{
|
|
|
|
kdWarning() << "CWBugListContainer::execute() Selected bug "
|
|
|
|
<< lvi->text( 0 )
|
|
|
|
<< " is not a BugLVI! Ignoring event." << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit executed( item->bug() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWBugListContainer::changeCurrent( TQListViewItem *lvi )
|
|
|
|
{
|
|
|
|
if( !lvi ) {
|
|
|
|
emit currentChanged( Bug() );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BugLVI *item = dynamic_cast<BugLVI *>( lvi );
|
|
|
|
if( !item )
|
|
|
|
{
|
|
|
|
kdWarning() << "CWBugListContainer::changeCurrent() Selected bug "
|
|
|
|
<< lvi->text( 0 )
|
|
|
|
<< " is not a BugLVI! Ignoring event." << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit currentChanged( item->bug() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWBugListContainer::setNoList()
|
|
|
|
{
|
|
|
|
m_listLabel->setText( i18n("Outstanding Bugs") );
|
|
|
|
m_listLoading->setText( i18n( "Click here to select a product" ) );
|
|
|
|
m_listStack->raiseWidget( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWBugListContainer::setLoading( const Package &package, const TQString &component )
|
|
|
|
{
|
|
|
|
if ( component.isEmpty() )
|
|
|
|
setLoading( i18n( "Retrieving List of Outstanding Bugs for Product '%1'..." ).tqarg( package.name() ) );
|
|
|
|
else
|
|
|
|
setLoading( i18n( "Retrieving List of Outstanding Bugs for Product '%1' (Component %2)..." ).tqarg( package.name(), component ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWBugListContainer::setLoading( const TQString &label )
|
|
|
|
{
|
|
|
|
m_listLoading->setText( label );
|
|
|
|
m_listStack->raiseWidget( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWBugListContainer::setCacheMiss( const Package &package )
|
|
|
|
{
|
|
|
|
setCacheMiss( i18n( "Package '%1'" ).tqarg( package.name() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWBugListContainer::setCacheMiss( const TQString &label )
|
|
|
|
{
|
|
|
|
m_listLoading->setText( i18n( "%1 is not available offline." ).tqarg( label ) );
|
|
|
|
m_listStack->raiseWidget( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWBugListContainer::markBugCommand( BugCommand *cmd )
|
|
|
|
{
|
|
|
|
BugLVI *item = (BugLVI *)m_listBugs->firstChild();
|
|
|
|
while( item ) {
|
|
|
|
if ( item->bug().number() == cmd->bug().number() ) {
|
|
|
|
item->setCommandState( BugCommand::Queued );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
item = (BugLVI *)item->nextSibling();
|
|
|
|
}
|
|
|
|
m_listBugs->triggerUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWBugListContainer::clearCommand( const TQString &bug )
|
|
|
|
{
|
|
|
|
BugLVI *item = (BugLVI *)m_listBugs->firstChild();
|
|
|
|
while( item ) {
|
|
|
|
if ( item->bug().number() == bug ) {
|
|
|
|
item->setCommandState( BugCommand::None );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
item = (BugLVI *)item->nextSibling();
|
|
|
|
}
|
|
|
|
m_listBugs->triggerUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWBugListContainer::searchBugByTitle( int options, const TQString& pattern )
|
|
|
|
{
|
|
|
|
m_tqfind = new KFind( pattern, options, this );
|
|
|
|
// Connect signals to code which handles highlighting
|
|
|
|
// of found text.
|
|
|
|
connect(m_tqfind, TQT_SIGNAL( highlight( const TQString &, int, int ) ),
|
|
|
|
this, TQT_SLOT( searchHighlight( const TQString &, int, int ) ) );
|
|
|
|
connect(m_tqfind, TQT_SIGNAL( findNext() ), this, TQT_SLOT( slotFindNext() ) );
|
|
|
|
|
|
|
|
m_findItem = (BugLVI *)m_listBugs->firstChild();
|
|
|
|
if ( options & KFindDialog::FromCursor && m_listBugs->currentItem() )
|
|
|
|
m_findItem = (BugLVI *)m_listBugs->currentItem();
|
|
|
|
|
|
|
|
slotFindNext();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note: if a 'find next' action is added, then one should also ensure
|
|
|
|
// that m_findItem never becomes dangling (i.e. clear it when clearing the listview).
|
|
|
|
void CWBugListContainer::slotFindNext()
|
|
|
|
{
|
|
|
|
KFind::Result res = KFind::NoMatch;
|
|
|
|
while( res == KFind::NoMatch && m_findItem ) {
|
|
|
|
|
|
|
|
if ( m_tqfind->needData() )
|
|
|
|
m_tqfind->setData( m_findItem->text(2) );
|
|
|
|
|
|
|
|
// Let KFind inspect the text fragment, and display a dialog if a match is found
|
|
|
|
res = m_tqfind->find();
|
|
|
|
|
|
|
|
if ( res == KFind::NoMatch ) {
|
|
|
|
if ( m_tqfind->options() & KFindDialog::FindBackwards )
|
|
|
|
m_findItem = (BugLVI *)m_findItem->itemAbove();
|
|
|
|
else
|
|
|
|
m_findItem = (BugLVI *)m_findItem->itemBelow();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( res == KFind::NoMatch ) // i.e. at end
|
|
|
|
if ( m_tqfind->shouldRestart() ) {
|
|
|
|
m_findItem = (BugLVI *)m_listBugs->firstChild();
|
|
|
|
slotFindNext();
|
|
|
|
} else {
|
|
|
|
delete m_tqfind;
|
|
|
|
m_tqfind = 0L;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWBugListContainer::searchHighlight( const TQString &, int, int )
|
|
|
|
{
|
|
|
|
if ( m_findItem ) {
|
|
|
|
m_listBugs->clearSelection();
|
|
|
|
m_listBugs->setSelected( m_findItem, true );
|
|
|
|
m_listBugs->ensureItemVisible( m_findItem );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList CWBugListContainer::selectedBugs() const
|
|
|
|
{
|
|
|
|
TQStringList lst;
|
|
|
|
BugLVI *item = (BugLVI *)m_listBugs->firstChild();
|
|
|
|
while( item ) {
|
|
|
|
if ( item->isSelected() )
|
|
|
|
lst.append( item->bug().number() );
|
|
|
|
item = (BugLVI *)item->nextSibling();
|
|
|
|
}
|
|
|
|
return lst;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "cwbuglistcontainer.moc"
|
|
|
|
|
|
|
|
/* vim: set et ts=4 sw=4 softtabstop=4: */
|