You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
506 lines
17 KiB
506 lines
17 KiB
/*
|
|
centralwidget.cpp - Central widget for the KBB main window
|
|
|
|
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 <tqsplitter.h>
|
|
#include <tqpushbutton.h>
|
|
#include <tqwidgetstack.h>
|
|
#include <tqlayout.h>
|
|
|
|
#include <kdialog.h>
|
|
#include <kdebug.h>
|
|
#include <kcombobox.h>
|
|
#include <tdelistview.h>
|
|
#include <kinputdialog.h>
|
|
|
|
#include "kbbprefs.h"
|
|
#include "bugsystem.h"
|
|
#include "packagelvi.h"
|
|
#include "buglvi.h"
|
|
#include "msginputdialog.h"
|
|
#include "packageselectdialog.h"
|
|
#include "cwbugdetails.h"
|
|
#include "bugcommand.h"
|
|
#include "severityselectdialog.h"
|
|
#include "cwsearchwidget.h"
|
|
#include "cwbuglistcontainer.h"
|
|
#include "cwbugdetailscontainer.h"
|
|
#include "bugserver.h"
|
|
|
|
#include "centralwidget.h"
|
|
#include <tdefiledialog.h>
|
|
#include <tdemessagebox.h>
|
|
#include "loadallbugsdlg.h"
|
|
|
|
using namespace KBugBusterMainWindow;
|
|
|
|
CentralWidget::CentralWidget( const TQCString &initialPackage,
|
|
const TQCString &initialComponent,
|
|
const TQCString &initialBug, TQWidget *parent,
|
|
const char * name )
|
|
: TQWidget( parent, name )
|
|
{
|
|
// Master layout
|
|
( new TQVBoxLayout( this, 0,
|
|
KDialog::spacingHint() ) )->setAutoAdd( true );
|
|
|
|
// Create TQSplitter children
|
|
m_vertSplitter = new TQSplitter( Qt::Vertical, this );
|
|
m_listPane = new CWBugListContainer( m_vertSplitter );
|
|
m_horSplitter = new TQSplitter( Qt::Horizontal,m_vertSplitter );
|
|
// The search pane isn't used. Should we remove the code?
|
|
m_searchPane = new CWSearchWidget( m_horSplitter );
|
|
m_bugPane = new CWBugDetailsContainer( m_horSplitter );
|
|
|
|
m_searchPane->hide();
|
|
// m_listPane->hide();
|
|
|
|
m_searchPane->setSizePolicy( TQSizePolicy( TQSizePolicy::Minimum,
|
|
TQSizePolicy::Minimum ) );
|
|
m_horSplitter->setResizeMode( m_searchPane, TQSplitter::FollowSizeHint );
|
|
|
|
connect( m_listPane, TQT_SIGNAL( resetProgressBar() ),
|
|
TQT_SIGNAL( resetProgressBar() ) );
|
|
connect( m_bugPane, TQT_SIGNAL( resetProgressBar() ),
|
|
TQT_SIGNAL( resetProgressBar() ) );
|
|
|
|
// Start the proper jobs for loading the package lists
|
|
connect( BugSystem::self(),
|
|
TQT_SIGNAL( packageListAvailable( const Package::List & ) ),
|
|
TQT_SLOT( updatePackageList( const Package::List & ) ) );
|
|
connect( BugSystem::self(),
|
|
TQT_SIGNAL( bugListAvailable( const Package &, const TQString &, const Bug::List & ) ),
|
|
TQT_SLOT( updateBugList( const Package &, const TQString &, const Bug::List & ) ) );
|
|
connect( BugSystem::self(),
|
|
TQT_SIGNAL( bugListAvailable( const TQString &, const Bug::List & ) ),
|
|
TQT_SLOT( updateBugList( const TQString &, const Bug::List & ) ) );
|
|
connect( BugSystem::self(),
|
|
TQT_SIGNAL( bugDetailsAvailable( const Bug &, const BugDetails & ) ),
|
|
TQT_SLOT( updateBugDetails( const Bug &, const BugDetails & ) ) );
|
|
|
|
connect( BugSystem::self(), TQT_SIGNAL( loadingError( const TQString & ) ),
|
|
TQT_SLOT( showLoadingError( const TQString & ) ) );
|
|
|
|
connect( m_bugPane, TQT_SIGNAL( signalCloseBug() ), TQT_SLOT( closeBug() ) );
|
|
connect( m_bugPane, TQT_SIGNAL( signalCloseBugSilently() ), TQT_SLOT( closeBugSilently() ) );
|
|
connect( m_bugPane, TQT_SIGNAL( signalReopenBug() ), TQT_SLOT( reopenBug() ) );
|
|
connect( m_bugPane, TQT_SIGNAL( signalReassignBug() ), TQT_SLOT( reassignBug() ) );
|
|
connect( m_bugPane, TQT_SIGNAL( signalTitleBug() ), TQT_SLOT( titleBug() ) );
|
|
connect( m_bugPane, TQT_SIGNAL( signalSeverityBug() ), TQT_SLOT( severityBug() ) );
|
|
connect( m_bugPane, TQT_SIGNAL( signalReplyBug() ), TQT_SLOT( replyBug() ) );
|
|
connect( m_bugPane, TQT_SIGNAL( signalReplyPrivateBug() ), TQT_SLOT( replyPrivateBug() ) );
|
|
|
|
connect( m_bugPane, TQT_SIGNAL( signalClearCommand() ), TQT_SLOT( clearCommand() ) );
|
|
|
|
// Add the selection slots for the listviews
|
|
connect( m_searchPane->m_searchPackages,
|
|
TQT_SIGNAL( activated( const TQString & ) ),
|
|
TQT_SLOT( slotRetrieveBugList( const TQString & ) ) );
|
|
|
|
connect( m_listPane, TQT_SIGNAL( executed( const Bug & ) ),
|
|
TQT_SLOT( slotRetrieveBugDetails( const Bug & ) ) );
|
|
connect( m_listPane, TQT_SIGNAL( currentChanged( const Bug & ) ),
|
|
TQT_SLOT( slotSetActiveBug( const Bug & ) ) );
|
|
|
|
connect( m_listPane, TQT_SIGNAL( searchPackage() ), TQT_SIGNAL( searchPackage() ) );
|
|
connect( m_bugPane, TQT_SIGNAL( searchBugNumber() ), TQT_SIGNAL( searchBugNumber() ) );
|
|
|
|
m_bLoadingAllBugs = false;
|
|
|
|
initialize( initialPackage, initialComponent, initialBug );
|
|
}
|
|
|
|
CentralWidget::~CentralWidget()
|
|
{
|
|
// kdDebug() << "CentralWidget::~CentralWidget()" << endl;
|
|
}
|
|
|
|
void CentralWidget::initialize( const TQString& p, const TQString &c, const TQString& b )
|
|
{
|
|
// kdDebug() << "CentralWidget::initialize(): package: '" << p
|
|
// << "' bug: '" << b << "'" << endl;
|
|
|
|
BugServerConfig cfg = BugSystem::self()->server()->serverConfig();
|
|
TQString package = p.isEmpty() ? cfg.currentPackage() : p;
|
|
TQString bug = b.isEmpty() ? cfg.currentBug() : b;
|
|
TQString component = c.isEmpty() ? cfg.currentComponent() : c;
|
|
|
|
m_listPane->setNoList();
|
|
m_bugPane->setNoBug();
|
|
|
|
BugSystem::self()->retrievePackageList();
|
|
if ( !package.isEmpty() ) {
|
|
m_currentPackage = BugSystem::self()->package( package );
|
|
m_currentComponent = component;
|
|
BugSystem::self()->retrieveBugList( m_currentPackage, m_currentComponent );
|
|
|
|
if ( !bug.isEmpty() ) {
|
|
m_currentBug = BugSystem::self()->bug( m_currentPackage,
|
|
m_currentComponent, bug );
|
|
BugSystem::self()->retrieveBugDetails( m_currentBug );
|
|
}
|
|
} else {
|
|
if ( !bug.isEmpty() ) {
|
|
// ### bad way to instanciating a bug object! doesn't restore details!
|
|
m_currentBug = Bug::fromNumber( bug ); // bug number specified on cmdline. Is it a problem that we don't have details ?
|
|
BugSystem::self()->retrieveBugDetails( m_currentBug );
|
|
}
|
|
}
|
|
}
|
|
|
|
void CentralWidget::readConfig()
|
|
{
|
|
m_horSplitter->setSizes( KBBPrefs::instance()->mSplitter2 );
|
|
m_vertSplitter->setSizes( KBBPrefs::instance()->mSplitter1 );
|
|
}
|
|
|
|
void CentralWidget::writeConfig()
|
|
{
|
|
#if 0
|
|
kdDebug() << "m_vertSplitter" << endl;
|
|
TQValueList<int> sizes = m_vertSplitter->sizes();
|
|
TQValueList<int>::ConstIterator it;
|
|
for( it = sizes.begin(); it != sizes.end(); ++it ) {
|
|
kdDebug() << " " << (*it) << endl;
|
|
}
|
|
#endif
|
|
|
|
KBBPrefs::instance()->mSplitter1 = m_vertSplitter->sizes();
|
|
KBBPrefs::instance()->mSplitter2 = m_horSplitter->sizes();
|
|
|
|
BugServer *server = BugSystem::self()->server();
|
|
server->serverConfig().setCurrentPackage( m_currentPackage.name() );
|
|
server->serverConfig().setCurrentComponent( m_currentComponent );
|
|
server->serverConfig().setCurrentBug( m_currentBug.number() );
|
|
}
|
|
|
|
void CentralWidget::slotRetrieveBugList( const TQString &package )
|
|
{
|
|
slotRetrieveBugList( package, TQString() );
|
|
}
|
|
|
|
void CentralWidget::slotRetrieveBugList( const TQString &p, const TQString &component )
|
|
{
|
|
if ( p.isEmpty() ) return;
|
|
|
|
Package package = m_packageList[ p ];
|
|
|
|
if ( package.isNull() ) {
|
|
// Invalid package, return
|
|
return;
|
|
}
|
|
|
|
if ( ( package == m_currentPackage ) && ( m_currentComponent == component ) ) {
|
|
return; // Nothing to do
|
|
}
|
|
|
|
m_currentComponent = component;
|
|
m_currentPackage = package;
|
|
|
|
BugSystem::self()->retrieveBugList( m_currentPackage, m_currentComponent );
|
|
}
|
|
|
|
TQString CentralWidget::currentNumber() const
|
|
{
|
|
if( m_currentBug.isNull() )
|
|
return "";
|
|
else
|
|
return m_currentBug.number();
|
|
}
|
|
|
|
TQString CentralWidget::currentTitle() const
|
|
{
|
|
if( m_currentBug.isNull() )
|
|
return "";
|
|
else
|
|
return m_currentBug.title();
|
|
}
|
|
|
|
void CentralWidget::slotRetrieveBugDetails( const Bug &bug )
|
|
{
|
|
if( m_currentBug == bug )
|
|
return; // Nothing to do
|
|
|
|
m_currentBug = bug;
|
|
BugSystem::self()->retrieveBugDetails( m_currentBug );
|
|
}
|
|
|
|
void CentralWidget::slotSetActiveBug( const Bug &bug )
|
|
{
|
|
if( bug.isNull() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( m_activeBug == bug )
|
|
return; // Nothing to do
|
|
|
|
m_activeBug = bug;
|
|
}
|
|
|
|
void CentralWidget::updatePackageList( const Package::List &pkgs )
|
|
{
|
|
// ### needs proper implementation ;-)
|
|
|
|
m_searchPane->m_searchPackages->clear();
|
|
m_searchPane->m_searchPackages->completionObject()->clear();
|
|
// m_bugPane->m_bugDetails->m_bugPackage->clear();
|
|
emit resetProgressBar();
|
|
|
|
Package::List::ConstIterator it = pkgs.begin();
|
|
for ( ; it != pkgs.end(); ++it )
|
|
{
|
|
m_packageList[ ( *it ).name() ] = *it;
|
|
m_searchPane->m_searchPackages->insertItem( ( *it ).name() );
|
|
m_searchPane->m_searchPackages->
|
|
completionObject()->addItem( ( *it ).name() );
|
|
// m_bugPane->m_bugDetails->m_bugPackage->insertItem( ( *it ).name() );
|
|
}
|
|
|
|
/*
|
|
if( m_bugPane->m_bugStack->id(
|
|
m_bugPane->m_bugStack->visibleWidget() ) != 0 )
|
|
{
|
|
m_bugPane->m_bugDetails->m_bugPackage->setCurrentItem( -1 );
|
|
}
|
|
*/
|
|
}
|
|
|
|
void CentralWidget::updateBugList( const Package &pkg, const TQString &component, const Bug::List &bugs )
|
|
{
|
|
m_listPane->setBugList( pkg, component, bugs );
|
|
}
|
|
|
|
void CentralWidget::updateBugList( const TQString &label, const Bug::List &bugs )
|
|
{
|
|
m_listPane->setBugList( label, bugs );
|
|
}
|
|
|
|
void CentralWidget::updateBugDetails( const Bug &bug, const BugDetails &bd )
|
|
{
|
|
if ( !m_bLoadingAllBugs )
|
|
m_bugPane->setBug( bug, bd );
|
|
}
|
|
|
|
void CentralWidget::slotReloadPackageList()
|
|
{
|
|
BugSystem::self()->cache()->invalidatePackageList();
|
|
BugSystem::self()->retrievePackageList();
|
|
}
|
|
|
|
void CentralWidget::slotReloadPackage()
|
|
{
|
|
if (!m_currentPackage.isNull()) {
|
|
BugSystem::self()->cache()->invalidateBugList( m_currentPackage, m_currentComponent );
|
|
BugSystem::self()->retrieveBugList( m_currentPackage, m_currentComponent );
|
|
}
|
|
}
|
|
|
|
void CentralWidget::slotLoadMyBugs()
|
|
{
|
|
BugSystem::self()->retrieveMyBugsList();
|
|
}
|
|
|
|
void CentralWidget::slotReloadBug()
|
|
{
|
|
if (!m_currentBug.isNull()) {
|
|
BugSystem::self()->cache()->invalidateBugDetails( m_currentBug );
|
|
BugSystem::self()->retrieveBugDetails( m_currentBug );
|
|
}
|
|
}
|
|
|
|
void CentralWidget::updatePackage()
|
|
{
|
|
if (!m_currentPackage.isNull()) {
|
|
BugSystem::self()->retrieveBugList( m_currentPackage, m_currentComponent );
|
|
}
|
|
}
|
|
|
|
void CentralWidget::slotExtractAttachments()
|
|
{
|
|
if (!m_currentBug.isNull()) {
|
|
// Grab bug details (i.e. full-text) from cache, then extract attachments from it
|
|
BugDetails details = BugSystem::self()->cache()->loadBugDetails( m_currentBug );
|
|
TQValueList<BugDetails::Attachment> attachments = details.extractAttachments();
|
|
if ( !attachments.isEmpty() )
|
|
{
|
|
TQStringList fileList;
|
|
for ( TQValueList<BugDetails::Attachment>::Iterator it = attachments.begin() ; it != attachments.end() ; ++it )
|
|
{
|
|
// Handle duplicates
|
|
if ( fileList.contains( (*it).filename ) )
|
|
{
|
|
int n = 2; // looks stupid to have "blah" and "1-blah", start at 2
|
|
TQString fn = TQString::number(n) + '-' + (*it).filename;
|
|
while ( fileList.contains( fn ) )
|
|
{
|
|
++n;
|
|
fn = TQString::number(n) + '-' + (*it).filename;
|
|
}
|
|
(*it).filename = fn;
|
|
}
|
|
fileList += (*it).filename;
|
|
}
|
|
|
|
int res = KMessageBox::questionYesNoList( this,
|
|
i18n("Found the following attachments. Save?"),
|
|
fileList, TQString(), KStdGuiItem::save(), KStdGuiItem::dontSave() );
|
|
if ( res == KMessageBox::No )
|
|
return;
|
|
TQString dir = KFileDialog::getExistingDirectory( TQString(), this, i18n("Select Folder Where to Save Attachments") );
|
|
if ( !dir.isEmpty() )
|
|
{
|
|
if ( !dir.endsWith( "/" ) )
|
|
dir += '/';
|
|
for ( TQValueList<BugDetails::Attachment>::Iterator it = attachments.begin() ; it != attachments.end() ; ++it )
|
|
{
|
|
TQString filename = m_currentBug.number() + '-' + (*it).filename;
|
|
TQFile file( dir + filename );
|
|
if ( file.open( IO_WriteOnly ) )
|
|
file.writeBlock( (*it).contents );
|
|
else
|
|
kdError() << "Couldn't save attachment to " << filename << endl;
|
|
file.close();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CentralWidget::mergeBugs()
|
|
{
|
|
TQStringList bugNumbers = m_listPane->selectedBugs();
|
|
if ( bugNumbers.count() >= 2 ) {
|
|
BugSystem::self()->queueCommand(
|
|
new BugCommandMerge( bugNumbers, m_currentPackage ) );
|
|
}
|
|
}
|
|
|
|
void CentralWidget::unmergeBugs()
|
|
{
|
|
BugSystem::self()->queueCommand(
|
|
new BugCommandUnmerge( m_currentBug, m_currentPackage ) );
|
|
}
|
|
|
|
void CentralWidget::closeBug()
|
|
{
|
|
MsgInputDialog *dlg = new MsgInputDialog( MsgInputDialog::Close,
|
|
m_currentBug, m_currentPackage,
|
|
m_bugPane->bugDetailsWidget()->selectedText(), this );
|
|
dlg->show();
|
|
}
|
|
|
|
void CentralWidget::closeBugSilently()
|
|
{
|
|
BugSystem::self()->queueCommand(
|
|
new BugCommandCloseSilently( m_currentBug, m_currentPackage ) );
|
|
}
|
|
|
|
void CentralWidget::reopenBug()
|
|
{
|
|
BugSystem::self()->queueCommand(
|
|
new BugCommandReopen( m_currentBug, m_currentPackage ) );
|
|
}
|
|
|
|
void CentralWidget::reassignBug()
|
|
{
|
|
PackageSelectDialog *dlg = new PackageSelectDialog( this );
|
|
dlg->exec();
|
|
|
|
dlg->setPackages( BugSystem::self()->packageList() );
|
|
BugServerConfig cfg = BugSystem::self()->server()->serverConfig();
|
|
dlg->setRecentPackages( cfg.recentPackages() );
|
|
|
|
Package package = dlg->selectedPackage();
|
|
|
|
if ( package.isNull() ) {
|
|
return;
|
|
}
|
|
|
|
BugSystem::self()->queueCommand(
|
|
new BugCommandReassign( m_currentBug, package.name(), m_currentPackage ) );
|
|
}
|
|
|
|
void CentralWidget::titleBug()
|
|
{
|
|
bool ok = false;
|
|
TQString title = KInputDialog::getText( i18n("Change Bug Title"),
|
|
i18n( "Please enter a new title:" ),
|
|
m_currentBug.title(), &ok, this );
|
|
if ( ok && !title.isEmpty() ) {
|
|
BugSystem::self()->queueCommand(
|
|
new BugCommandRetitle( m_currentBug, title, m_currentPackage ) );
|
|
}
|
|
}
|
|
|
|
void CentralWidget::severityBug()
|
|
{
|
|
SeveritySelectDialog *dlg = new SeveritySelectDialog( this );
|
|
dlg->setSeverity( m_currentBug.severity() );
|
|
int result = dlg->exec();
|
|
if ( result == TQDialog::Accepted ) {
|
|
BugSystem::self()->queueCommand(
|
|
new BugCommandSeverity( m_currentBug,
|
|
dlg->selectedSeverityAsString(), m_currentPackage ) );
|
|
}
|
|
}
|
|
|
|
void CentralWidget::replyBug()
|
|
{
|
|
MsgInputDialog *dlg = new MsgInputDialog( MsgInputDialog::Reply,
|
|
m_currentBug, m_currentPackage,
|
|
m_bugPane->bugDetailsWidget()->selectedText(), this );
|
|
dlg->show();
|
|
}
|
|
|
|
void CentralWidget::replyPrivateBug()
|
|
{
|
|
MsgInputDialog *dlg = new MsgInputDialog( MsgInputDialog::ReplyPrivate,
|
|
m_currentBug, m_currentPackage,
|
|
m_bugPane->bugDetailsWidget()->selectedText(), this );
|
|
dlg->show();
|
|
}
|
|
|
|
void CentralWidget::clearCommand()
|
|
{
|
|
BugSystem::self()->clearCommands( m_currentBug.number() );
|
|
}
|
|
|
|
void CentralWidget::searchBugByTitle( int options, const TQString& pattern )
|
|
{
|
|
m_listPane->searchBugByTitle( options, pattern );
|
|
}
|
|
|
|
void CentralWidget::slotRetrieveAllBugDetails()
|
|
{
|
|
m_bLoadingAllBugs = true;
|
|
// Make a modal dialog to show the progress, and block usage of main window.
|
|
LoadAllBugsDlg dlg( m_currentPackage, m_currentComponent );
|
|
dlg.exec();
|
|
m_bLoadingAllBugs = false;
|
|
}
|
|
|
|
void CentralWidget::showLoadingError( const TQString &text )
|
|
{
|
|
KMessageBox::error( this, text );
|
|
}
|
|
|
|
CWBugDetails *CentralWidget::bugDetailsWidget()
|
|
{
|
|
return m_bugPane->bugDetailsWidget();
|
|
}
|
|
|
|
#include "centralwidget.moc"
|