diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | bd9e6617827818fd043452c08c606f07b78014a0 (patch) | |
tree | 425bb4c3168f9c02f10150f235d2cb998dcc6108 /kbugbuster/gui | |
download | tdesdk-bd9e6617827818fd043452c08c606f07b78014a0.tar.gz tdesdk-bd9e6617827818fd043452c08c606f07b78014a0.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdesdk@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kbugbuster/gui')
39 files changed, 5294 insertions, 0 deletions
diff --git a/kbugbuster/gui/Makefile.am b/kbugbuster/gui/Makefile.am new file mode 100644 index 00000000..f1a13327 --- /dev/null +++ b/kbugbuster/gui/Makefile.am @@ -0,0 +1,24 @@ +INCLUDES= -I$(top_srcdir)/kbugbuster/backend -I$(top_srcdir)/kbugbuster/ $(all_includes) + +noinst_LTLIBRARIES = libkbbmainwindow.la + +libkbbmainwindow_la_SOURCES = packagelvi.cpp buglvi.cpp cwloadingwidget.cpp \ + cwsearchwidget_base.ui cwsearchwidget.cpp \ + cwbugdetailscontainer_base.ui \ + cwbugdetailscontainer.cpp \ + cwbuglistcontainer.cpp \ + cwbugdetails.cpp \ + centralwidget_base.ui centralwidget.cpp \ + kbbmainwindow.cpp msginputdialog.cpp \ + packageselectdialog.cpp messageeditor.cpp \ + severityselectdialog.cpp \ + preferencesdialog.cpp loadallbugsdlg.cpp \ + serverconfigdialog.cpp + +METASOURCES = AUTO + +EXTRA_DIST = kbugbusterui.rc + +rcdir = $(kde_datadir)/kbugbuster +rc_DATA = kbugbusterui.rc + diff --git a/kbugbuster/gui/README b/kbugbuster/gui/README new file mode 100644 index 00000000..54e5fa67 --- /dev/null +++ b/kbugbuster/gui/README @@ -0,0 +1,21 @@ +Normal classes: +=============== +kbbmainwindow.* KBugBuster's main window +buglvi.* QListViewItem representing a bug +packagelvi.* QListViewItem representing a package +cwloadingwidget.* The temporary widget shown initially, while loading + +msginputdialog.* The dialog for entering a message for closing the bug +messageeditor.* The dialog for editing the custom messages, associated with buttons +packageselectdialog.* Dialog for selecting a package +severityselectdialog.* Dialog for selecting a severity + +Widgets, including a Qt designer .ui file: +========================================== +centralwidget* The main widget of kbbmainwindow +cwbuglistcontainer* The widget containing the bug list (top of central widget) +cwbugdetailscontainer* The widget containing the bug details + the buttons in its right (bottom of central widget). +cwbugdetails* The widget showing details of a bug report, using KHTMLPart +cwsearchwidget* A future search widget on the left of the bug details. + Same functionality is in the menus, this would take too much screen space IMHO (DF) +preferencesdialog* Preferences dialog diff --git a/kbugbuster/gui/buglvi.cpp b/kbugbuster/gui/buglvi.cpp new file mode 100644 index 00000000..be629510 --- /dev/null +++ b/kbugbuster/gui/buglvi.cpp @@ -0,0 +1,109 @@ +/* + buglvi.cpp - Custom QListViewItem that holds a Bug object + + 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 <qfont.h> +#include <qpainter.h> + +#include <kstringhandler.h> +#include <kdebug.h> + +#include "bugsystem.h" +#include "bugserver.h" + +#include "buglvi.h" + +using namespace KBugBusterMainWindow; + +BugLVI::BugLVI( KListView *parent , const Bug &bug ) +: KListViewItem( parent, bug.number() + " ", + i18n( "1 day", "%n days", bug.age() ), + bug.title(), //KStringHandler::csqueeze( bug.title(), 70 ), + Bug::statusLabel( bug.status() ), + Bug::severityLabel( bug.severity() ), + bug.submitter().fullName() ) +{ + m_bug = bug; + + bool hasCommands = BugSystem::self()->server()->hasCommandsFor( bug ); + mCommandState = hasCommands ? BugCommand::Queued : BugCommand::None; + + if ( bug.age() == 0xFFFFFFFF ) + setText( 1, i18n( "Unknown" ) ); + + Person developer = bug.developerTODO(); + if ( !developer.name.isEmpty() ) + setText( 3, i18n( "%1 (%2)" ).arg( Bug::statusLabel( bug.status() ), developer.name ) ); +} + +BugLVI::~BugLVI() +{ +} + +QString BugLVI::key( int column, bool /* ascending */ ) const +{ + QString key; + + if ( column == 0 ) + { + key = text( 0 ).rightJustify( 10, '0' ); + } + else if ( column == 1 ) + { + if ( m_bug.age() == 0xFFFFFFFF ) + key = "0"; + else + key = QString::number( m_bug.age() ).rightJustify( 10, '0' ); + } + else if ( column == 4 ) + { + key = QString::number( 10 - m_bug.severity() ); + key += m_bug.number().rightJustify( 10, '0' ); + } + else + { + key = text( column ); + } + + return key; +} + +void BugLVI::paintCell(QPainter* p, const QColorGroup& cg, + int column, int width, int align) +{ + QColorGroup newCg = cg; + if ( mCommandState == BugCommand::Queued ) { + QFont font = p->font(); + font.setBold( true ); + p->setFont( font ); + } else if ( mCommandState == BugCommand::Sent ) { + QFont font = p->font(); + font.setItalic( true ); + p->setFont( font ); + } else if ( m_bug.status() == Bug::Closed ) { + // Different color for closed bugs + newCg.setColor( QColorGroup::Text, cg.color( QColorGroup::Dark ) ); + } + + KListViewItem::paintCell( p, newCg, column, width, align ); +} + +void BugLVI::setCommandState( BugCommand::State state) +{ + mCommandState = state; +} + +// vim: set et ts=4 sw=4 sts=4: + diff --git a/kbugbuster/gui/buglvi.h b/kbugbuster/gui/buglvi.h new file mode 100644 index 00000000..ff8fa7f9 --- /dev/null +++ b/kbugbuster/gui/buglvi.h @@ -0,0 +1,57 @@ +/* + buglvi.h - Custom QListViewItem that holds a Bug object + + 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. * + * * + ************************************************************************* +*/ + +#ifndef KBBMAINWINDOW_BUGLVI_H +#define KBBMAINWINDOW_BUGLVI_H + +#include <klistview.h> + +#include "bug.h" +#include "bugcommand.h" + +namespace KBugBusterMainWindow +{ + +/** + * @author Martijn Klingens + */ +class BugLVI : public KListViewItem +{ +public: + BugLVI( KListView *parent , const Bug &bug ); + ~BugLVI(); + + Bug& bug() { return m_bug; } + void setBug( Bug &bug ) { m_bug = bug; } + + QString key ( int column, bool ascending ) const; + + void setCommandState( BugCommand::State state ); + + void paintCell(QPainter* p, const QColorGroup& cg, + int column, int width, int align); + +private: + Bug m_bug; + BugCommand::State mCommandState; +}; + +} // namespace + +#endif // KBBMAINWINDOW_BUGLVI_H + +/* vim: set et ts=4 softtabstop=4 sw=4: */ + diff --git a/kbugbuster/gui/centralwidget.cpp b/kbugbuster/gui/centralwidget.cpp new file mode 100644 index 00000000..80bd0672 --- /dev/null +++ b/kbugbuster/gui/centralwidget.cpp @@ -0,0 +1,507 @@ +/* + 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 <qsplitter.h> +#include <qpushbutton.h> +#include <qwidgetstack.h> +#include <qlayout.h> + +#include <kdialog.h> +#include <kdebug.h> +#include <kcombobox.h> +#include <klistview.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 <kfiledialog.h> +#include <kmessagebox.h> +#include "loadallbugsdlg.h" + +using namespace KBugBusterMainWindow; + +CentralWidget::CentralWidget( const QCString &initialPackage, + const QCString &initialComponent, + const QCString &initialBug, QWidget *parent, + const char * name ) + : QWidget( parent, name ) +{ + // Master layout + ( new QVBoxLayout( this, 0, + KDialog::spacingHint() ) )->setAutoAdd( true ); + + // Create QSplitter children + m_vertSplitter = new QSplitter( QSplitter::Vertical, this ); + m_listPane = new CWBugListContainer( m_vertSplitter ); + m_horSplitter = new QSplitter( QSplitter::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( QSizePolicy( QSizePolicy::Minimum, + QSizePolicy::Minimum ) ); + m_horSplitter->setResizeMode( m_searchPane, QSplitter::FollowSizeHint ); + + connect( m_listPane, SIGNAL( resetProgressBar() ), + SIGNAL( resetProgressBar() ) ); + connect( m_bugPane, SIGNAL( resetProgressBar() ), + SIGNAL( resetProgressBar() ) ); + + // Start the proper jobs for loading the package lists + connect( BugSystem::self(), + SIGNAL( packageListAvailable( const Package::List & ) ), + SLOT( updatePackageList( const Package::List & ) ) ); + connect( BugSystem::self(), + SIGNAL( bugListAvailable( const Package &, const QString &, const Bug::List & ) ), + SLOT( updateBugList( const Package &, const QString &, const Bug::List & ) ) ); + connect( BugSystem::self(), + SIGNAL( bugListAvailable( const QString &, const Bug::List & ) ), + SLOT( updateBugList( const QString &, const Bug::List & ) ) ); + connect( BugSystem::self(), + SIGNAL( bugDetailsAvailable( const Bug &, const BugDetails & ) ), + SLOT( updateBugDetails( const Bug &, const BugDetails & ) ) ); + + connect( BugSystem::self(), SIGNAL( loadingError( const QString & ) ), + SLOT( showLoadingError( const QString & ) ) ); + + connect( m_bugPane, SIGNAL( signalCloseBug() ), SLOT( closeBug() ) ); + connect( m_bugPane, SIGNAL( signalCloseBugSilently() ), SLOT( closeBugSilently() ) ); + connect( m_bugPane, SIGNAL( signalReopenBug() ), SLOT( reopenBug() ) ); + connect( m_bugPane, SIGNAL( signalReassignBug() ), SLOT( reassignBug() ) ); + connect( m_bugPane, SIGNAL( signalTitleBug() ), SLOT( titleBug() ) ); + connect( m_bugPane, SIGNAL( signalSeverityBug() ), SLOT( severityBug() ) ); + connect( m_bugPane, SIGNAL( signalReplyBug() ), SLOT( replyBug() ) ); + connect( m_bugPane, SIGNAL( signalReplyPrivateBug() ), SLOT( replyPrivateBug() ) ); + + connect( m_bugPane, SIGNAL( signalClearCommand() ), SLOT( clearCommand() ) ); + + // Add the selection slots for the listviews + connect( m_searchPane->m_searchPackages, + SIGNAL( activated( const QString & ) ), + SLOT( slotRetrieveBugList( const QString & ) ) ); + + connect( m_listPane, SIGNAL( executed( const Bug & ) ), + SLOT( slotRetrieveBugDetails( const Bug & ) ) ); + connect( m_listPane, SIGNAL( currentChanged( const Bug & ) ), + SLOT( slotSetActiveBug( const Bug & ) ) ); + + connect( m_listPane, SIGNAL( searchPackage() ), SIGNAL( searchPackage() ) ); + connect( m_bugPane, SIGNAL( searchBugNumber() ), SIGNAL( searchBugNumber() ) ); + + m_bLoadingAllBugs = false; + + initialize( initialPackage, initialComponent, initialBug ); +} + +CentralWidget::~CentralWidget() +{ +// kdDebug() << "CentralWidget::~CentralWidget()" << endl; +} + +void CentralWidget::initialize( const QString& p, const QString &c, const QString& b ) +{ +// kdDebug() << "CentralWidget::initialize(): package: '" << p +// << "' bug: '" << b << "'" << endl; + + BugServerConfig cfg = BugSystem::self()->server()->serverConfig(); + QString package = p.isEmpty() ? cfg.currentPackage() : p; + QString bug = b.isEmpty() ? cfg.currentBug() : b; + QString 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; + QValueList<int> sizes = m_vertSplitter->sizes(); + QValueList<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 QString &package ) +{ + slotRetrieveBugList( package, QString::null ); +} + +void CentralWidget::slotRetrieveBugList( const QString &p, const QString &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 ); +} + +QString CentralWidget::currentNumber() const +{ + if( m_currentBug.isNull() ) + return ""; + else + return m_currentBug.number(); +} + +QString 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 QString &component, const Bug::List &bugs ) +{ + m_listPane->setBugList( pkg, component, bugs ); +} + +void CentralWidget::updateBugList( const QString &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 ); + QValueList<BugDetails::Attachment> attachments = details.extractAttachments(); + if ( !attachments.isEmpty() ) + { + QStringList fileList; + for ( QValueList<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 + QString fn = QString::number(n) + '-' + (*it).filename; + while ( fileList.contains( fn ) ) + { + ++n; + fn = QString::number(n) + '-' + (*it).filename; + } + (*it).filename = fn; + } + fileList += (*it).filename; + } + + int res = KMessageBox::questionYesNoList( this, + i18n("Found the following attachments. Save?"), + fileList, QString::null, KStdGuiItem::save(), KStdGuiItem::dontSave() ); + if ( res == KMessageBox::No ) + return; + QString dir = KFileDialog::getExistingDirectory( QString::null, this, i18n("Select Folder Where to Save Attachments") ); + if ( !dir.isEmpty() ) + { + if ( !dir.endsWith( "/" ) ) + dir += '/'; + for ( QValueList<BugDetails::Attachment>::Iterator it = attachments.begin() ; it != attachments.end() ; ++it ) + { + QString filename = m_currentBug.number() + '-' + (*it).filename; + QFile 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() +{ + QStringList 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; + QString 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 == QDialog::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 QString& 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 QString &text ) +{ + KMessageBox::error( this, text ); +} + +CWBugDetails *CentralWidget::bugDetailsWidget() +{ + return m_bugPane->bugDetailsWidget(); +} + +#include "centralwidget.moc" + +/* vim: set et ts=4 sw=4 softtabstop=4: */ diff --git a/kbugbuster/gui/centralwidget.h b/kbugbuster/gui/centralwidget.h new file mode 100644 index 00000000..85b97eca --- /dev/null +++ b/kbugbuster/gui/centralwidget.h @@ -0,0 +1,142 @@ +/* + centralwidget.h - 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. * + * * + ************************************************************************* +*/ + +#ifndef KBBMAINWINDOW_CENTRALWIDGET_H +#define KBBMAINWINDOW_CENTRALWIDGET_H + +#include <qwidget.h> + +#include "package.h" +#include "bug.h" +#include "bugdetails.h" + +class QSplitter; +class QListViewItem; + +namespace KBugBusterMainWindow +{ + +class CWSearchWidget; +class CWBugListContainer; +class CWBugDetailsContainer; +class CWBugDetails; + +/** + * @author Martijn Klingens + */ +class CentralWidget : public QWidget +{ + Q_OBJECT + +public: + CentralWidget( const QCString &initialPackage, + const QCString &initalComponent,const QCString& initialBug, + QWidget* parent = 0, const char* name = 0 ); + ~CentralWidget(); + + void initialize( const QString &initialPackage = QString::null, + const QString &initalComponent = QString::null, + const QString &initialBug = QString::null ); + + void readConfig(); + void writeConfig(); + + void searchBugByTitle( int options, const QString& pattern ); + + virtual QString currentNumber() const; + virtual QString currentTitle() const; + + void updatePackage(); + + CWBugDetails *bugDetailsWidget(); + +public slots: + void slotRetrieveBugList( const QString &package, const QString &component ); + void slotRetrieveBugList( const QString &package ); + void slotRetrieveBugDetails( const Bug & ); + void slotSetActiveBug( const Bug & ); + void slotRetrieveAllBugDetails(); + + void updatePackageList( const Package::List &pkgs ); + void updateBugList( const Package &pkg, const QString &component, const Bug::List &bugs ); + void updateBugList( const QString &label, const Bug::List &bugs ); + void updateBugDetails( const Bug &, const BugDetails & ); + + void slotReloadPackageList(); + void slotReloadPackage(); + void slotReloadBug(); + void slotExtractAttachments(); + + /** + * Load the bugs the user reported himself, or for which he is the assigned to person + */ + void slotLoadMyBugs(); + + void mergeBugs(); + void unmergeBugs(); + + void closeBug(); + void closeBugSilently(); + void reopenBug(); + void titleBug(); + void severityBug(); + void replyBug(); + void replyPrivateBug(); + void reassignBug(); + + void clearCommand(); + +signals: + void resetProgressBar(); + void searchPackage(); // when clicking on the initial package widget + void searchBugNumber(); // when clicking on the initial bug-details widget + +protected slots: + void showLoadingError( const QString & ); + +private: + CWSearchWidget *m_searchPane; + CWBugListContainer *m_listPane; + CWBugDetailsContainer *m_bugPane; + + QSplitter *m_vertSplitter; + QSplitter *m_horSplitter; + + /** + * Other status info + */ + Package m_currentPackage; + QString m_currentComponent; + Bug m_currentBug; + + QMap<QString, Package> m_packageList; + + /** + * We do multi-select, but the close/reopen buttons are per-item and + * on highlight instead of on execute! Hence this different member + */ + Bug m_activeBug; + + // For "load all bugs" + bool m_bLoadingAllBugs; +}; + +} // namespace + +#endif // KBBMAINWINDOW_CENTRALWIGET_H + +/* vim: set et ts=4 softtabstop=4 sw=4: */ + diff --git a/kbugbuster/gui/centralwidget_base.ui b/kbugbuster/gui/centralwidget_base.ui new file mode 100644 index 00000000..d2f707de --- /dev/null +++ b/kbugbuster/gui/centralwidget_base.ui @@ -0,0 +1,236 @@ +<!DOCTYPE UI><UI version="3.0" stdsetdef="1"> +<class>CentralWidget_Base</class> +<widget class="QWidget"> + <property name="name"> + <cstring>CentralWidget_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>630</width> + <height>518</height> + </rect> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>m_searchGroup</cstring> + </property> + <property name="title"> + <string>Search</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>m_searchContainer</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QWidgetStack"> + <property name="name"> + <cstring>m_searchStack</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel9</cstring> + </property> + <property name="text"> + <string>Bug &number:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_searchBugNumber</cstring> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout17</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_searchBugNumber</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_searchBugNumberBtn</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string></string> + </property> + <property name="pixmap"> + <pixmap>image0</pixmap> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel7</cstring> + </property> + <property name="text"> + <string>&Description:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_searchDesc</cstring> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout15</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_searchDesc</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_searchDescBtn</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string></string> + </property> + <property name="pixmap"> + <pixmap>image0</pixmap> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </vbox> + </widget> + <widget class="QSplitter"> + <property name="name"> + <cstring>m_splitter</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + </hbox> +</widget> +<customwidgets> + <customwidget> + <class>QWidgetStack</class> + <header location="global">qwidgetstack.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>1</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image1</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="XPM.GZ" length="1725">789c75d4594fdb401405e0777e4584df5075b0e325b6aa3eb015ca1e76a8fa309ea518ca9eb055fdef9d39774815447311e4c3c73377c6cbfc5cef6477ab37373ff33052a34ef7f4b9baefcd99f1d5d5cbf71f5f7ecfcc6655cfff544daf3ffb69667638eae9def6cdb50d40e791a4fc04274aac7df1f840ecfc87bea3b350b4a5fba1787e420f42f1f8906e42d16b741b8a6e691b8a7e09e6f0323fc7eb0f42d179706e956a739afde62e146dde5cc8f93ab8487d49bf2774def65b4d1f0797b96e4c416f0757a9ceb4a1fb74ad2b23e73fd146175acecf68e7cdfe13ae87cb97fc0a9de94a8e23a52bdd9a92de129b8195f51cd1b5a9a3bfd28d56b1bf92567e3ed9bf535aeb26f67b41bbba5fcbfcb7c1755ae735af0f76e8526b23aee846d746f6eb9056a6b5d2df01ddfafee4f832ed8cb3355d0437a9298df4f318dd18b91e9b746933abe8bd60559b2caeff3adaca7c0968632a23f9fd6863a5df1bb12de2fc67b4f579997f8976b671d2ef46709b5a65a59f57baf2fdc97ed57463fc90f46a741bd7fb4c2babe3f963da5ae3647fcf8375660a53b17fde6f3a0fc5e3eb623fbfdc2f5774691b2bf335b4f2c7a59f5dda581dfb77b435b591e76731d8a42e73b27f0b74e9fa4eee8f6ff4c09696fde0e7c4b25fbf68edf3d2df88b6ae74f27c5d065b3e40f47d7411f30fb472ad53f23291420285f64df17f7a387acbc0c0c2e127ced1c14ce724e31317b8c42f5ce11a37fe7b4ce116b793cc1deef18011c678c4139ed1c5840e25ef0fbc62c12716b18465ace02b56b136c924f24ec137acfb3136b0892d6c6307bb18c655243217d6b0877d1ce0104738c6094e7126b34df5dcf9515264e8fb44eebf77ff59d718054a54feef853f67f03ec354871a4d82b03f18f8dfddfb0c73774982bbe12851e89236d16fa9c9387aea0a74d0ff5253e3e88f53b167eef9bbab3949c97b45f6fce319a732c9fb91980a73fdf93cf317e4bbac85</data> + </image> + <image name="image1"> + <data format="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758</data> + </image> +</images> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kbugbuster/gui/cwbugdetails.cpp b/kbugbuster/gui/cwbugdetails.cpp new file mode 100644 index 00000000..7aaf16a4 --- /dev/null +++ b/kbugbuster/gui/cwbugdetails.cpp @@ -0,0 +1,212 @@ +/* + cwbugdetails.cpp - Details of a bug report + + 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 <qtextview.h> +#include <qlineedit.h> +#include <qcombobox.h> +#include <qlabel.h> + +#include "cwbugdetails.h" +#include "kbbprefs.h" +#include "bugsystem.h" +#include "bugserver.h" + +#include <khtml_part.h> +#include <khtmlview.h> +#include <kdebug.h> +#include <kglobal.h> +#include <krun.h> + +#include <qlayout.h> +#include <qpalette.h> + +using namespace KBugBusterMainWindow; + +CWBugDetails::CWBugDetails( QWidget *parent , const char * name ) + : QWidget( parent, name ) +{ + QBoxLayout *topLayout = new QVBoxLayout( this ); + + m_bugDesc = new KHTMLPart( this, "m_bugDesc" ); + connect( m_bugDesc->browserExtension(), SIGNAL( openURLRequest( const KURL &, const KParts::URLArgs & ) ), + this, SLOT( handleOpenURLRequest( const KURL &, const KParts::URLArgs & ) ) ); + + topLayout->addWidget( m_bugDesc->view() ); +} + +CWBugDetails::~CWBugDetails() +{ +} + +void CWBugDetails::setBug( const Bug &bug, const BugDetails &details ) +{ + QColorGroup cg = m_bugDesc->view()->palette().active(); + QString text = + "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n" + "<html><head><title></title></head>\n" + "<style>"; + + text.append( + QString( "table.helpT { text-align: center; font-family: Verdana; font-weight: normal; font-size: 11px; color: #404040; width: 100%; background-color: #fafafa; border: 1px #6699CC solid; border-collapse: collapse; border-spacing: 0px; }\n" + "td.helpHed { border-bottom: 2px solid #000000; border-left: 1px solid #000000; background-color: %1; text-align: center; text-indent: 5px; font-family: Verdana; font-weight: bold; font-size: 11px; color: %2; }\n" + "td.helpBod { border-bottom: 1px solid #9CF; border-top: 0px; border-left: 1px solid #9CF; border-right: 0px; text-align: center; text-indent: 10px; font-family: Verdana, sans-serif, Arial; font-weight: normal; font-size: 11px; color: #404040; background-color: #000000; }\n" + "table.sofT { text-align: center; font-family: Verdana; font-weight: normal; font-size: 11px; color: #404040; width: 100%; background-color: #fafafa; border: 1px #000000 solid; border-collapse: collapse; border-spacing: 0px; }\n" + "</style>\n" ) + .arg( cg.highlight().name() ) + .arg( cg.highlightedText().name() ) ); + + text.append( "<body style=\"margin: 0px\">\n" ); + + QString highlightStyle = QString( "background: %1; color: %2; " ) + .arg( cg.highlight().name() ) + .arg( cg.highlightedText().name() ); + QString borderBottomStyle = QString( "border-bottom: solid %1 1px; " ) + .arg( cg.foreground().name() ); + QString borderTopStyle = QString( "border-top: solid %1 1px; " ) + .arg( cg.foreground().name() ); + + QString submitter = bug.submitter().fullName( true ); + int age = details.age(); + text.append( "<div style=\"" + highlightStyle + "padding: 8px; float: left\">" ); + text.append( "<a href=\"" + BugSystem::self()->server()->bugLink( bug ).url() + + "\">" + i18n("Bug Report</a> from <b>%1</b> " ) + .arg( submitter ) ); + int replies = details.parts().count() - 1; + if ( replies >= 1 ) text += i18n( "(1 reply)", "(%n replies)", replies ); + text += "</div>"; + text += "<div style=\"" + highlightStyle + borderBottomStyle + + " text-align: right; padding: 8px\">" + + i18n( "1 day old", "%n days old", age ) + "</div>\n"; + + text.append( + QString( "<div style=\"background: %1; color: %2; " + + borderBottomStyle + + "border-bottom: solid %3 1px; " + "padding: 4px\">" + "<table cellspacing=\"0\" cellpadding=\"4\" width=\"100%\">" ) + .arg( cg.background().name() ) + .arg( cg.foreground().name() ) ); + text.append( textBugDetailsAttribute( details.version(), i18n("Version") ) ); + text.append( textBugDetailsAttribute( details.source(), i18n("Source") ) ); + text.append( textBugDetailsAttribute( details.compiler(), i18n("Compiler") ) ); + text.append( textBugDetailsAttribute( details.os(), i18n("OS") ) ); + text.append( "</table></div>\n" ); + + BugDetailsPart::List bdp = details.parts(); + BugDetailsPart::List::ConstIterator it; + bool firstHeader = true; + + for ( it = bdp.begin(); it != bdp.end(); ++it ) { + if ( bdp.count() > 1 ) { + text.append( "<div style=\"" + highlightStyle + "padding: 8px; float: left; " ); + if ( !firstHeader ) text += borderTopStyle; + + text.append( borderBottomStyle + "\">" ); + QString sender = (*it).sender.fullName( true ); + QString date = KGlobal::locale()->formatDateTime( (*it).date, false ); + BugDetailsPart::List::ConstIterator it2 = it; + if ( ++it2 == bdp.end() ) + text.append( "<a href=\"" + BugSystem::self()->server()->bugLink( bug ).url() + + "\">" + i18n("Bug Report</a> from <b>%1</b>") + .arg( sender ) ); + else { + text.append( "<a href=\"" + BugSystem::self()->server()->bugLink( bug ).url() + QString("#c%1").arg( replies ) + + "\">" + i18n("Reply #%1</a> from <b>%2</b>") + .arg( replies ).arg( sender ) ); + replies--; + } + text.append( "</div>\n" ); + text += "<div style=\"" + highlightStyle + borderBottomStyle; + if ( !firstHeader ) text += borderTopStyle; + text += "text-align: right; padding: 8px\">" + date + "</div>\n"; + + firstHeader = false; + } + + // Adding of <pre> tags is now done by BugDetailsJob::processNode. This + // was breaking the display of attachments because they have <br/>\n + // after each line -> two newlines with <pre> + text.append( "<div style=\"padding: 8px\">" ); + text.append( (*it).text ); + text.append( "</div>\n" ); + } + + QValueList<BugDetailsImpl::AttachmentDetails> atts = details.attachmentDetails(); + if ( atts.count() > 0 ) { + text.append( "<table summary=\"Attachment data table\" class=\"sofT\" cellspacing=\"0\">" ); + text.append( QString( "<tr> <td colspan=\"4\" class=\"helpHed\">%1</td> </tr>") + .arg( i18n( "Attachment List") ) ); + text.append( QString("<tr> <td class=\"helpHed\">%1</td> <td class=\"helpHed\">%2</td> <td class=\"helpHed\">%3</td> <td class=\"helpHed\">%4</td> </tr>") + .arg( i18n("Description") ) + .arg( i18n("Date") ) + .arg( i18n("View") ) + .arg( i18n("Edit") ) ); + QValueList<BugDetailsImpl::AttachmentDetails>::iterator it; + for ( it = atts.begin() ; it != atts.end() ; ++it ) { + text.append( QString("<tr><td>%1</td>").arg( (*it).description ) ) ; + text.append( QString("<td>%1</td>").arg( (*it).date ) ); + text.append( "<td><a href=\"" + + BugSystem::self()->server()->attachmentViewLink( (*it).id ).url() + + "\">" + i18n("View") + "</a></td>" ); + text.append( "<td><a href=\"" + + BugSystem::self()->server()->attachmentEditLink( (*it).id ).url() + + "\">" + i18n("Edit") + "</a></td>" ); + text.append( "</tr>" ); + } + } + + text.append( "</body></html>" ); + + //kdDebug() << "BEGIN OUTPUT" << text << "END OUTPUT" << endl; + + m_bugDesc->view()->setContentsPos(0,0); + m_bugDesc->begin(); + m_bugDesc->write( text ); + m_bugDesc->end(); + + if ( KBBPrefs::instance()->mDebugMode ) mSource = text; +} + +void CWBugDetails::handleOpenURLRequest( const KURL &url, const KParts::URLArgs & ) +{ + new KRun( url ); +} + +QString CWBugDetails::textBugDetailsAttribute( const QString &value, + const QString &name ) +{ + QString text = ""; + if ( !value.isEmpty() ) { + text.append( "<tr><td style=\"width: 20%\"><b>" + name + "</b></td>" + "<td>" + value + "</td></tr>" ); + } + return text; +} + +QString CWBugDetails::source() const +{ + return mSource; +} + +QString CWBugDetails::selectedText() const +{ + return m_bugDesc->selectedText(); +} + +#include "cwbugdetails.moc" + +/* vim: set et ts=4 sw=4 softtabstop=4: */ + diff --git a/kbugbuster/gui/cwbugdetails.h b/kbugbuster/gui/cwbugdetails.h new file mode 100644 index 00000000..31a5339f --- /dev/null +++ b/kbugbuster/gui/cwbugdetails.h @@ -0,0 +1,65 @@ +/* + cwbugdetails.h - Details of a bug report + + 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. * + * * + ************************************************************************* +*/ + +#ifndef KBBMAINWINDOW_CWBUGDETAILS_H +#define KBBMAINWINDOW_CWBUGDETAILS_H + +#include "bug.h" +#include "bugdetails.h" + +#include <qwidget.h> + +#include <kparts/browserextension.h> + +class KHTMLPart; + +namespace KBugBusterMainWindow +{ + +/** + * @author Martijn Klingens + */ +class CWBugDetails : public QWidget +{ + Q_OBJECT + + public: + CWBugDetails( QWidget* parent = 0, const char* name = 0 ); + ~CWBugDetails(); + + void setBug( const Bug &, const BugDetails & ); + + QString source() const; + QString selectedText() const; + + private slots: + void handleOpenURLRequest( const KURL &url, const KParts::URLArgs & ); + + private: + QString textBugDetailsAttribute( const QString &value, + const QString &name ); + + KHTMLPart *m_bugDesc; + + QString mSource; +}; + +} // namespace + +#endif + +/* vim: set et ts=4 softtabstop=4 sw=4: */ + diff --git a/kbugbuster/gui/cwbugdetailscontainer.cpp b/kbugbuster/gui/cwbugdetailscontainer.cpp new file mode 100644 index 00000000..b33ec3b1 --- /dev/null +++ b/kbugbuster/gui/cwbugdetailscontainer.cpp @@ -0,0 +1,269 @@ +/* + cwbugdetailscontainer.cpp - Container for bug details + + 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 <qpushbutton.h> +#include <qwidgetstack.h> +#include <qlayout.h> +#include <qtooltip.h> + +#include <kiconloader.h> +#include <klocale.h> +#include <kactivelabel.h> +#include <kdialog.h> + +#include "bugsystem.h" +#include "bugcommand.h" +#include "bugserver.h" + +#include "cwbugdetails.h" +#include "cwloadingwidget.h" + +#include "cwbugdetailscontainer.h" +#include <kstringhandler.h> + +using namespace KBugBusterMainWindow; + +CWBugDetailsContainer::CWBugDetailsContainer( QWidget *parent , const char * name ) +: CWBugDetailsContainer_Base( parent, name ) +{ + // Do some stuff Designer can't do: + m_bugCloseBtn->setIconSet( BarIconSet( "edittrash" ) ); + m_bugCloseSilentlyBtn->setIconSet( BarIconSet( "edittrash" ) ); + m_bugReopenBtn->setIconSet( SmallIconSet( "idea" ) ); + m_bugReassignBtn->setIconSet( BarIconSet( "folder_new" ) ); + m_bugTitleBtn->setIconSet( SmallIconSet( "text_under" ) ); + m_bugSeverityBtn->setIconSet( SmallIconSet( "edit" ) ); + m_bugReplyBtn->setIconSet( SmallIconSet( "mail_replyall" ) ); + m_bugReplyPrivBtn->setIconSet( SmallIconSet( "mail_reply" ) ); + + // The Bugzilla mail interface doesn't support all commands yet. + m_bugCloseSilentlyBtn->hide(); + m_bugReassignBtn->hide(); + m_bugTitleBtn->hide(); + m_bugSeverityBtn->hide(); + + // Create Bug Details pane + m_bugDetails = new CWBugDetails( m_bugStack ); + + // Fill WidgetStack in Bug Details pane + m_bugLoading = new CWLoadingWidget( CWLoadingWidget::BottomFrame, + m_bugStack ); + connect( m_bugLoading, SIGNAL( clicked() ), SIGNAL( searchBugNumber() ) ); + + m_bugStack->addWidget( m_bugDetails, 0 ); + m_bugStack->addWidget( m_bugLoading, 1 ); + + setNoBug(); + + QFont f = m_bugLabel->font(); + f.setBold( true ); + m_bugLabel->setFont( f ); + + // Set fonts and margins + CWBugDetailsContainer_BaseLayout->setSpacing( KDialog::spacingHint() ); + CWBugDetailsContainer_BaseLayout->setMargin( KDialog::marginHint() ); + + connect( m_bugCloseBtn, SIGNAL( clicked() ), SIGNAL( signalCloseBug() ) ); + connect( m_bugCloseSilentlyBtn, SIGNAL( clicked() ), SIGNAL( signalCloseBugSilently() ) ); + connect( m_bugReopenBtn, SIGNAL( clicked() ), SIGNAL( signalReopenBug() ) ); + connect( m_bugReassignBtn, SIGNAL( clicked() ), SIGNAL( signalReassignBug() ) ); + connect( m_bugTitleBtn, SIGNAL( clicked() ), SIGNAL( signalTitleBug() ) ); + connect( m_bugSeverityBtn, SIGNAL( clicked() ), SIGNAL( signalSeverityBug() ) ); + connect( m_bugReplyBtn, SIGNAL( clicked() ), SIGNAL( signalReplyBug() ) ); + connect( m_bugReplyPrivBtn, SIGNAL( clicked() ), SIGNAL( signalReplyPrivateBug() ) ); + + connect( m_cmdClearBtn, SIGNAL( clicked() ), SIGNAL( signalClearCommand() ) ); + + connect( BugSystem::self(), SIGNAL( bugDetailsLoading( const Bug & ) ), + SLOT( setLoading( const Bug & ) ) ); + connect( BugSystem::self(), SIGNAL( bugDetailsCacheMiss( const Bug & ) ), + SLOT( setCacheMiss( const Bug & ) ) ); + connect( BugSystem::self(), SIGNAL( commandQueued( BugCommand * ) ), + SLOT( commandQueued( BugCommand * ) ) ); + connect( BugSystem::self(), SIGNAL( commandCanceled( const QString & ) ), + SLOT( clearCommand( const QString & ) ) ); +} + +CWBugDetailsContainer::~CWBugDetailsContainer() +{ +} + +void CWBugDetailsContainer::setBug( const Bug &bug, const BugDetails &details ) +{ + m_bug = bug; + m_bugDetails->setBug( bug, details ); + + QString labelText; + + if ( bug.mergedWith().size() ) + { + //FIXME: What should the separator be for lists? Don't see anything in KLocale for that + QString list; + Bug::BugMergeList mergedWith = bug.mergedWith(); + for (Bug::BugMergeList::ConstIterator i = mergedWith.begin(); i != mergedWith.end(); ++i) + { + list += QString::number(*i)+", "; + } + + list.truncate( list.length()-2 ); //Strip off the last ", " + + labelText = i18n("bug #number [Merged with: a list of bugs] (severity): title","Bug #%1 [Merged with: %2] (%3): %4") + .arg( bug.number() ) + .arg( list ) + .arg( bug.severityAsString() ) + .arg( bug.title() ); + + } + else + { + labelText = i18n("bug #number (severity): title","Bug #%1 (%2): %3") + .arg( bug.number() ).arg( bug.severityAsString() ) + .arg( bug.title() ); + } + + m_bugLabel->setText( KStringHandler::tagURLs( labelText ) ); + + showCommands( bug ); + + enableButtons( bug ); + + m_bugStack->raiseWidget( 0 ); + emit resetProgressBar(); +} + +void CWBugDetailsContainer::showCommands( const Bug& bug ) +{ + QPtrList<BugCommand> commands = BugSystem::self()->server()->queryCommands( bug ); + if ( !commands.isEmpty() ) { + QString cmdDetails; + QString cmdText = i18n("Pending commands:")+" "; + bool first = true; + QPtrListIterator<BugCommand> cmdIt( commands ); + for( ; cmdIt.current(); ++cmdIt ) + { + BugCommand *cmd = cmdIt.current(); + if (!first) + cmdText += " | "; // separator in case of multiple commands + first = false; + cmdText += QString("<b>%1</b>").arg( cmd->name() ); + if (!cmdDetails.isEmpty()) + cmdDetails += " | "; // separator in case of multiple commands + cmdDetails += cmd->details(); + } + // Set summary as text label, details into tooltip + m_cmdLabel->setText( cmdText ); + if ( !cmdDetails.isEmpty() ) { + QToolTip::add( m_cmdLabel, cmdDetails ); + } else { + QToolTip::remove( m_cmdLabel ); + } + m_cmdLabel->show(); + } else { + hideCommands(); + } +} + +void CWBugDetailsContainer::hideCommands() +{ + m_cmdLabel->hide(); +} + +void CWBugDetailsContainer::clearCommand( const QString &bug ) +{ + if ( bug == m_bug.number() ) + showCommands( m_bug ); +} + +void CWBugDetailsContainer::commandQueued( BugCommand *cmd ) +{ + // ### use == operator instead? + // (might not work because impl is different) + if ( cmd && cmd->bug().number() == m_bug.number() ) + showCommands( m_bug ); +} + +void CWBugDetailsContainer::setNoBug() +{ + m_bugLabel->setText( i18n("Bug Title") ); + + m_bug = Bug(); + showCommands( m_bug ); + + m_bugLoading->setText( i18n( "Click here to select a bug by number" ) ); + m_bugStack->raiseWidget( 1 ); +} + +void CWBugDetailsContainer::setLoading( const Bug &bug ) +{ + m_bug = bug; + showCommands( bug ); + + m_bugLoading->setText(i18n( "Retrieving Details for Bug %1\n\n(%2)" ) + .arg( bug.number() ).arg( bug.title() ) ); + m_bugStack->raiseWidget( 1 ); +} + +void CWBugDetailsContainer::setCacheMiss( const Bug &bug ) +{ + m_bug = bug; + showCommands( bug ); + + QString msg; + if( BugSystem::self()->disconnected() ) + msg = i18n( "Bug #%1 (%2) is not available offline." ). + arg( bug.number() ).arg( bug.title() ); + else + msg = i18n( "Retrieving details for bug #%1\n" + "(%2)" ). + arg( bug.number() ).arg( bug.title() ); + m_bugLoading->setText( msg ); + m_bugStack->raiseWidget( 1 ); +} + + +void CWBugDetailsContainer::enableButtons( const Bug &bug ) +{ + if( bug.isNull() ) { + m_bugCloseBtn->setEnabled( false ); + m_bugCloseSilentlyBtn->setEnabled( false ); + m_bugReopenBtn->setEnabled( false ); + m_bugReassignBtn->setEnabled( false ); + m_bugTitleBtn->setEnabled( false ); + m_bugSeverityBtn->setEnabled( false ); + m_bugReplyBtn->setEnabled( false ); + m_bugReplyPrivBtn->setEnabled( false ); + } else { + if( bug.status() != Bug::Closed ) { + m_bugCloseBtn->setEnabled( true ); + m_bugCloseSilentlyBtn->setEnabled( true ); + m_bugReopenBtn->setEnabled( false ); + } else { + m_bugCloseBtn->setEnabled( false ); + m_bugCloseSilentlyBtn->setEnabled( false ); + m_bugReopenBtn->setEnabled( true ); + } + m_bugReassignBtn->setEnabled( true ); + m_bugTitleBtn->setEnabled( true ); + m_bugSeverityBtn->setEnabled( true ); + m_bugReplyBtn->setEnabled( true ); + m_bugReplyPrivBtn->setEnabled( true ); + } +} + +#include "cwbugdetailscontainer.moc" + +/* vim: set et ts=4 sw=4 softtabstop=4: */ + diff --git a/kbugbuster/gui/cwbugdetailscontainer.h b/kbugbuster/gui/cwbugdetailscontainer.h new file mode 100644 index 00000000..c183a8ea --- /dev/null +++ b/kbugbuster/gui/cwbugdetailscontainer.h @@ -0,0 +1,88 @@ +/* + cwbugdetailscontainer.h - Container for bug details + + 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. * + * * + ************************************************************************* +*/ + +#ifndef KBBMAINWINDOW_CWBUGDETAILSCONTAINER_H +#define KBBMAINWINDOW_CWBUGDETAILSCONTAINER_H + +#include "bug.h" +#include "bugdetails.h" + +#include "cwbugdetailscontainer_base.h" + +class BugCommand; + +namespace KBugBusterMainWindow +{ + +class CWBugDetails; +class CWLoadingWidget; + +/** + * @author Martijn Klingens + */ +class CWBugDetailsContainer : public CWBugDetailsContainer_Base +{ + Q_OBJECT + +public: + CWBugDetailsContainer( QWidget* parent = 0, const char* name = 0 ); + ~CWBugDetailsContainer(); + + void setBug( const Bug &, const BugDetails & ); + + CWBugDetails *bugDetailsWidget() { return m_bugDetails; } + +public slots: + void setNoBug(); + void setLoading( const Bug &bug ); + void setCacheMiss( const Bug &bug ); + + void enableButtons( const Bug & ); + +signals: + void resetProgressBar(); + void searchBugNumber(); + + void signalCloseBug(); + void signalCloseBugSilently(); + void signalReopenBug(); + void signalReassignBug(); + void signalTitleBug(); + void signalSeverityBug(); + void signalReplyBug(); + void signalReplyPrivateBug(); + + void signalClearCommand(); + +private slots: + void showCommands( const Bug & ); + void clearCommand( const QString & ); + void commandQueued( BugCommand * ); + +private: + void hideCommands(); + + CWLoadingWidget *m_bugLoading; + CWBugDetails *m_bugDetails; + Bug m_bug; +}; + +} // namespace + +#endif + +/* vim: set et ts=4 softtabstop=4 sw=4: */ + diff --git a/kbugbuster/gui/cwbugdetailscontainer_base.ui b/kbugbuster/gui/cwbugdetailscontainer_base.ui new file mode 100644 index 00000000..c5ef87b7 --- /dev/null +++ b/kbugbuster/gui/cwbugdetailscontainer_base.ui @@ -0,0 +1,244 @@ +<!DOCTYPE UI><UI version="3.0" stdsetdef="1"> +<class>CWBugDetailsContainer_Base</class> +<widget class="QWidget"> + <property name="name"> + <cstring>CWBugDetailsContainer_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>507</width> + <height>559</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QWidgetStack" row="1" column="0"> + <property name="name"> + <cstring>m_bugStack</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>Layout5</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="KActiveLabel"> + <property name="name"> + <cstring>m_bugLabel</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>20</height> + </size> + </property> + <property name="text"> + <string>Bug Title</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_cmdLabel</cstring> + </property> + <property name="text"> + <string>Bug Commands</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="1" column="1"> + <property name="name"> + <cstring>Layout3</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_cmdClearBtn</cstring> + </property> + <property name="text"> + <string>Clear Co&mmands</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_bugCloseBtn</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>C&lose...</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_bugCloseSilentlyBtn</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Close Silentl&y</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_bugReopenBtn</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Re&open</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_bugReassignBtn</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Re&assign...</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_bugTitleBtn</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Change &Title...</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_bugSeverityBtn</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Chan&ge Severity...</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer1_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_bugReplyBtn</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>&Reply...</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_bugReplyPrivBtn</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Reply &Privately...</string> + </property> + </widget> + </vbox> + </widget> + </grid> +</widget> +<customwidgets> + <customwidget> + <class>QWidgetStack</class> + <header location="global">qwidgetstack.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>1</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753</data> + </image> +</images> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kbugbuster/gui/cwbuglistcontainer.cpp b/kbugbuster/gui/cwbuglistcontainer.cpp new file mode 100644 index 00000000..0188a996 --- /dev/null +++ b/kbugbuster/gui/cwbuglistcontainer.cpp @@ -0,0 +1,328 @@ +/* + 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 <qpushbutton.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qwidgetstack.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( QWidget *parent , const char * name ) + : QWidget( parent, name ), m_find(0), m_findItem(0) +{ + QBoxLayout *topLayout = new QVBoxLayout( this ); + topLayout->setSpacing( KDialog::spacingHint() ); + topLayout->setMargin( KDialog::marginHint() ); + + m_listLabel = new QLabel( this ); + topLayout->addWidget( m_listLabel ); + topLayout->setStretchFactor( m_listLabel, 0 ); + + QFont f = m_listLabel->font(); + f.setBold( true ); + m_listLabel->setFont( f ); + + m_listStack = new QWidgetStack( 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( "Status" ) ); + 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( QListView::Extended ); // needed for merging bugs + + m_listBugs->restoreLayout( KBBPrefs::instance()->config(), "BugListLayout" ); + + connect( m_listBugs, SIGNAL( executed( QListViewItem * ) ), + SLOT( execute( QListViewItem * ) ) ); + connect( m_listBugs, SIGNAL( returnPressed( QListViewItem * ) ), + SLOT( execute( QListViewItem * ) ) ); + connect( m_listBugs, SIGNAL( currentChanged( QListViewItem * ) ), + SLOT( changeCurrent( QListViewItem * ) ) ); + + // Fill WidgetStack in Outstanding Bugs pane + m_listLoading = new CWLoadingWidget( CWLoadingWidget::TopFrame, + m_listStack ); + connect( m_listLoading, SIGNAL( clicked() ), SIGNAL( searchPackage() ) ); + + m_listStack->addWidget( m_listBugs, 0 ); + m_listStack->addWidget( m_listLoading, 1 ); + + setNoList(); + + connect( BugSystem::self(), SIGNAL( bugListLoading( const Package &, const QString & ) ), + SLOT( setLoading( const Package &, const QString & ) ) ); + connect( BugSystem::self(), SIGNAL( bugListLoading( const QString & ) ), + SLOT( setLoading( const QString & ) ) ); + connect( BugSystem::self(), SIGNAL( bugListCacheMiss( const Package & ) ), + SLOT( setCacheMiss( const Package & ) ) ); + connect( BugSystem::self(), SIGNAL( bugListCacheMiss( const QString & ) ), + SLOT( setCacheMiss( const QString & ) ) ); + connect( BugSystem::self(), SIGNAL( commandQueued( BugCommand * ) ), + SLOT( markBugCommand( BugCommand * ) ) ); + connect( BugSystem::self(), SIGNAL( commandCanceled( const QString & ) ), + SLOT( clearCommand( const QString & ) ) ); +} + +CWBugListContainer::~CWBugListContainer() +{ + m_listBugs->saveLayout( KBBPrefs::instance()->config(), "BugListLayout" ); + KBBPrefs::instance()->writeConfig(); + delete m_find; +} + +void CWBugListContainer::setBugList( const QString &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)" ).arg( label ).arg( noBugs ).arg( noWishes ) ); + m_listStack->raiseWidget( 0 ); +} + +void CWBugListContainer::setBugList( const Package &package, const QString &component, const Bug::List &bugs ) +{ + QString listLabel; + if ( component.isEmpty() ) + { + if ( package.components().count() > 1 ) + listLabel = i18n( "Product '%1', all components" ).arg( package.name() ); + else + listLabel = i18n( "Product '%1'" ).arg( package.name() ); + } + else + { + listLabel = i18n( "Product '%1', component '%2'" ).arg( package.name(), component ); + } + + setBugList( listLabel, bugs ); +} + +void CWBugListContainer::execute( QListViewItem *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( QListViewItem *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 QString &component ) +{ + if ( component.isEmpty() ) + setLoading( i18n( "Retrieving List of Outstanding Bugs for Product '%1'..." ).arg( package.name() ) ); + else + setLoading( i18n( "Retrieving List of Outstanding Bugs for Product '%1' (Component %2)..." ).arg( package.name(), component ) ); +} + +void CWBugListContainer::setLoading( const QString &label ) +{ + m_listLoading->setText( label ); + m_listStack->raiseWidget( 1 ); +} + +void CWBugListContainer::setCacheMiss( const Package &package ) +{ + setCacheMiss( i18n( "Package '%1'" ).arg( package.name() ) ); +} + +void CWBugListContainer::setCacheMiss( const QString &label ) +{ + m_listLoading->setText( i18n( "%1 is not available offline." ).arg( 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 QString &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 QString& pattern ) +{ + m_find = new KFind( pattern, options, this ); + // Connect signals to code which handles highlighting + // of found text. + connect(m_find, SIGNAL( highlight( const QString &, int, int ) ), + this, SLOT( searchHighlight( const QString &, int, int ) ) ); + connect(m_find, SIGNAL( findNext() ), this, 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_find->needData() ) + m_find->setData( m_findItem->text(2) ); + + // Let KFind inspect the text fragment, and display a dialog if a match is found + res = m_find->find(); + + if ( res == KFind::NoMatch ) { + if ( m_find->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_find->shouldRestart() ) { + m_findItem = (BugLVI *)m_listBugs->firstChild(); + slotFindNext(); + } else { + delete m_find; + m_find = 0L; + } +} + +void CWBugListContainer::searchHighlight( const QString &, int, int ) +{ + if ( m_findItem ) { + m_listBugs->clearSelection(); + m_listBugs->setSelected( m_findItem, true ); + m_listBugs->ensureItemVisible( m_findItem ); + } +} + +QStringList CWBugListContainer::selectedBugs() const +{ + QStringList 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: */ diff --git a/kbugbuster/gui/cwbuglistcontainer.h b/kbugbuster/gui/cwbuglistcontainer.h new file mode 100644 index 00000000..bcda4c15 --- /dev/null +++ b/kbugbuster/gui/cwbuglistcontainer.h @@ -0,0 +1,99 @@ +/* + cwbuglistcontainer.h - 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. * + * * + ************************************************************************* +*/ + +#ifndef KBBMAINWINDOW_CWBUGLISTCONTAINER_H +#define KBBMAINWINDOW_CWBUGLISTCONTAINER_H + +#include "package.h" +#include "bug.h" + +#include <qwidget.h> + +class KListView; +class KFind; +class BugCommand; +class BugLVI; + +namespace KBugBusterMainWindow +{ + +class CWLoadingWidget; + +/** + * @author Martijn Klingens + */ +class CWBugListContainer : public QWidget +{ + Q_OBJECT + +public: + CWBugListContainer( QWidget* parent = 0, const char* name = 0 ); + ~CWBugListContainer(); + + void setBugList( const Package &package, const QString &component, const Bug::List &bugs ); + + /** + * Overloaded method that takes a QString for the label. To be used when the + * bug list doesn't belong to a package, liek search results + */ + void setBugList( const QString &label, const Bug::List &bugs ); + + void searchBugByTitle( int options, const QString& pattern ); + + /** Return list of selected bugs in the listview. Used for merging. */ + QStringList selectedBugs() const; + +public slots: + void setNoList(); + void setLoading( const Package &package, const QString &component ); + void setLoading( const QString &label ); + void setCacheMiss( const Package &package ); + void setCacheMiss( const QString &label ); + void slotFindNext(); + +signals: + void resetProgressBar(); + void searchPackage(); + + void executed( const Bug & ); + void currentChanged( const Bug & ); + +private slots: + void execute( QListViewItem * ); + void changeCurrent( QListViewItem * ); + + void markBugCommand( BugCommand * ); + void clearCommand( const QString & ); + + void searchHighlight( const QString &, int, int ); + +private: + QLabel *m_listLabel; + QWidgetStack *m_listStack; + + KListView *m_listBugs; + KFind *m_find; + BugLVI *m_findItem; + + CWLoadingWidget *m_listLoading; +}; + +} // namespace + +#endif + +/* vim: set et ts=4 softtabstop=4 sw=4: */ + diff --git a/kbugbuster/gui/cwloadingwidget.cpp b/kbugbuster/gui/cwloadingwidget.cpp new file mode 100644 index 00000000..ddd218a5 --- /dev/null +++ b/kbugbuster/gui/cwloadingwidget.cpp @@ -0,0 +1,256 @@ +/* + cwloadingwidget.cpp - Widget to be shown while loading data + + 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 "cwloadingwidget.h" + +#include <qpainter.h> +#include <qpixmap.h> +#include <kpixmap.h> +#include <kpixmapeffect.h> + +#include <kstandarddirs.h> +#include <klocale.h> +#include <kglobalsettings.h> + +using namespace KBugBusterMainWindow; + +CWLoadingWidget::CWLoadingWidget( WidgetMode mode, QWidget *parent, + const char * name ) +: QFrame( parent, name ) +{ + init( mode ); +} + +CWLoadingWidget::CWLoadingWidget( const QString &text, WidgetMode mode, + QWidget *parent, const char * name ) +: QFrame( parent, name ) +{ + init( mode ); + setText( text ); +} + +void CWLoadingWidget::init( WidgetMode mode ) +{ + m_mode = mode; + + QPalette pal = palette(); + pal.setColor( QPalette::Active, QColorGroup::Background, + QColor( 49, 121, 173 ) ); + pal.setColor( QPalette::Inactive, QColorGroup::Background, + QColor( 49, 121, 173 ) ); + pal.setColor( QPalette::Disabled, QColorGroup::Background, + QColor( 49, 121, 173 ) ); + setPalette( pal ); + + setFrameShape( StyledPanel ); + setFrameShadow( Sunken ); + setLineWidth( 2 ); + + setBackgroundMode( NoBackground ); // no flicker + + // Load images and prepare pixmap effect + if( m_mode == TopFrame ) + { + m_logoPixmap = + new QPixmap( locate( "data", "kbugbuster/pics/logo.png" ) ); + m_topRightPixmap = + new QPixmap( locate( "data", "kbugbuster/pics/top-right.png" ) ); + m_barsPixmap = + new QPixmap( locate( "data", "kbugbuster/pics/bars.png" ) ); + m_toolsPixmap = 0L; + m_toolsPixmapEffect = 0L; + } + else + { + m_toolsPixmap = + new QPixmap( locate( "data", "kbugbuster/pics/tools.png" ) ); + + m_toolsPixmapEffect = new KPixmap( m_toolsPixmap->size() ); + + QPainter pb; + pb.begin( m_toolsPixmapEffect ); + pb.fillRect( 0, 0, m_toolsPixmap->width(), m_toolsPixmap->height(), + QBrush( QColor( 49, 121, 172 ) ) ); + pb.drawPixmap( 0, 0, *m_toolsPixmap ); + pb.end(); + + KPixmapEffect::fade( *m_toolsPixmapEffect, 0.75, white ); + + m_logoPixmap = 0L; + m_topRightPixmap = 0L; + m_barsPixmap = 0L; + } + + // Create and fill the buffer + m_buffer = new QPixmap; +} + +void CWLoadingWidget::resizeEvent( QResizeEvent * ) +{ + updatePixmap(); +} + +void CWLoadingWidget::setText( const QString &text ) +{ + m_text = text; + updatePixmap(); + repaint(); +} + +void CWLoadingWidget::updatePixmap() +{ + QRect cr = contentsRect(); + cr.setWidth( cr.width() + 2 ); + cr.setHeight( cr.height() + 2 ); + m_buffer->resize( cr.width(), cr.height() ); + + QPainter p( m_buffer ); + + // fill background + p.fillRect( 0, 0, cr.width(), cr.height(), + QBrush( QColor( 49, 121, 173 ) ) ); + + if( m_mode == TopFrame ) + { + QFont bigFont = QFont( KGlobalSettings::generalFont().family(), + 28, QFont::Bold, true ); + + int xoffset = m_logoPixmap->width(); + + // Draw bars tiled + int xpos = xoffset; + if( width() > xpos ) + p.drawTiledPixmap( xpos, 0, cr.width() - xpos, + m_barsPixmap->height(), *m_barsPixmap ); + + // Draw logo + p.drawPixmap(width() - m_topRightPixmap->width(), 0, *m_topRightPixmap); + p.drawPixmap( 0, 0, *m_logoPixmap ); + + // Draw title text + p.setPen( black ); + p.drawText( 150, 84, cr.width() - 150, 108 - 84, + AlignAuto | AlignVCenter, m_text ); + + // Draw intro text + QString desc = i18n( "Welcome to KBugBuster, a tool to manage the " + "KDE Bug Report System. With KBugBuster you can " + "manage outstanding bug reports for KDE from a " + "convenient front end." ); + p.setPen( black ); + p.drawText( 28, 128, cr.width() - 28, 184 - 128, + AlignAuto | AlignVCenter | WordBreak, desc ); + + // Draw the caption text + QString caption = i18n( "KBugBuster" ); + p.setFont( bigFont ); + p.setPen( QColor(139, 183, 222) ); + p.drawText( 220, 60, caption ); + p.setPen( black ); + p.drawText( 217, 57, caption ); + } + else + { + // draw tools image + if( cr.height() <= 24 ) + return; + + int toolsEffectY = cr.height() - m_toolsPixmap->height(); + int toolsEffectX = cr.width() - m_toolsPixmap->width(); + if ( toolsEffectX < 0) + toolsEffectX = 0; + if ( height() < 24 + m_toolsPixmap->height() ) + toolsEffectY = 24; + + p.drawPixmap( toolsEffectX, toolsEffectY, *m_toolsPixmap ); + + // draw textbox + if( cr.height() <= 24 + 50 ) + return; + + int fheight = fontMetrics().height(); + + int boxX = 25; + int boxY = 24 + 50; + int boxW = cr.width() - 2 * boxX - 2 * 10; + if( boxW > 500 ) + boxW = 500; + + QRect br = fontMetrics().boundingRect( boxX, boxY, + boxW, cr.height() - boxY - 10 - 2 * fheight, + AlignAuto | AlignTop | WordBreak, m_text ); + + QRect box = br; + box.setHeight( box.height() + 2 * fheight ); + box.setWidth( box.width() + 2 * 10 ); + if( box.width() < cr.width() - 2 * boxX ) + box.setWidth( QMIN( cr.width() - 2 * boxX, 500 + 2 * 10 ) ); + if( box.height() < 100 ) + box.setHeight( QMIN( cr.height() - boxY - 2 * fheight - 10, 100 ) ); + + p.setClipRect( box ); + p.fillRect( box, QBrush( QColor( 204, 222, 234 ) ) ); + p.drawPixmap( toolsEffectX, toolsEffectY, *m_toolsPixmapEffect ); + + p.setViewport( box ); + p.setWindow( 0, 0, box.width(), box.height() ); + + p.drawText( 10, fheight, br.width(), + QMAX( br.height(), box.height() - 2 * fheight ), + AlignAuto | AlignVCenter | WordBreak, m_text ); + } +} + +CWLoadingWidget::~CWLoadingWidget() +{ + if( m_toolsPixmap ) + delete m_toolsPixmap; + if( m_logoPixmap ) + delete m_logoPixmap; + if( m_topRightPixmap ) + delete m_topRightPixmap; + if( m_barsPixmap ) + delete m_barsPixmap; + if( m_toolsPixmapEffect ) + delete m_toolsPixmapEffect; + + delete m_buffer; + + m_toolsPixmap = 0L; + m_logoPixmap = 0L; + m_topRightPixmap = 0L; + m_barsPixmap = 0L; + m_toolsPixmapEffect = 0L; + m_buffer = 0L; +} + +void CWLoadingWidget::mouseReleaseEvent( QMouseEvent * ) +{ + emit clicked(); +} + +void CWLoadingWidget::drawContents( QPainter *p ) +{ + if( !m_buffer || m_buffer->isNull() ) + p->fillRect( contentsRect(), QBrush( QColor( 255, 121, 172 ) ) ); + else + p->drawPixmap( QPoint( contentsRect().x(), contentsRect().y()), + *m_buffer, contentsRect() ); +} + +#include "cwloadingwidget.moc" + +/* vim: set et ts=4 sw=4 softtabstop=4: */ diff --git a/kbugbuster/gui/cwloadingwidget.h b/kbugbuster/gui/cwloadingwidget.h new file mode 100644 index 00000000..17c91f05 --- /dev/null +++ b/kbugbuster/gui/cwloadingwidget.h @@ -0,0 +1,87 @@ +/* + cwloadingwidget.h - Widget to be shown while loading data + + begin : sun march 18 17:12:24 CET 2001 + 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. * + * * + ************************************************************************* +*/ + +#ifndef KBBMAINWINDOW_CWLOADINGWIDGET_H +#define KBBMAINWINDOW_CWLOADINGWIDGET_H + +#include <qlabel.h> +#include <qframe.h> + +class QPixmap; +class KPixmap; + +namespace KBugBusterMainWindow +{ + +/** + * @author Martijn Klingens + */ +class CWLoadingWidget : public QFrame +{ + Q_OBJECT + +public: + /** + * Use WidgetMode to specify the layout for the background images + * TopFrame loads and uses the logo and horizontal bars, + * BottomFrame loads the tools and the translucent block. + */ + enum WidgetMode { TopFrame = 0, BottomFrame }; + + CWLoadingWidget( WidgetMode mode = TopFrame, QWidget* parent = 0, + const char* name = 0 ); + CWLoadingWidget( const QString &text, WidgetMode mode = TopFrame, + QWidget* parent = 0, const char* name = 0 ); + ~CWLoadingWidget(); + + QString text() const { return m_text; } + void setText( const QString &text ); + +protected: + virtual void mouseReleaseEvent( QMouseEvent * ); + virtual void drawContents( QPainter *p ); + virtual void resizeEvent( QResizeEvent * ); + +signals: + void clicked(); + +private: + void init( WidgetMode mode ); + void updatePixmap(); + + QString m_text; + WidgetMode m_mode; + + // Pixmaps used + QPixmap *m_toolsPixmap; + QPixmap *m_logoPixmap; + QPixmap *m_topRightPixmap; + QPixmap *m_barsPixmap; + + // For performance reasons we apply the KPixmapEffect only once + KPixmap *m_toolsPixmapEffect; + + QPixmap *m_buffer; + +}; + +} // namespace + +#endif // KBBMAINWINDOW_CWLOADINGWIDGET_H + +/* vim: set et ts=4 softtabstop=4 sw=4: */ + diff --git a/kbugbuster/gui/cwsearchwidget.cpp b/kbugbuster/gui/cwsearchwidget.cpp new file mode 100644 index 00000000..8f7fcb26 --- /dev/null +++ b/kbugbuster/gui/cwsearchwidget.cpp @@ -0,0 +1,69 @@ +/* + cwsearchwidget.cpp - Search Pane + + 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 <qpushbutton.h> +#include <klocale.h> +#include <kdialog.h> +#include <qlineedit.h> +#include <qlayout.h> +#include <kcombobox.h> +#include <qlabel.h> + +#include "cwsearchwidget.h" + +using namespace KBugBusterMainWindow; + +CWSearchWidget::CWSearchWidget( QWidget *parent , const char * name ) +: CWSearchWidget_Base( parent, name ) +{ + // Set fonts and margins + CWSearchWidget_BaseLayout->setSpacing( KDialog::spacingHint() ); + CWSearchWidget_BaseLayout->setMargin( KDialog::marginHint() ); + + QFont f = m_searchLabel->font(); + f.setBold( true ); + m_searchLabel->setFont( f ); + + connect( m_searchDesc, SIGNAL( textChanged ( const QString & ) ), + this, SLOT( textDescriptionChanged ( const QString & ) ) ); + + connect( m_searchBugNumber, SIGNAL( textChanged ( const QString & ) ), + this, SLOT( textNumberChanged ( const QString & ) ) ); + + m_searchDescBtn->setEnabled( !m_searchDesc->text().isEmpty() ); + m_searchBugNumberBtn->setEnabled( !m_searchBugNumber->text().isEmpty() ); + +// m_searchPackages->setCompletionMode( KGlobalSettings::CompletionAuto ); +} + +CWSearchWidget::~CWSearchWidget() +{ +} + +void CWSearchWidget::textDescriptionChanged ( const QString &_text ) +{ + m_searchDescBtn->setEnabled( !_text.isEmpty() ); +} + +void CWSearchWidget::textNumberChanged ( const QString &_text ) +{ + m_searchBugNumberBtn->setEnabled( !_text.isEmpty() ); +} + +#include "cwsearchwidget.moc" + +/* vim: set et ts=4 sw=4 softtabstop=4: */ + diff --git a/kbugbuster/gui/cwsearchwidget.h b/kbugbuster/gui/cwsearchwidget.h new file mode 100644 index 00000000..4cf65720 --- /dev/null +++ b/kbugbuster/gui/cwsearchwidget.h @@ -0,0 +1,46 @@ +/* + cwsearchwidget.h - Search Pane + + 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. * + * * + ************************************************************************* +*/ + +#ifndef KBBMAINWINDOW_CWSEARCHWIDGET_H +#define KBBMAINWINDOW_CWSEARCHWIDGET_H + +#include "cwsearchwidget_base.h" + +namespace KBugBusterMainWindow +{ + +/** + * @author Martijn Klingens + */ +class CWSearchWidget : public CWSearchWidget_Base +{ + Q_OBJECT + +public: + CWSearchWidget( QWidget* parent = 0, const char* name = 0 ); + ~CWSearchWidget(); + +public slots: + void textNumberChanged ( const QString & ); + void textDescriptionChanged ( const QString & ); +}; + +} // namespace + +#endif + +/* vim: set et ts=4 softtabstop=4 sw=4: */ + diff --git a/kbugbuster/gui/cwsearchwidget_base.ui b/kbugbuster/gui/cwsearchwidget_base.ui new file mode 100644 index 00000000..c5e9b860 --- /dev/null +++ b/kbugbuster/gui/cwsearchwidget_base.ui @@ -0,0 +1,198 @@ +<!DOCTYPE UI><UI version="3.0" stdsetdef="1"> +<class>CWSearchWidget_Base</class> +<widget class="QWidget"> + <property name="name"> + <cstring>CWSearchWidget_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>165</width> + <height>266</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_searchLabel</cstring> + </property> + <property name="text"> + <string>Search</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel2</cstring> + </property> + <property name="text"> + <string>&Package:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_searchPackages</cstring> + </property> + </widget> + <widget class="KComboBox"> + <property name="name"> + <cstring>m_searchPackages</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="editable"> + <bool>true</bool> + </property> + <property name="insertionPolicy"> + <enum>NoInsertion</enum> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel9</cstring> + </property> + <property name="text"> + <string>Bug &number:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_searchBugNumber</cstring> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout17</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_searchBugNumber</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_searchBugNumberBtn</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string></string> + </property> + <property name="pixmap"> + <pixmap>image0</pixmap> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel7</cstring> + </property> + <property name="text"> + <string>&Description:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_searchDesc</cstring> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout15</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_searchDesc</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_searchDescBtn</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string></string> + </property> + <property name="pixmap"> + <pixmap>image0</pixmap> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + </spacer> + </vbox> +</widget> +<images> + <image name="image0"> + <data format="XPM.GZ" length="1725">789c75d4594fdb401405e0777e4584df5075b0e325b6aa3eb015ca1e76a8fa309ea518ca9eb055fdef9d39774815447311e4c3c73377c6cbfc5cef6477ab37373ff33052a34ef7f4b9baefcd99f1d5d5cbf71f5f7ecfcc6655cfff544daf3ffb69667638eae9def6cdb50d40e791a4fc04274aac7df1f840ecfc87bea3b350b4a5fba1787e420f42f1f8906e42d16b741b8a6e691b8a7e09e6f0323fc7eb0f42d179706e956a739afde62e146dde5cc8f93ab8487d49bf2774def65b4d1f0797b96e4c416f0757a9ceb4a1fb74ad2b23e73fd146175acecf68e7cdfe13ae87cb97fc0a9de94a8e23a52bdd9a92de129b8195f51cd1b5a9a3bfd28d56b1bf92567e3ed9bf535aeb26f67b41bbba5fcbfcb7c1755ae735af0f76e8526b23aee846d746f6eb9056a6b5d2df01ddfafee4f832ed8cb3355d0437a9298df4f318dd18b91e9b746933abe8bd60559b2caeff3adaca7c0968632a23f9fd6863a5df1bb12de2fc67b4f579997f8976b671d2ef46709b5a65a59f57baf2fdc97ed57463fc90f46a741bd7fb4c2babe3f963da5ae3647fcf8375660a53b17fde6f3a0fc5e3eb623fbfdc2f5774691b2bf335b4f2c7a59f5dda581dfb77b435b591e76731d8a42e73b27f0b74e9fa4eee8f6ff4c09696fde0e7c4b25fbf68edf3d2df88b6ae74f27c5d065b3e40f47d7411f30fb472ad53f23291420285f64df17f7a387acbc0c0c2e127ced1c14ce724e31317b8c42f5ce11a37fe7b4ce116b793cc1deef18011c678c4139ed1c5840e25ef0fbc62c12716b18465ace02b56b136c924f24ec137acfb3136b0892d6c6307bb18c655243217d6b0877d1ce0104738c6094e7126b34df5dcf9515264e8fb44eebf77ff59d718054a54feef853f67f03ec354871a4d82b03f18f8dfddfb0c73774982bbe12851e89236d16fa9c9387aea0a74d0ff5253e3e88f53b167eef9bbab3949c97b45f6fce319a732c9fb91980a73fdf93cf317e4bbac85</data> + </image> +</images> +<includes> + <include location="global" impldecl="in declaration">kcombobox.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kbugbuster/gui/kbbbookmarkmanager.h b/kbugbuster/gui/kbbbookmarkmanager.h new file mode 100644 index 00000000..64edfc24 --- /dev/null +++ b/kbugbuster/gui/kbbbookmarkmanager.h @@ -0,0 +1,23 @@ +#ifndef KBBBOOKMARKMANAGER_H +#define KBBBOOKMARKMANAGER_H + +#include <kbookmarkmanager.h> +#include <kstandarddirs.h> + +class KBBBookmarkManager +{ +public: + static KBookmarkManager * self() { + if ( !s_bookmarkManager ) + { + QString bookmarksFile = locateLocal("data", QString::fromLatin1("kbugbuster/bookmarks.xml")); + s_bookmarkManager = KBookmarkManager::managerForFile( bookmarksFile ); + } + return s_bookmarkManager; + } + + + static KBookmarkManager *s_bookmarkManager; +}; + +#endif diff --git a/kbugbuster/gui/kbbmainwindow.cpp b/kbugbuster/gui/kbbmainwindow.cpp new file mode 100644 index 00000000..66a9b588 --- /dev/null +++ b/kbugbuster/gui/kbbmainwindow.cpp @@ -0,0 +1,504 @@ +/*************************************************************************** + kbbmainwindow.cpp - description + ------------------- + 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 "kbbmainwindow.h" + +#include <qlabel.h> +#include <qlayout.h> +#include <qmultilineedit.h> +#include <qprogressbar.h> +#include <qpushbutton.h> +#include <qtextview.h> +#include <qwidgetstack.h> + +#include <kaction.h> +#include <kbookmarkmenu.h> +#include <kcombobox.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kdialog.h> +#include <kinputdialog.h> +#include <klineedit.h> +#include <klistview.h> +#include <klocale.h> +#include <kmenubar.h> +#include <kmessagebox.h> +#include <kstatusbar.h> +#include <kstdaction.h> +#include <kstdguiitem.h> +#include <kedittoolbar.h> + + +#include "bugcommand.h" +#include "bugserver.h" +#include "bugserverconfig.h" +#include "bugsystem.h" +#include "centralwidget.h" +#include "cwbugdetails.h" +#include "kbbbookmarkmanager.h" +#include "kbbprefs.h" +#include "kfinddialog.h" +#include "packageselectdialog.h" +#include "preferencesdialog.h" + +#define ID_STATUS_MSG 1 + +using namespace KBugBusterMainWindow; + +class TextViewer : public KDialogBase +{ + public: + TextViewer( const QString &title, QWidget *parent = 0 ) + : KDialogBase( Plain, title, Ok, Ok, parent, 0, + false ) + { + QFrame *topFrame = plainPage(); + + QBoxLayout *topLayout = new QVBoxLayout( topFrame ); + + mTextView = new QTextEdit( topFrame ); + mTextView->setReadOnly( true ); + mTextView->setTextFormat( PlainText ); + topLayout->addWidget( mTextView ); + + resize( 600, 400 ); + } + + void setText( const QString &text ) + { + mTextView->setText( text ); + } + + private: + QTextEdit *mTextView; +}; + +KBookmarkManager* KBBBookmarkManager::s_bookmarkManager; + +KBBMainWindow::KBBMainWindow( const QCString &initialPackage, + const QCString &initialComponent, + const QCString &initialBug, + QWidget * , const char * name ) + : KMainWindow( 0, name ), mPreferencesDialog( 0 ), mResponseViewer( 0 ), + mBugSourceViewer( 0 ), mPackageSelectDialog( 0 ) +{ + BugSystem::self()->setCurrentServer( KBBPrefs::instance()->mCurrentServer ); + + m_statusLabel = new QLabel( i18n( "Welcome to <b>KBugBuster</b>." ), statusBar() ); + m_statusLabel->setMaximumHeight( statusBar()->fontMetrics().height() + 6 ); + m_statusLabel->setIndent( KDialog::marginHint() / 2 ); + statusBar()->addWidget( m_statusLabel, 1 ); + + m_mainWidget = new CentralWidget( initialPackage, initialComponent, + initialBug, this ); + setCentralWidget( m_mainWidget ); + + initActions(); + + m_progressBar = new QProgressBar( 100, statusBar() ); + m_progressBar->setCenterIndicator( true ); + m_progressBar->setMinimumWidth( 150 ); + m_progressBar->setMaximumHeight( statusBar()->fontMetrics().height() + 6 ); + statusBar()->addWidget( m_progressBar ); + connect( m_mainWidget, SIGNAL( resetProgressBar() ), + m_progressBar, SLOT( reset() ) ); + connect( m_mainWidget, SIGNAL( searchPackage() ), + this, SLOT( searchPackage() ) ); + connect( m_mainWidget, SIGNAL( searchBugNumber() ), + this, SLOT( searchBugNumber() ) ); + + connect( BugSystem::self(), SIGNAL( infoMessage( const QString & ) ), + SLOT( slotStatusMsg( const QString & ) ) ); + + connect( BugSystem::self(), SIGNAL( infoMessage( const QString & ) ), + SLOT( slotStatusMsg( const QString & ) ) ); + connect( BugSystem::self(), SIGNAL( infoPercent( unsigned long ) ), + SLOT( slotSetPercent( unsigned long ) ) ); + + m_mainWidget->readConfig(); +} + +KBBMainWindow::~KBBMainWindow() +{ +// kdDebug() << "KBBMainWindow::~KBBMainWindow()" << endl; + delete m_pBookmarkMenu; + + m_mainWidget->writeConfig(); + + KBBPrefs::instance()->writeConfig(); +} + +void KBBMainWindow::initActions() +{ + // Prepare and create XML GUI + fileQuit = KStdAction::quit( this, + SLOT( close() ), actionCollection() ); + fileQuit->setToolTip( i18n( "Quit KBugBuster" ) ); + + new KAction( i18n("See &Pending Changes"), "contents", 0, this, SLOT( slotListChanges() ), + actionCollection(), "file_seechanges" ); + new KAction( i18n("&Submit Changes"), "mail_send", 0, this, SLOT( slotSubmit() ), + actionCollection(), "file_submit" ); + + reloadpacklist = new KAction( i18n("Reload &Product List"), "reload", CTRL+Qt::Key_F5, m_mainWidget, SLOT( slotReloadPackageList() ), + actionCollection(), "reload_packagelist" ); + reloadpack= new KAction( i18n("Reload Bug &List (for current product)"), "reload", Qt::Key_F5, m_mainWidget, SLOT( slotReloadPackage() ), + actionCollection(), "reload_package" ); + reloadbug = new KAction( i18n("Reload Bug &Details (for current bug)"), "reload", SHIFT+Qt::Key_F5, m_mainWidget, SLOT( slotReloadBug() ), + actionCollection(), "reload_bug" ); + loadMyBugs = new KAction( i18n( "Load &My Bugs List" ), 0, m_mainWidget, SLOT( slotLoadMyBugs() ), + actionCollection(), "load_my_bugs" ); + reloadall = new KAction( i18n("Load All Bug Details (for current product)"), Qt::Key_F6, m_mainWidget, SLOT( slotRetrieveAllBugDetails() ), actionCollection(), "load_allbugs" ); + new KAction( i18n("Extract &Attachments"), "filesave", Qt::Key_F4, m_mainWidget, SLOT( slotExtractAttachments() ), + actionCollection(), "extract_attachments" ); + + new KAction( i18n("Clear Cache"), 0, this, SLOT( clearCache() ), + actionCollection(), "clear_cache" ); + + new KAction( i18n("&Search by Product..."), "goto", CTRL+Qt::Key_P, this, + SLOT( searchPackage() ), actionCollection(), "search_package" ); + new KAction( i18n("Search by Bug &Number..."), "filefind", CTRL+Qt::Key_N, this, + SLOT( searchBugNumber() ), actionCollection(), "search_bugnumber" ); + // For now "Description" searches by title. Maybe later we can have a + // full-text search interfacing bugs.kde.org and rename the current one to "By Title". + new KAction( i18n("Search by &Description...") ,"find", CTRL+Qt::Key_D, this, + SLOT( searchDescription() ), actionCollection(), "search_description" ); + +// new KAction( i18n("&Merge"), "view_remove", CTRL+Qt::Key_M, m_mainWidget, +// SLOT( mergeBugs() ), actionCollection(), "cmd_merge" ); +// new KAction( i18n("&Unmerge"), "view_top_bottom", CTRL+SHIFT+Qt::Key_M, m_mainWidget, +// SLOT( unmergeBugs() ), actionCollection(), "cmd_unmerge" ); + new KAction( i18n("C&lose..."), "edittrash", CTRL+Qt::Key_L, m_mainWidget, + SLOT( closeBug() ), actionCollection(), "cmd_close" ); +// new KAction( i18n("Clos&e Silently"), "edittrash", CTRL+Qt::Key_E, m_mainWidget, +// SLOT( closeBugSilently() ), actionCollection(), "cmd_close_silently" ); + new KAction( i18n("Re&open"), "idea", CTRL+Qt::Key_O, m_mainWidget, + SLOT( reopenBug() ), actionCollection(), "cmd_reopen" ); +// new KAction( i18n("Re&assign..."), "folder_new", CTRL+Qt::Key_A, m_mainWidget, +// SLOT( reassignBug() ), actionCollection(), "cmd_reassign" ); +// new KAction( i18n("Change &Title..."), "text_under", CTRL+Qt::Key_T, m_mainWidget, +// SLOT( titleBug() ), actionCollection(), "cmd_title" ); +// new KAction( i18n("Change &Severity..."), "edit", CTRL+Qt::Key_S, m_mainWidget, +// SLOT( severityBug() ), actionCollection(), "cmd_severity" ); + new KAction( i18n("&Reply..."), "mail_replyall",CTRL+Qt::Key_R , m_mainWidget, + SLOT( replyBug() ), actionCollection(), "cmd_reply" ); + new KAction( i18n("Reply &Privately..."), "mail_reply", CTRL+Qt::Key_I, m_mainWidget, + SLOT( replyPrivateBug() ), actionCollection(), "cmd_replyprivate" ); + + KStdAction::showMenubar(this, SLOT( slotToggleMenubar() ), actionCollection() ); +#if KDE_IS_VERSION( 3, 1, 90 ) + createStandardStatusBarAction(); + setStandardToolBarMenuEnabled(true); +#endif + + m_disconnectedAction = new KToggleAction( i18n("&Disconnected Mode"), 0, + this, + SLOT( slotDisconnectedAction() ), + actionCollection(), + "settings_disconnected" ); + m_disconnectedAction->setChecked( BugSystem::self()->disconnected() ); + + // Bookmarks menu + m_pamBookmarks = new KActionMenu( i18n( "&Bookmarks" ), "bookmark", actionCollection(), "bookmarks" ); + m_pBookmarkMenu = new KBookmarkMenu( KBBBookmarkManager::self(), this, m_pamBookmarks->popupMenu(), actionCollection(), true ); + + KStdAction::preferences( this, SLOT(preferences()), actionCollection() ); + + KToggleAction *toggleTmp = new KToggleAction( i18n("Show Closed Bugs"), "recycled", 0, this, SLOT( slotToggleDone() ), + actionCollection(), "cmd_toggle_done" ); +#if KDE_IS_VERSION( 3, 2, 90 ) + toggleTmp->setCheckedState(i18n("Hide Closed Bugs")); +#endif + toggleTmp->setChecked( KBBPrefs::instance()->mShowClosedBugs ); + + toggleTmp =new KToggleAction( i18n("Show Wishes"), "bookmark", 0, this, SLOT( slotToggleWishes() ), + actionCollection(), "cmd_toggle_wishes" ); +#if KDE_IS_VERSION( 3, 2, 90 ) + toggleTmp->setCheckedState(i18n("Hide Wishes")); +#endif + toggleTmp->setChecked(KBBPrefs::instance()->mShowWishes); + + mSelectServerAction = new KSelectAction( i18n( "Select Server" ), 0, 0, + this, + SLOT( slotSelectServer() ), + actionCollection(), + "select_server" ); + + setupSelectServerAction(); + + if ( KBBPrefs::instance()->mDebugMode ) { + new KAction( i18n("Show Last Server Response..."), 0 , this, + SLOT( showLastResponse() ), actionCollection(), + "debug_lastresponse" ); + new KAction( i18n("Show Bug HTML Source..."), 0 , this, + SLOT( showBugSource() ), actionCollection(), + "debug_showbugsource" ); + } + +#if KDE_IS_VERSION( 3, 2, 90 ) + setupGUI( (ToolBar | Keys | StatusBar | Save | Create ), "kbugbusterui.rc" ); +#else + createGUI(); +#endif +} + +void KBBMainWindow::slotToggleMenubar() +{ + if ( !hasMenuBar() ) + return; + + if ( menuBar()->isVisible() ) + menuBar()->hide(); + else + menuBar()->show(); +} + +void KBBMainWindow::setupSelectServerAction() +{ + QStringList servers; + int current = -1; + QValueList<BugServer *> serverList = BugSystem::self()->serverList(); + QValueList<BugServer *>::ConstIterator it; + for ( it = serverList.begin(); it != serverList.end(); ++it ) { + QString name = (*it)->serverConfig().name(); + servers.append( name ); + if ( name == KBBPrefs::instance()->mCurrentServer ) { + current = servers.count() - 1; + } + } + mSelectServerAction->setItems( servers ); + if ( current >= 0 ) { + mSelectServerAction->setCurrentItem( current ); + } +} + +QString KBBMainWindow::currentURL() const +{ + QString number=m_mainWidget->currentNumber(); + + if (number.isEmpty()) + return ""; + else + return "bug:"+number; +} + +QString KBBMainWindow::currentTitle() const +{ + return "#"+m_mainWidget->currentNumber()+": "+m_mainWidget->currentTitle(); +} + +void KBBMainWindow::openBookmarkURL( const QString & url ) +{ + if ( url.left(4)=="bug:" ) { + QString bugnumber = url.mid(4); + m_mainWidget->slotRetrieveBugDetails( Bug::fromNumber( bugnumber ) ); + } +} + +// --- SLOT IMPLEMENTATIONS ------------------------------------------------- + +void KBBMainWindow::slotDisconnectedAction() +{ + BugSystem::self()->setDisconnected( m_disconnectedAction->isChecked() ); + + bool enable = !m_disconnectedAction->isChecked(); + + reloadpacklist->setEnabled( enable ); + reloadpacklist->setEnabled( enable ); + reloadpack->setEnabled( enable ); + reloadbug->setEnabled( enable ); + reloadall->setEnabled( enable ); + loadMyBugs->setEnabled( enable ); +} + +void KBBMainWindow::slotStatusMsg( const QString &text ) +{ + // Change status message permanently + m_statusLabel->setText( text ); +} + +void KBBMainWindow::slotSubmit() +{ + BugSystem::self()->sendCommands(); +} + +void KBBMainWindow::slotListChanges() +{ + QStringList list = BugSystem::self()->server()->listCommands(); + + if (list.count() > 0) + { + int ret = KMessageBox::questionYesNoList( this, i18n("List of pending commands:"), + list, QString::null, KStdGuiItem::clear(), KStdGuiItem::close() ); + if ( ret == KMessageBox::Yes ) + { + // Ask for confirmation, it's too easy to click the wrong button in the above dlg box + if ( KMessageBox::warningContinueCancel( this, i18n("Do you really want to delete all commands?"), + i18n("Confirmation Required"), KGuiItem( i18n("&Delete"), "editdelete"), "clearcommands", true) + == KMessageBox::Continue ) + BugSystem::self()->clearCommands(); + } + } + else + { + KMessageBox::information( this, i18n("There are no pending commands.") ); + } +} + +void KBBMainWindow::slotSetPercent( unsigned long percent ) +{ + // KIO::Job::percent() shouldn't return an unsigned long. - Frerich + m_progressBar->setProgress( percent ); +} + +void KBBMainWindow::searchPackage() +{ + if ( !mPackageSelectDialog ) { + mPackageSelectDialog = new PackageSelectDialog( this ); + } + mPackageSelectDialog->setPackages( BugSystem::self()->packageList() ); + BugServerConfig cfg = BugSystem::self()->server()->serverConfig(); + QStringList recent = cfg.recentPackages(); + kdDebug() << "MainWindow RECENT: " << recent.join(",") << endl; + mPackageSelectDialog->setRecentPackages( recent ); + + mPackageSelectDialog->exec(); + Package package = mPackageSelectDialog->selectedPackage(); + + if ( package.isNull() ) { + return; + } + + QString component = mPackageSelectDialog->selectedComponent(); + m_mainWidget->slotRetrieveBugList( package.name(), component ); +} + +void KBBMainWindow::searchBugNumber() +{ + bool ok = false; + QString result = KInputDialog::getText( i18n("Search for Bug Number"), + i18n("Please enter a bug number:"), + QString::null, &ok, this ); + if ( ok ) { + //Strip whitespace and # if needed + result = result.stripWhiteSpace(); + if (result[0]=='#') + result = result.mid(1); + } + + if ( ok && !result.isEmpty()) { + // ### bad way to instantiate a bug! doesn't get us the details! + // Right - but do we need the details in this case ? There's no listview entry here... (DF) + m_mainWidget->slotRetrieveBugDetails( Bug::fromNumber( result ) ); + } +} + +void KBBMainWindow::searchDescription() +{ + kdDebug() << "KBBMainWindow::searchDescription()." << endl; + //KMessageBox::sorry(this,i18n("searchDescription(): to be implemented."),i18n("Not implemented")); + KFindDialog dlg( this ); + if ( dlg.exec() == KDialogBase::Accepted ) + m_mainWidget->searchBugByTitle( dlg.options(), dlg.pattern() ); +} + +bool KBBMainWindow::queryClose() +{ + if ( ! BugSystem::self()->server()->commandsPending() ) return true; + + int result = KMessageBox::warningYesNoCancel(this,i18n("There are unsent bug commands." + " Do you want to send them now?"), QString::null, i18n("Send"), i18n("Do Not Send")); + if ( result == KMessageBox::Cancel ) return false; + if ( result == KMessageBox::Yes ) { + BugSystem::self()->sendCommands(); + } + return true; +} + +void KBBMainWindow::preferences() +{ + if (!mPreferencesDialog) { + mPreferencesDialog = new PreferencesDialog(this); + connect( mPreferencesDialog, SIGNAL( configChanged() ), + SLOT( setupSelectServerAction() ) ); + connect( mPreferencesDialog, SIGNAL( configChanged() ), + m_mainWidget, SLOT( slotReloadPackage() ) ); + } + mPreferencesDialog->show(); + mPreferencesDialog->raise(); +} + +void KBBMainWindow::updatePackage() +{ + m_mainWidget->updatePackage(); +} + +void KBBMainWindow::slotToggleDone() +{ + KBBPrefs::instance()->mShowClosedBugs=!(KBBPrefs::instance()->mShowClosedBugs); + updatePackage(); +} + +void KBBMainWindow::slotToggleWishes() +{ + KBBPrefs::instance()->mShowWishes=!(KBBPrefs::instance()->mShowWishes); + updatePackage(); +} + +void KBBMainWindow::slotSelectServer() +{ + m_mainWidget->writeConfig(); + + QString currentServer = mSelectServerAction->currentText(); + + BugSystem::self()->setCurrentServer( currentServer ); + + m_mainWidget->initialize(); +} + +void KBBMainWindow::showLastResponse() +{ + if ( !mResponseViewer ) { + mResponseViewer = new TextViewer( i18n("Last Server Response"), this ); + } + + mResponseViewer->setText( BugSystem::lastResponse() ); + + mResponseViewer->show(); + mResponseViewer->raise(); +} + +void KBBMainWindow::showBugSource() +{ + if ( !mBugSourceViewer ) { + mBugSourceViewer = new TextViewer( i18n("Bug HTML Source"), this ); + } + + mBugSourceViewer->setText( m_mainWidget->bugDetailsWidget()->source() ); + + mBugSourceViewer->show(); + mBugSourceViewer->raise(); +} + +void KBBMainWindow::clearCache() +{ + BugSystem::self()->server()->cache()->clear(); +} + +#include "kbbmainwindow.moc" + +/* vim: set et ts=4 sw=4 softtabstop=4: */ + diff --git a/kbugbuster/gui/kbbmainwindow.h b/kbugbuster/gui/kbbmainwindow.h new file mode 100644 index 00000000..f139c733 --- /dev/null +++ b/kbugbuster/gui/kbbmainwindow.h @@ -0,0 +1,144 @@ +/* + kbbmainwindow.h - KBugBuster's main window + + Copyright (c) 2001-2004 by Martijn Klingens <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. * + * * + ************************************************************************* +*/ + +#ifndef KBBMAINWINDOW_H +#define KBBMAINWINDOW_H + +#include <kapplication.h> +#include <kbookmarkmanager.h> +#include <kmainwindow.h> +#include <qmap.h> + +#include "package.h" +#include "bug.h" +#include "bugdetails.h" + +class KAction; +class KActionMenu; +class KBookmarkMenu; +class KToggleAction; +class KSelectAction; +class QLabel; +class QListViewItem; +class QProgressBar; +class PreferencesDialog; +class TextViewer; +class PackageSelectDialog; + +namespace KBugBusterMainWindow +{ + class CentralWidget; +} + +/** + * @author Martijn Klingens + */ +class KBBMainWindow : public KMainWindow, virtual public KBookmarkOwner +{ + Q_OBJECT + public: + /** + * construtor of KBugBusterApp, calls all init functions to create the application. + */ + KBBMainWindow( const QCString &initialPackage = "", + const QCString &initialCpomponent = "", + const QCString &initialBug = "", + QWidget* parent = 0, const char* name = 0 ); + ~KBBMainWindow(); + + /// Overloaded functions of KBookmarkOwner + virtual void openBookmarkURL( const QString & _url ); + virtual QString currentTitle() const; + virtual QString currentURL() const; + + public slots: + /** + * Event handlers for our KActions + */ + void slotStatusMsg( const QString &text ); + void slotDisconnectedAction(); + void slotSubmit(); + void slotListChanges(); + void slotSetPercent( unsigned long percent ); + void slotSelectServer(); + + void showLastResponse(); + void showBugSource(); + + void clearCache(); + + /** + * Other event handlers + */ + + void searchPackage(); + void searchBugNumber(); + void searchDescription(); + + void preferences(); + void updatePackage(); + void slotToggleDone(); + void slotToggleWishes(); + + protected: + virtual bool queryClose(); + + protected slots: + void setupSelectServerAction(); + void slotToggleMenubar(); + + private: + void initActions(); + + /** + * Our main widget + */ + KBugBusterMainWindow::CentralWidget *m_mainWidget; + + /** + * Used KActions + */ + KAction *fileQuit; + KAction *reloadpacklist; + KAction *reloadpack; + KAction *reloadbug; + KAction *reloadall; + KAction *loadMyBugs; + KToggleAction *m_disconnectedAction; + + /** + * Status bar label. We need this, because the default Qt version doesn't + * support rich text in the messages + */ + QLabel *m_statusLabel; + QProgressBar *m_progressBar; + + PreferencesDialog *mPreferencesDialog; + + KActionMenu *m_pamBookmarks; + KBookmarkMenu* m_pBookmarkMenu; + + KSelectAction *mSelectServerAction; + + TextViewer *mResponseViewer; + TextViewer *mBugSourceViewer; + + PackageSelectDialog *mPackageSelectDialog; +}; + +#endif + +/* vim: set et ts=4 softtabstop=4 sw=4: */ + diff --git a/kbugbuster/gui/kbugbusterui.rc b/kbugbuster/gui/kbugbusterui.rc new file mode 100644 index 00000000..f347855c --- /dev/null +++ b/kbugbuster/gui/kbugbusterui.rc @@ -0,0 +1,78 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui name="kbugbuster" version="11"> + +<MenuBar> + <Menu name="file" noMerge="1"><text>&File</text> + <Action name="file_new_window" /> + <Action name="file_seechanges" /> + <Action name="file_submit" /> + <Separator/> + <Action name="file_quit" /> + </Menu> + <Menu name="view"><text>&View</text> + <Action name="reload_packagelist" /> + <Action name="reload_package" /> + <Action name="reload_bug" /> + <Separator/> + <Action name="load_my_bugs" /> + <Action name="load_allbugs" /> + <Separator/> + <Action name="extract_attachments" /> + <Separator/> + <Action name="clear_cache" /> + <Separator/> + <Action name="debug_lastresponse" /> + <Action name="debug_showbugsource" /> + </Menu> + <Menu name="search"><text>S&earch</text> + <Action name="search_package" /> + <Action name="search_bugnumber" /> + <Action name="search_description" /> + </Menu> + <Action name="bookmarks"/> + <Menu name="commands"><text>&Commands</text> + <!-- <Action name="cmd_merge" /> + <Action name="cmd_unmerge" /> + <Separator/> --> + <Action name="cmd_close" /> + <Action name="cmd_close_silently" /> + <Action name="cmd_reopen" /> + <Action name="cmd_reassign" /> + <Action name="cmd_title" /> + <Action name="cmd_severity" /> + <Separator/> + <Action name="cmd_reply" /> + <Action name="cmd_replyprivate" /> + </Menu> + <Menu name="settings"><text>&Settings</text> + <Action name="settings_disconnected" append="save_merge"/> + <Action name="select_server" append="save_merge"/> + </Menu> +</MenuBar> + +<ToolBar name="searchToolBar"><text>Search Toolbar</text> + <Action name="search_package" /> + <Action name="search_bugnumber" /> + <Action name="search_description" /> +</ToolBar> + +<ToolBar name="commandToolBar"><text>Command Toolbar</text> + <Action name="cmd_merge" /> + <Action name="cmd_unmerge" /> + <Separator/> + <Action name="cmd_close" /> + <Action name="cmd_reopen" /> + <Action name="cmd_reassign" /> + <Action name="cmd_title" /> + <Action name="cmd_severity" /> + <Separator/> + <Action name="cmd_reply" /> + <Action name="cmd_replyprivate" /> +</ToolBar> + +<ToolBar name="settingToolBar"><text>Settings Toolbar</text> + <Action name="cmd_toggle_wishes" /> + <Action name="cmd_toggle_done" /> +</ToolBar> + +</kpartgui> diff --git a/kbugbuster/gui/loadallbugsdlg.cpp b/kbugbuster/gui/loadallbugsdlg.cpp new file mode 100644 index 00000000..40ecd6d8 --- /dev/null +++ b/kbugbuster/gui/loadallbugsdlg.cpp @@ -0,0 +1,92 @@ +/*************************************************************************** + loadallbugsdlg.cpp - progress dialog while loading all bugs for a package + ------------------- + copyright : (C) 2002 by David Faure + email : david@mandrakesoft.com + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 version 2. * + * * + ***************************************************************************/ + +#include "loadallbugsdlg.h" +#include "bugsystem.h" +#include "bugcache.h" +#include <kdebug.h> +#include <kio/defaultprogress.h> +#include <qtimer.h> + +LoadAllBugsDlg::LoadAllBugsDlg( const Package& pkg, const QString &component ) + : QDialog( 0L, "progressdlg", TRUE ) +{ + m_bugLoadingProgress = new KIO::DefaultProgress( this ); + connect( m_bugLoadingProgress, SIGNAL( stopped() ), + this, SLOT( slotStopped() ) ); + setCaption( i18n( "Loading All Bugs for Product %1" ).arg( pkg.name() ) ); + connect( BugSystem::self(), + SIGNAL( bugDetailsAvailable( const Bug &, const BugDetails & ) ), + SLOT( slotBugDetailsAvailable( const Bug &, const BugDetails & ) ) ); + connect( BugSystem::self(), + SIGNAL( bugDetailsLoadingError() ), + SLOT( slotBugDetailsLoadingError() ) ); + // The package (and its buglist) has to be in the cache already... + m_bugs = BugSystem::self()->cache()->loadBugList( pkg, component, true ); + m_count = m_bugs.count(); + m_bugLoadingProgress->slotTotalSize( 0, m_count ); + kdDebug() << "LoadAllBugsDlg: " << m_count << " bugs to load" << endl; + m_processed = 0; + QTimer::singleShot( 0, this, SLOT( loadNextBug() ) ); +} + +void LoadAllBugsDlg::slotBugDetailsAvailable( const Bug &bug, const BugDetails & ) +{ + kdDebug() << "LoadAllBugsDlg::slotBugDetailsAvailable " << bug.number() << endl; + m_bugLoadingProgress->slotInfoMessage( 0L, i18n( "Bug %1 loaded" ).arg(bug.number()) ); + loadNextBug(); +} + +void LoadAllBugsDlg::slotBugDetailsLoadingError() +{ + // Abort at the first error. Otherwise we get spammed with "no host bugs.kde.org" msg boxes.... + reject(); +} + +void LoadAllBugsDlg::loadNextBug() +{ + kdDebug() << "LoadAllBugsDlg::loadNextBug" << endl; + if ( m_bugs.isEmpty() ) + { + kdDebug() << "LoadAllBugsDlg::loadNextBug DONE!" << endl; + accept(); + } else { + BugCache* cache = BugSystem::self()->cache(); + Bug bug; + do { + bug = m_bugs.front(); + m_bugs.pop_front(); + m_processed++; + m_bugLoadingProgress->slotPercent( 0L, (100 * m_processed) / m_count ); + kdDebug() << "looking at bug " << bug.number() << " in cache:" << cache->hasBugDetails( bug ) << endl; + } while ( cache->hasBugDetails( bug ) && !m_bugs.isEmpty() ); + if ( !cache->hasBugDetails( bug ) ) { + kdDebug() << "LoadAllBugsDlg::loadNextBug loading bug " << bug.number() << endl; + BugSystem::self()->retrieveBugDetails( bug ); + } else { + kdDebug() << "LoadAllBugsDlg::loadNextBug DONE!" << endl; + accept(); + } + } +} + +void LoadAllBugsDlg::slotStopped() +{ + kdDebug() << "LoadAllBugsDlg::slotStopped" << endl; + // TODO abort job? + reject(); +} + +#include "loadallbugsdlg.moc" diff --git a/kbugbuster/gui/loadallbugsdlg.h b/kbugbuster/gui/loadallbugsdlg.h new file mode 100644 index 00000000..685abcb0 --- /dev/null +++ b/kbugbuster/gui/loadallbugsdlg.h @@ -0,0 +1,43 @@ +/*************************************************************************** + loadallbugsdlg.h - progress dialog while loading all bugs for a package + ------------------- + copyright : (C) 2002 by David Faure + email : david@mandrakesoft.com + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 version 2. * + * * + ***************************************************************************/ +#ifndef loadallbugsdlg_h +#define loadallbugsdlg_h + +#include <qdialog.h> +#include "bug.h" +class Package; +class BugDetails; + +namespace KIO { class DefaultProgress; } + +class LoadAllBugsDlg : public QDialog +{ + Q_OBJECT +public: + LoadAllBugsDlg( const Package& pkg, const QString &component ); + +protected slots: + void slotBugDetailsAvailable( const Bug &bug, const BugDetails &bd ); + void slotBugDetailsLoadingError(); + void slotStopped(); + void loadNextBug(); +private: + Bug::List m_bugs; + unsigned int m_processed; + unsigned int m_count; + KIO::DefaultProgress* m_bugLoadingProgress; +}; + +#endif diff --git a/kbugbuster/gui/messageeditor.cpp b/kbugbuster/gui/messageeditor.cpp new file mode 100644 index 00000000..517ef80b --- /dev/null +++ b/kbugbuster/gui/messageeditor.cpp @@ -0,0 +1,117 @@ +#include <qcombobox.h> +#include <ktextedit.h> +#include <kinputdialog.h> +#include <qlayout.h> +#include <qlabel.h> + +#include <klocale.h> +#include <kmessagebox.h> +#include <kdebug.h> + +#include "kbbprefs.h" + +#include "messageeditor.h" +#include <qpushbutton.h> +#include "messageeditor.moc" + +MessageEditor::MessageEditor( QWidget *parent ) + : KDialogBase(Plain,i18n("Edit Message Buttons"),Ok|Cancel,Ok,parent,0, + true,true) +{ + QFrame *topFrame = plainPage(); + QBoxLayout *topLayout = new QVBoxLayout(topFrame,0,spacingHint()); + + QBoxLayout *selectionLayout = new QHBoxLayout; + topLayout->addLayout(selectionLayout); + + QLabel *selectionLabel = new QLabel(i18n("Button:"),topFrame); + selectionLayout->addWidget(selectionLabel); + + mSelectionCombo = new QComboBox(topFrame); + selectionLayout->addWidget(mSelectionCombo); + connect(mSelectionCombo,SIGNAL(activated(int)),SLOT(changeMessage())); + + QPushButton *addButton = new QPushButton(i18n("Add Button..."),topFrame); + selectionLayout->addWidget(addButton); + connect(addButton,SIGNAL(clicked()),SLOT(addButton())); + + QPushButton *removeButton = new QPushButton(i18n("Remove Button"),topFrame); + selectionLayout->addWidget(removeButton); + connect(removeButton,SIGNAL(clicked()),SLOT(removeButton())); + + mMessageEdit = new KTextEdit(topFrame); + topLayout->addWidget(mMessageEdit,1); + + updateConfig(); +} + +void MessageEditor::updateConfig() +{ + mMessageButtons = KBBPrefs::instance()->mMessageButtons; + + mSelectionCombo->clear(); + + QMap<QString,QString>::ConstIterator it; + for(it = mMessageButtons.begin();it != mMessageButtons.end();++it) { + mSelectionCombo->insertItem(it.key()); + } + + updateMessage(); +} + +void MessageEditor::addButton() +{ + QString txt; + txt = KInputDialog::getText(i18n("Add Message Button"), + i18n("Enter button name:"), QString::null, + NULL, this ); + + if ( !txt.isNull() ) { + saveMessage(); + mSelectionCombo->insertItem(txt); + mMessageButtons.insert(txt,""); + mSelectionCombo->setCurrentItem(mSelectionCombo->count()-1); + updateMessage(); + } + +} + +void MessageEditor::removeButton() +{ + int result = KMessageBox::warningContinueCancel(this, + i18n("Remove the button %1?").arg(mSelectionCombo->currentText()), + i18n("Remove"), KGuiItem( i18n("Delete"), "editdelete") ); + + if (result == KMessageBox::Continue) { + mMessageButtons.remove(mSelectionCombo->currentText()); + mSelectionCombo->removeItem(mSelectionCombo->currentItem()); + mSelectionCombo->setCurrentItem(0); + updateMessage(); + } +} + +void MessageEditor::changeMessage() +{ + saveMessage(); + updateMessage(); +} + +void MessageEditor::updateMessage() +{ + mCurrentButton = mSelectionCombo->currentText(); + + mMessageEdit->setText(mMessageButtons[mCurrentButton]); +} + +void MessageEditor::saveMessage() +{ + mMessageButtons.replace(mCurrentButton,mMessageEdit->text()); +} + +void MessageEditor::slotOk() +{ + saveMessage(); + + KBBPrefs::instance()->mMessageButtons = mMessageButtons; + accept(); +} diff --git a/kbugbuster/gui/messageeditor.h b/kbugbuster/gui/messageeditor.h new file mode 100644 index 00000000..e32e8cec --- /dev/null +++ b/kbugbuster/gui/messageeditor.h @@ -0,0 +1,33 @@ +#ifndef MESSAGEEDITOR_H +#define MESSAGEEDITOR_H + +#include <kdialogbase.h> + +class QComboBox; +class KTextEdit; + +class MessageEditor : public KDialogBase { + Q_OBJECT + public: + MessageEditor( QWidget *parent ); + + protected slots: + void slotOk(); + + private slots: + void addButton(); + void removeButton(); + void changeMessage(); + void saveMessage(); + void updateMessage(); + void updateConfig(); + + private: + QComboBox *mSelectionCombo; + KTextEdit *mMessageEdit; + + QString mCurrentButton; + QMap <QString,QString> mMessageButtons; +}; + +#endif diff --git a/kbugbuster/gui/msginputdialog.cpp b/kbugbuster/gui/msginputdialog.cpp new file mode 100644 index 00000000..a3fc39c7 --- /dev/null +++ b/kbugbuster/gui/msginputdialog.cpp @@ -0,0 +1,226 @@ +// $Id$ +// (c) 2001, Cornelius Schumacher + +#include <ktextedit.h> +#include <qlayout.h> + +#include <klocale.h> +#include <kdebug.h> +#include <qcombobox.h> +#include <qsplitter.h> +#include <qlabel.h> + +#include "messageeditor.h" +#include "kbbprefs.h" +#include "bugsystem.h" +#include "bugcommand.h" + +#include "msginputdialog.h" +#include "msginputdialog.moc" + +MsgInputDialog::MsgInputDialog(MsgInputDialog::MessageType type, const Bug &bug, + const Package &package, const QString "edMsg, + QWidget *parent) + : KDialogBase(Plain,QString::null,User1|User2|Ok|Cancel,Ok,parent,0,false, + true,KStdGuiItem::clear(),i18n( "&Edit Presets..." )), + mBug( bug ), + mPackage( package ), + mType( type ) +{ + switch ( mType ) { + case Close: + setCaption( i18n("Close Bug %1").arg( mBug.number() ) ); + break; + case Reply: + setCaption( i18n("Reply to Bug") ); + break; + case ReplyPrivate: + setCaption( i18n("Reply Privately to Bug") ); + break; + default: + break; + } + + QFrame *topFrame = plainPage(); + ( new QHBoxLayout( topFrame ) )->setAutoAdd( true ); + + mSplitter = new QSplitter( QSplitter::Horizontal, topFrame ); + + QWidget *w = new QWidget( mSplitter ); + ( new QVBoxLayout( w, spacingHint(), -1 ) )->setAutoAdd( true ); + + if ( mType == Reply ) { + QWidget *r = new QWidget( w ); + QHBoxLayout* rlayout = new QHBoxLayout( r ); + + QLabel *rlabel = new QLabel( i18n("&Recipient:"),r ); + QFont f = r->font(); + f.setBold( true ); + r->setFont( f ); + rlayout->add( rlabel ); + + mRecipient = new QComboBox( r ); + mRecipient->insertItem( i18n("Normal (bugs.kde.org & Maintainer & kde-bugs-dist)"), BugCommand::Normal ); + mRecipient->insertItem( i18n("Maintonly (bugs.kde.org & Maintainer)"), BugCommand::Maintonly ); + mRecipient->insertItem( i18n("Quiet (bugs.kde.org only)"), BugCommand::Quiet ); + rlabel->setBuddy( mRecipient ); + rlayout->add( mRecipient ); + + QSpacerItem *rspacer= new QSpacerItem( 1,1,QSizePolicy::Expanding ); + rlayout->addItem( rspacer ); + + // Reply currently only replies to the bug tracking system + r->hide(); + } + + + QLabel *l = new QLabel( i18n( "&Message" ), w ); + QFont f = l->font(); + f.setBold( true ); + l->setFont( f ); + + mMessageEdit = new KTextEdit( w ); + mMessageEdit->setMinimumWidth( mMessageEdit->fontMetrics().width('x') * 72 ); + mMessageEdit->setWordWrap( QTextEdit::FixedColumnWidth ); + mMessageEdit->setWrapColumnOrWidth( 72 ); + l->setBuddy( mMessageEdit ); + + w = new QWidget( mSplitter ); + ( new QVBoxLayout( w, spacingHint(), -1 ) )->setAutoAdd( true ); + l = new QLabel( i18n( "&Preset Messages" ), w ); + l->setFont( f ); + + mPresets = new KListBox( w ); + updatePresets(); + l->setBuddy( mPresets ); + + connect( mPresets, SIGNAL( executed( QListBoxItem* ) ), + SLOT( slotPresetSelected( QListBoxItem * ) ) ); + connect( this, SIGNAL( user2Clicked() ), SLOT( editPresets() ) ); + connect( this, SIGNAL( user1Clicked() ), SLOT( clearMessage() ) ); + mMessageEdit->setFocus(); + + if ( !quotedMsg.isEmpty() ) + insertQuotedMessage( quotedMsg ); + + readConfig(); +} + +MsgInputDialog::~MsgInputDialog() +{ + kdDebug() << "MsgInputDialog::~MsgInputDialog()" << endl; + writeConfig(); +} + +void MsgInputDialog::readConfig() +{ + resize( KBBPrefs::instance()->mMsgDlgWidth, + KBBPrefs::instance()->mMsgDlgHeight ); + QValueList<int> sizes = KBBPrefs::instance()->mMsgDlgSplitter; + mSplitter->setSizes( sizes ); +} + +void MsgInputDialog::writeConfig() +{ + KBBPrefs::instance()->mMsgDlgWidth = width(); + KBBPrefs::instance()->mMsgDlgHeight = height(); + KBBPrefs::instance()->mMsgDlgSplitter = mSplitter->sizes(); +} + +void MsgInputDialog::updatePresets() +{ + mPresets->clear(); + + QMap<QString,QString> messageButtons = KBBPrefs::instance()->mMessageButtons; + + int id = 0; + QMap<QString,QString>::ConstIterator it; + for( it = messageButtons.begin(); it != messageButtons.end(); ++it ) + mPresets->insertItem( it.key(), id ); +} + +QString MsgInputDialog::message() const +{ + return mMessageEdit->text(); +} + +void MsgInputDialog::editPresets() +{ + MessageEditor *dlg = new MessageEditor(this); + dlg->exec(); + delete dlg; + + updatePresets(); +} + +void MsgInputDialog::slotPresetSelected( QListBoxItem *lbi ) +{ + mMessageEdit->setText( KBBPrefs::instance()->mMessageButtons[ lbi->text() ] ); +} + +void MsgInputDialog::clearMessage() +{ + mMessageEdit->setText(""); +} + +void MsgInputDialog::queueCommand() +{ + switch ( mType ) { + case Close: + BugSystem::self()->queueCommand( + new BugCommandClose( mBug, message(), mPackage ) ); + break; + case Reply: + BugSystem::self()->queueCommand( + new BugCommandReply( mBug, message(), mRecipient->currentItem() ) ); + break; + case ReplyPrivate: + BugSystem::self()->queueCommand( + new BugCommandReplyPrivate( mBug, mBug.submitter().email, + message() ) ); + break; + default: + break; + } +} + +void MsgInputDialog::slotOk() +{ + queueCommand(); + delete this; +} + +void MsgInputDialog::slotCancel() +{ + delete this; +} + +void MsgInputDialog::insertQuotedMessage( const QString &msg ) +{ + Q_ASSERT( mMessageEdit->wordWrap() == QTextEdit::FixedColumnWidth ); + + const QString quotationMarker = "> "; + const unsigned int wrapColumn = mMessageEdit->wrapColumnOrWidth(); + + // ### Needs something more sophisticated than simplifyWhiteSpace to + // handle quoting multiple paragraphs properly. + QString line = msg.simplifyWhiteSpace(); + + QString quotedMsg; + while ( line.length() + quotationMarker.length() + 1 > wrapColumn ) { + int pos = wrapColumn - quotationMarker.length() - 1; + while ( pos > 0 && !line[ pos ].isSpace() ) + --pos; + if ( pos == 0 ) + pos = wrapColumn; + quotedMsg += quotationMarker + line.left( pos ) + "\n"; + line = line.mid( pos + 1 ); + } + quotedMsg += quotationMarker + line + "\n\n"; + + mMessageEdit->setText( quotedMsg ); + + const int lastPara = mMessageEdit->paragraphs() - 1; + const int lastParaLen = mMessageEdit->paragraphLength( lastPara ) - 1; + mMessageEdit->setCursorPosition( lastPara, lastParaLen ); +} diff --git a/kbugbuster/gui/msginputdialog.h b/kbugbuster/gui/msginputdialog.h new file mode 100644 index 00000000..9de767e3 --- /dev/null +++ b/kbugbuster/gui/msginputdialog.h @@ -0,0 +1,55 @@ +#ifndef MSGINPUTDIALOG_H +#define MSGINPUTDIALOG_H + +#include <kdialogbase.h> + +#include "bug.h" +#include "package.h" + +class KTextEdit; +class QSplitter; +class KListBox; + +class MsgInputDialog : public KDialogBase +{ + Q_OBJECT + public: + enum MessageType{ Close, Reply, ReplyPrivate }; + + MsgInputDialog( MessageType, const Bug &, const Package &, + const QString &, QWidget *parent=0); + virtual ~MsgInputDialog(); + + QString message() const; + + protected slots: + void slotOk(); + void slotCancel(); + + private slots: + void editPresets(); + void updatePresets(); + void slotPresetSelected( QListBoxItem * ); + void clearMessage(); + void queueCommand(); + + private: + void createButtons(); + void createLayout(); + + void readConfig(); + void writeConfig(); + + void insertQuotedMessage( const QString "edMsg ); + + QComboBox *mRecipient; + KTextEdit *mMessageEdit; + QSplitter *mSplitter; + KListBox *mPresets; + + Bug mBug; + Package mPackage; + MessageType mType; +}; + +#endif diff --git a/kbugbuster/gui/packagelvi.cpp b/kbugbuster/gui/packagelvi.cpp new file mode 100644 index 00000000..7fe7cfe6 --- /dev/null +++ b/kbugbuster/gui/packagelvi.cpp @@ -0,0 +1,38 @@ +/* + packagelvi.cpp - Custom QListViewItem that holds a Package object + + 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 "packagelvi.h" + +PackageLVI::PackageLVI( QListView *parent , const Package &pkg, const QString &component ) +: QListViewItem( parent, pkg.name(), pkg.description() ) +{ + m_package = pkg; + m_component = component; +} + +PackageLVI::PackageLVI( QListViewItem *parent , const Package &pkg, const QString &component ) +: QListViewItem( parent, component ) +{ + m_package = pkg; + m_component = component; +} + +PackageLVI::~PackageLVI() +{ +} + +/* vim: set et ts=4 sw=4 softtabstop=4: */ + diff --git a/kbugbuster/gui/packagelvi.h b/kbugbuster/gui/packagelvi.h new file mode 100644 index 00000000..32f48642 --- /dev/null +++ b/kbugbuster/gui/packagelvi.h @@ -0,0 +1,51 @@ +/* + packagelvi.h - Custom QListViewItem that holds a Package object + + 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. * + * * + ************************************************************************* +*/ + +#ifndef PACKAGELVI_H +#define PACKAGELVI_H + +#include <qlistview.h> + +#include "package.h" + +/** + * @author Martijn Klingens + */ +class PackageLVI : public QListViewItem +{ +public: + // Top-level package + PackageLVI( QListView *parent , const Package &pkg, const QString &component ); + // Child component + PackageLVI( QListViewItem *parent , const Package &pkg, const QString &component ); + + ~PackageLVI(); + + Package& package() { return m_package; } + void setPackage( const Package &pkg ) { m_package = pkg; } + + QString component() { return m_component; } + void setComponent( const QString &component ) { m_component = component; } + +private: + Package m_package; + QString m_component; +}; + +#endif // PACKAGELVI_H + +/* vim: set et ts=4 softtabstop=4 sw=4: */ + diff --git a/kbugbuster/gui/packageselectdialog.cpp b/kbugbuster/gui/packageselectdialog.cpp new file mode 100644 index 00000000..7b791e9d --- /dev/null +++ b/kbugbuster/gui/packageselectdialog.cpp @@ -0,0 +1,214 @@ +#include <qlistview.h> +#include <qlayout.h> +#include <qheader.h> + +#include <kdebug.h> +#include <kcompletion.h> +#include <klineedit.h> + +#include "bugsystem.h" +#include "kbbprefs.h" +#include "bugserver.h" + +#include "packagelvi.h" +#include "packageselectdialog.h" +#include "packageselectdialog.moc" + +PackageListView::PackageListView( QWidget *parent ) : + QListView( parent ) +{ + setFocusPolicy( QWidget::StrongFocus ); +} + +void PackageListView::resetTyped() +{ + mTyped = ""; +} + +void PackageListView::keyPressEvent( QKeyEvent *e ) +{ + // Disable listview text completion for now + QListView::keyPressEvent( e ); + return; + + int k = e->key(); + if ( k == Key_Return || k == Key_Escape ) e->ignore(); + + QString key = e->text(); + mTyped.append(key); + emit typed( mTyped ); +} + +PackageSelectDialog::PackageSelectDialog(QWidget *parent,const char *name) : + KDialogBase( parent, name, true, i18n("Select Product"), Ok|Cancel ) +{ + QWidget *topWidget = new QWidget( this ); + setMainWidget( topWidget ); + + QBoxLayout *topLayout = new QVBoxLayout( topWidget ); + QSplitter *topSplitter = new QSplitter( QSplitter::Vertical, topWidget ); + topSplitter->setOpaqueResize( true ); + + topLayout->addWidget( topSplitter ); + + mRecentList = new QListView( topSplitter ); + mRecentList->addColumn( i18n("Recent") ); + mRecentList->resize( mRecentList->width(), mRecentList->fontMetrics().height() * + KBBPrefs::instance()->mRecentPackagesCount ); + + connect( mRecentList, SIGNAL( mouseButtonPressed( int, QListViewItem *, const QPoint &, int) ), + SLOT( recentSelected( int, QListViewItem * ) ) ); + connect( mRecentList, SIGNAL( doubleClicked( QListViewItem * ) ), + SLOT( slotOk() ) ); + + mCompletion = new KCompletion; + mCompletion->setCompletionMode( KGlobalSettings::CompletionAuto ); + + mCompleteList = new PackageListView( topSplitter ); + mCompleteList->addColumn( i18n("Name") ); + mCompleteList->addColumn( i18n("Description") ); + mCompleteList->setRootIsDecorated(true); + mCompleteList->setAllColumnsShowFocus( true ); + connect( mCompleteList, SIGNAL( typed( const QString & ) ), + SLOT( completeTyped( const QString & ) ) ); + + + connect( mCompleteList, SIGNAL( mouseButtonPressed( int, QListViewItem *, const QPoint &, int) ), + SLOT( completeSelected( int, QListViewItem * ) ) ); + connect( mCompleteList, SIGNAL( doubleClicked( QListViewItem * ) ), + SLOT( slotOk() ) ); + + mPackageEdit = new KLineEdit( topWidget ); + mPackageEdit->setFocus(); + + topLayout->addWidget( mPackageEdit ); + connect( mPackageEdit, SIGNAL( textChanged( const QString & ) ), + SLOT( completeTyped( const QString & ) ) ); + enableButtonOK( !mPackageEdit->text().isEmpty() ); +} + +PackageSelectDialog::~PackageSelectDialog() +{ + delete mCompletion; +} + +void PackageSelectDialog::setRecentPackages( const QStringList &recent ) +{ + mRecentList->clear(); + QStringList::ConstIterator it; + for( it = recent.begin(); it != recent.end(); ++it ) { + new QListViewItem( mRecentList, *it ); + } +} + +void PackageSelectDialog::setPackages( const Package::List &pkgs ) +{ + mCompleteList->clear(); + mCompletion->clear(); + mCompletionDict.clear(); + Package::List::ConstIterator it; + for( it = pkgs.begin(); it != pkgs.end(); ++it ) { + PackageLVI *item = new PackageLVI( mCompleteList, (*it), QString::null ); + QStringList components = (*it).components(); + + if (components.count() > 1) { + for( QStringList::ConstIterator cit = components.begin(); cit != components.end(); ++cit ) { + PackageLVI *component = new PackageLVI( item, (*it), (*cit) ); + QString completionName = (*it).name() + "/" + (*cit); + + mCompletion->addItem( completionName ); + mCompletionDict.insert( completionName, component ); + } + } + + mCompletion->addItem( (*it).name() ); + mCompletionDict.insert((*it).name(),item); + } +} + +void PackageSelectDialog::recentSelected( int, QListViewItem *item ) +{ + kdDebug() << "PackageSelectDialog::recentSelected()" << endl; + if ( item ) { + mCompleteList->clearSelection(); + // Why does a QLineEdit->setText() call emit the textChanged() signal? + mPackageEdit->blockSignals( true ); + mPackageEdit->setText( item->text( 0 ) ); + enableButtonOK(true); + mPackageEdit->blockSignals( false ); + } +} + +void PackageSelectDialog::completeSelected( int, QListViewItem *item ) +{ + PackageLVI *lvi = dynamic_cast<PackageLVI*>(item); + + if ( lvi ) { + mRecentList->clearSelection(); + if ( lvi->component().isEmpty() ) { + mPackageEdit->setText( lvi->package().name() ); + } + else { + mPackageEdit->setText( lvi->package().name() + "/" + lvi->component() ); + } + } +} + +void PackageSelectDialog::slotOk() +{ + PackageLVI *item = (PackageLVI *)mCompleteList->selectedItem(); + if ( item ) { + mSelectedPackage = item->package(); + mSelectedComponent = item->component(); + + QString recent_key; + if ( item->component().isEmpty() ) + recent_key = item->package().name(); + else + recent_key = item->package().name() + "/" + item->component(); + + BugServer *server = BugSystem::self()->server(); + QStringList recent = server->serverConfig().recentPackages(); + if( !recent.contains( recent_key ) ) { + recent.prepend( recent_key ); + if ( int( recent.count() ) > KBBPrefs::instance()->mRecentPackagesCount ) { + recent.remove( recent.last() ); + } + kdDebug() << "RECENT: " << recent.join(",") << endl; + server->serverConfig().setRecentPackages( recent ); + } + } else { + QListViewItem *recentItem = mRecentList->selectedItem(); + if ( recentItem ) { + QStringList tokens = QStringList::split( '/', recentItem->text( 0 ) ); + mSelectedPackage = BugSystem::self()->package( tokens[0] ); + mSelectedComponent = tokens[1]; + } + } + mCompleteList->resetTyped(); + accept(); +} + +Package PackageSelectDialog::selectedPackage() +{ + return mSelectedPackage; +} + +QString PackageSelectDialog::selectedComponent() +{ + return mSelectedComponent; +} + +void PackageSelectDialog::completeTyped( const QString &typed ) +{ + kdDebug() << "completeTyped: " << typed << endl; + QString completed = mCompletion->makeCompletion( typed ); + kdDebug() << "completed: " << completed << endl; + if ( !completed.isEmpty() ) { + mCompleteList->setSelected( mCompletionDict[ completed ], true ); + mCompleteList->ensureItemVisible( mCompletionDict[ completed ] ); + } else { + mCompleteList->resetTyped(); + } + enableButtonOK( !typed.isEmpty() ); +} diff --git a/kbugbuster/gui/packageselectdialog.h b/kbugbuster/gui/packageselectdialog.h new file mode 100644 index 00000000..1fe596aa --- /dev/null +++ b/kbugbuster/gui/packageselectdialog.h @@ -0,0 +1,64 @@ +#ifndef PACKAGESELECTDIALOG_H +#define PACKAGESELECTDIALOG_H + +#include <qdict.h> + +#include <kdialogbase.h> + +#include "package.h" + +class KCompletion; +class KLineEdit; + +class PackageListView : public QListView +{ + Q_OBJECT + public: + PackageListView( QWidget *parent ); + + void resetTyped(); + + signals: + void typed( const QString & ); + + protected: + void keyPressEvent( QKeyEvent *e ); + + private: + QString mTyped; +}; + +class PackageSelectDialog : public KDialogBase +{ + Q_OBJECT + public: + PackageSelectDialog(QWidget *parent=0,const char *name=0); + ~PackageSelectDialog(); + + void setRecentPackages( const QStringList & ); + void setPackages( const Package::List &pkgs ); + + Package selectedPackage(); + QString selectedComponent(); + + protected slots: + void slotOk(); + + private slots: + void recentSelected( int, QListViewItem * ); + void completeSelected( int, QListViewItem * ); + void completeTyped( const QString & ); + + private: + Package::List mPackages; + Package mSelectedPackage; + QString mSelectedComponent; + + QListView *mRecentList; + PackageListView *mCompleteList; + KLineEdit *mPackageEdit; + KCompletion *mCompletion; + QDict<QListViewItem> mCompletionDict; +}; + +#endif diff --git a/kbugbuster/gui/preferencesdialog.cpp b/kbugbuster/gui/preferencesdialog.cpp new file mode 100644 index 00000000..9cafff28 --- /dev/null +++ b/kbugbuster/gui/preferencesdialog.cpp @@ -0,0 +1,306 @@ +#include <qradiobutton.h> +#include <qcheckbox.h> +#include <qlineedit.h> +#include <qpushbutton.h> +#include <qlayout.h> +#include <qgroupbox.h> +#include <qbuttongroup.h> +#include <qlistview.h> +#include <qhbox.h> + +#include <knuminput.h> +#include <kurl.h> +#include <kmessagebox.h> +#include <kiconloader.h> +#include <kdebug.h> + +#include "mailsender.h" +#include "kbbprefs.h" +#include "kbbmainwindow.h" +#include "serverconfigdialog.h" +#include "bugsystem.h" +#include "bugserver.h" +#include "bugserverconfig.h" + +#include "preferencesdialog.h" + +class ServerItem : public QListViewItem +{ + public: + ServerItem( QListView *listView, const BugServerConfig &cfg ) + : QListViewItem( listView ) + { + setServerConfig( cfg ); + } + + void setServerConfig( const BugServerConfig &cfg ) + { + mServerConfig = cfg; + setText( 0, cfg.name() ); + setText( 1, cfg.baseUrl().prettyURL() ); + setText( 2, cfg.user() ); + setText( 3, cfg.bugzillaVersion() ); + } + + const BugServerConfig &serverConfig() const { return mServerConfig; } + + private: + BugServerConfig mServerConfig; +}; + +class ServerListView : public QListView +{ + public: + ServerListView( QWidget *parent ) : QListView( parent ) + { + addColumn( i18n("Name") ); + addColumn( i18n("Base URL") ); + addColumn( i18n("User") ); + addColumn( i18n("Version") ); + } +}; + +PreferencesDialog::PreferencesDialog( QWidget* parent, const char* name ) + : KDialogBase ( IconList, i18n("Preferences"), Ok|Apply|Cancel, Ok, + parent, name, false, true ) +{ + setupServerPage(); + setupAdvancedPage(); + + readConfig(); +} + +PreferencesDialog::~PreferencesDialog() +{ +} + +void PreferencesDialog::setupServerPage() +{ + QFrame *topFrame = addPage( i18n("Servers"), 0, + DesktopIcon( "gohome", KIcon::SizeMedium ) ); + + QBoxLayout *layout = new QVBoxLayout( topFrame ); + layout->setSpacing( spacingHint() ); + + mServerList = new ServerListView( topFrame ); + layout->addWidget( mServerList ); + + QHBox *buttonBox = new QHBox( topFrame ); + buttonBox->setSpacing( spacingHint() ); + layout->addWidget( buttonBox ); + + QPushButton *addButton = new QPushButton( i18n("Add Server..."), buttonBox ); + connect( addButton, SIGNAL( clicked() ), SLOT( addServer() ) ); + + QPushButton *editButton = new QPushButton( i18n("Edit Server..."), buttonBox ); + connect( editButton, SIGNAL( clicked() ), SLOT( editServer() ) ); + + QPushButton *removeButton = new QPushButton( i18n("Delete Server"), buttonBox ); + connect( removeButton, SIGNAL( clicked() ), SLOT( removeServer() ) ); + + QPushButton *button = new QPushButton( i18n("Select Server From List..."), + topFrame ); + layout->addWidget( button ); + connect( button, SIGNAL( clicked() ), SLOT( selectServer() ) ); + connect( mServerList, SIGNAL( doubleClicked ( QListViewItem *)), this, SLOT( editServer())); +} + +void PreferencesDialog::setupAdvancedPage() +{ + QFrame *topFrame = addPage( i18n("Advanced"), 0, + DesktopIcon( "misc", KIcon::SizeMedium ) ); + + QBoxLayout *layout = new QVBoxLayout( topFrame ); + layout->setSpacing( spacingHint() ); + + QButtonGroup *mailGroup = new QButtonGroup( 1, Horizontal, + i18n( "Mail Client" ), topFrame ); + layout->addWidget( mailGroup ); + + mKMailButton = new QRadioButton( i18n( "&KMail" ), mailGroup ); + mDirectButton = new QRadioButton( i18n( "D&irect" ), mailGroup ); + mSendmailButton = new QRadioButton( i18n( "&Sendmail" ), mailGroup ); + + mShowClosedCheckBox = new QCheckBox( i18n( "Show closed bugs" ), topFrame ); + layout->addWidget( mShowClosedCheckBox ); + + mShowWishesCheckBox = new QCheckBox( i18n( "Show wishes" ), topFrame ); + layout->addWidget( mShowWishesCheckBox ); + + mShowVotedCheckBox = new QCheckBox( i18n( "Show bugs with number of votes greater than:" ), topFrame ); + layout->addWidget( mShowVotedCheckBox ); + + mMinVotesInput = new KIntNumInput( topFrame ); + mMinVotesInput->setMinValue( 0 ); + connect( mShowVotedCheckBox, SIGNAL(toggled(bool)), + mMinVotesInput, SLOT(setEnabled(bool)) ); + layout->addWidget( mMinVotesInput ); + + mSendBccCheckBox = new QCheckBox( i18n( "Send BCC to myself" ), topFrame ); + layout->addWidget( mSendBccCheckBox ); +} + +void PreferencesDialog::setDefaults() +{ + KBBPrefs::instance()->setDefaults(); + readConfig(); +} + +void PreferencesDialog::slotApply() +{ + writeConfig(); +} + +void PreferencesDialog::slotOk() +{ + writeConfig(); + accept(); +} + +void PreferencesDialog::slotCancel() +{ + hide(); +} + +void PreferencesDialog::addServer() +{ + ServerConfigDialog *dlg = new ServerConfigDialog( this ); + int result = dlg->exec(); + if ( result == QDialog::Accepted ) { + new ServerItem( mServerList, dlg->serverConfig() ); + } +} + +void PreferencesDialog::editServer() +{ + ServerItem *item = static_cast<ServerItem *>( mServerList->currentItem() ); + if ( !item ) return; + + ServerConfigDialog *dlg = new ServerConfigDialog( this ); + dlg->setServerConfig( item->serverConfig() ); + + int result = dlg->exec(); + if ( result == QDialog::Accepted ) { + item->setServerConfig( dlg->serverConfig() ); + } +} + +void PreferencesDialog::removeServer() +{ + QListViewItem *item = mServerList->currentItem(); + if ( !item ) return; + + delete item; +} + +void PreferencesDialog::selectServer() +{ + SelectServerDlg *dlg =new SelectServerDlg( this, "Select Server" ); + + int result = dlg->exec(); + if ( result == QDialog::Accepted ) { + ServerItem *item = dlg->serverSelected(); + if ( item ) { + new ServerItem( mServerList, item->serverConfig() ); + } + } + delete dlg; +} + +void PreferencesDialog::createServerItem( ServerListView *listView, + const QString &name, + const QString &url, + const QString &version ) +{ + BugServerConfig cfg( name, KURL( url ) ); + cfg.setBugzillaVersion( version ); + new ServerItem( listView, cfg ); +} + +void PreferencesDialog::readConfig() +{ + int client = KBBPrefs::instance()->mMailClient; + switch(client) { + default: + case MailSender::KMail: + mKMailButton->setChecked(true); + break; + case MailSender::Sendmail: + mSendmailButton->setChecked(true); + break; + case MailSender::Direct: + mDirectButton->setChecked(true); + break; + } + mShowClosedCheckBox->setChecked( KBBPrefs::instance()->mShowClosedBugs ); + mShowWishesCheckBox->setChecked( KBBPrefs::instance()->mShowWishes ); + mShowVotedCheckBox->setChecked( KBBPrefs::instance()->mShowVoted ); + mMinVotesInput->setValue( KBBPrefs::instance()->mMinVotes ); + mSendBccCheckBox->setChecked( KBBPrefs::instance()->mSendBCC ); + + mServerList->clear(); + QValueList<BugServer *> servers = BugSystem::self()->serverList(); + QValueList<BugServer *>::ConstIterator it; + for( it = servers.begin(); it != servers.end(); ++it ) { + new ServerItem( mServerList, (*it)->serverConfig() ); + } +} + +void PreferencesDialog::writeConfig() +{ + MailSender::MailClient client = MailSender::KMail; + + if (mKMailButton->isChecked()) client = MailSender::KMail; + if (mSendmailButton->isChecked()) client = MailSender::Sendmail; + if (mDirectButton->isChecked()) client = MailSender::Direct; + + KBBPrefs::instance()->mMailClient = client; + KBBPrefs::instance()->mShowClosedBugs = mShowClosedCheckBox->isChecked(); + KBBPrefs::instance()->mShowWishes = mShowWishesCheckBox->isChecked(); + KBBPrefs::instance()->mShowVoted = mShowVotedCheckBox->isChecked(); + KBBPrefs::instance()->mMinVotes = mMinVotesInput->value(); + KBBPrefs::instance()->mSendBCC = mSendBccCheckBox->isChecked(); + KBBPrefs::instance()->writeConfig(); + + QValueList<BugServerConfig> servers; + QListViewItem *item; + for ( item = mServerList->firstChild(); item; + item = item->nextSibling() ) { + servers.append( static_cast<ServerItem *>( item )->serverConfig() ); + } + + BugSystem::self()->setServerList( servers ); + + emit configChanged(); +} + +SelectServerDlg::SelectServerDlg(PreferencesDialog *parent, const char */*name*/ ) + :KDialogBase(parent, 0, true, i18n("Select Server"), + KDialogBase::Ok | KDialogBase::Cancel) +{ + list = new ServerListView(this ); + setMainWidget( list ); + + parent->createServerItem( list, "KDE", "http://bugs.kde.org", "KDE" ); + parent->createServerItem( list, "GNOME", "http://bugzilla.gnome.org", "2.10" ); + parent->createServerItem( list, "Mozilla", "http://bugzilla.mozilla.org", "2.17.1" ); + parent->createServerItem( list, "Apache", "http://nagoya.apache.org/bugzilla/", "2.14.2" ); + parent->createServerItem( list, "XFree86", "http://bugs.xfree86.org/cgi-bin/bugzilla/", "2.14.2" ); + parent->createServerItem( list, "Ximian", "http://bugzilla.ximian.com", "2.10" ); + parent->createServerItem( list, "RedHat", "http://bugzilla.redhat.com/bugzilla/", "2.17.1" ); + parent->createServerItem( list, "Mandriva", "http://qa.mandriva.com/", "2.17.4" ); + connect( list, SIGNAL( doubleClicked ( QListViewItem *)), this, SLOT( slotDoubleClicked( QListViewItem *))); +} + + +ServerItem *SelectServerDlg::serverSelected() +{ + return static_cast<ServerItem *>( list->currentItem() ); +} + +void SelectServerDlg::slotDoubleClicked( QListViewItem *) +{ + accept(); +} + +#include "preferencesdialog.moc" diff --git a/kbugbuster/gui/preferencesdialog.h b/kbugbuster/gui/preferencesdialog.h new file mode 100644 index 00000000..29c72eaf --- /dev/null +++ b/kbugbuster/gui/preferencesdialog.h @@ -0,0 +1,76 @@ +#ifndef PREFERENCESDIALOG_H +#define PREFERENCESDIALOG_H + +#include <kdialogbase.h> + +class QCheckBox; +class QRadioButton; +class QLineEdit; +class QListView; +class KIntNumInput; +class ServerListView; + +class PreferencesDialog : public KDialogBase +{ + Q_OBJECT + public: + PreferencesDialog( QWidget* parent = 0, const char* name = 0 ); + ~PreferencesDialog(); + + void createServerItem( ServerListView *listView, const QString &name, + const QString &url, const QString &version ); + + public: + void readConfig(); + void writeConfig(); + + signals: + void configChanged(); + + protected slots: + void setDefaults(); + void slotApply(); + void slotOk(); + void slotCancel(); + + void addServer(); + void editServer(); + void removeServer(); + + void selectServer(); + + protected: + void setupServerPage(); + void setupAdvancedPage(); + + + private: + QCheckBox *mShowClosedCheckBox; + QCheckBox *mShowWishesCheckBox; + QCheckBox *mShowVotedCheckBox; + QCheckBox *mSendBccCheckBox; + KIntNumInput *mMinVotesInput; + QRadioButton *mKMailButton; + QRadioButton *mDirectButton; + QRadioButton *mSendmailButton; + QListView *mServerList; +}; + +class ServerListView; +class ServerItem; + +class SelectServerDlg : public KDialogBase +{ + Q_OBJECT +public: + SelectServerDlg(PreferencesDialog *parent, const char */*name*/ ); + ServerItem *serverSelected(); +protected slots: + void slotDoubleClicked( QListViewItem *); + +protected: + ServerListView *list; +}; + + +#endif diff --git a/kbugbuster/gui/serverconfigdialog.cpp b/kbugbuster/gui/serverconfigdialog.cpp new file mode 100644 index 00000000..32c5e241 --- /dev/null +++ b/kbugbuster/gui/serverconfigdialog.cpp @@ -0,0 +1,82 @@ +#include "serverconfigdialog.h" + +#include "bugserverconfig.h" + +#include <kpassdlg.h> +#include <kdebug.h> +#include <klocale.h> + +#include <qlayout.h> +#include <qlineedit.h> +#include <qlabel.h> +#include <qvbox.h> +#include <qcombobox.h> + +ServerConfigDialog::ServerConfigDialog( QWidget *parent, const char *name ) : + KDialogBase( parent, name, true, i18n("Edit Bugzilla Server"), Ok|Cancel ) +{ + QWidget *topFrame = makeMainWidget(); + + QGridLayout *topLayout = new QGridLayout( topFrame ); + topLayout->setSpacing( spacingHint() ); + + QLabel *label; + + mServerName = new QLineEdit( topFrame ); + label = new QLabel( mServerName, i18n("Name:"), topFrame ); + topLayout->addWidget( label, 0, 0 ); + topLayout->addWidget( mServerName, 0, 1 ); + mServerName->setFocus(); + + mServerUrl = new QLineEdit( topFrame ); + label = new QLabel( mServerUrl, i18n("URL:"), topFrame ); + topLayout->addWidget( label, 1, 0 ); + topLayout->addWidget( mServerUrl, 1, 1 ); + + mUser = new QLineEdit( topFrame ); + label = new QLabel( mUser, i18n("User:"), topFrame ); + topLayout->addWidget( label, 2, 0 ); + topLayout->addWidget( mUser, 2, 1 ); + + mPassword = new KPasswordEdit( topFrame ); + label = new QLabel( mPassword, i18n("Password:"), topFrame ); + topLayout->addWidget( label, 3, 0 ); + topLayout->addWidget( mPassword, 3, 1 ); + + mVersion = new QComboBox( topFrame ); + label = new QLabel( mVersion, i18n("Bugzilla version:"), topFrame ); + topLayout->addWidget( label, 4, 0 ); + topLayout->addWidget( mVersion, 4, 1 ); + mVersion->insertStringList( BugServerConfig::bugzillaVersions() ); +} + +void ServerConfigDialog::setServerConfig( const BugServerConfig &cfg ) +{ + mServerName->setText( cfg.name() ); + mServerUrl->setText( cfg.baseUrl().url() ); + mUser->setText( cfg.user() ); + mPassword->setText( cfg.password() ); + + int i; + for( i = 0; i < mVersion->count(); ++i ) { + if ( mVersion->text( i ) == cfg.bugzillaVersion() ) { + mVersion->setCurrentItem( i ); + break; + } + } +} + +BugServerConfig ServerConfigDialog::serverConfig() +{ + BugServerConfig cfg; + + cfg.setName( mServerName->text() ); + cfg.setBaseUrl( KURL( mServerUrl->text() ) ); + cfg.setUser( mUser->text() ); + cfg.setPassword( mPassword->text() ); + cfg.setBugzillaVersion( mVersion->currentText() ); + + return cfg; +} + +#include "serverconfigdialog.moc" diff --git a/kbugbuster/gui/serverconfigdialog.h b/kbugbuster/gui/serverconfigdialog.h new file mode 100644 index 00000000..5764bfdf --- /dev/null +++ b/kbugbuster/gui/serverconfigdialog.h @@ -0,0 +1,28 @@ +#ifndef SERVERCONFIGDIALOG_H +#define SERVERCONFIGDIALOG_H + +#include <kdialogbase.h> + +class BugServerConfig; +class QLineEdit; +class KPasswordEdit; +class QComboBox; + +class ServerConfigDialog : public KDialogBase +{ + Q_OBJECT + public: + ServerConfigDialog( QWidget *parent = 0 , const char *name = 0 ); + + void setServerConfig( const BugServerConfig & ); + BugServerConfig serverConfig(); + + private: + QLineEdit *mServerName; + QLineEdit *mServerUrl; + QLineEdit *mUser; + KPasswordEdit *mPassword; + QComboBox *mVersion; +}; + +#endif diff --git a/kbugbuster/gui/severityselectdialog.cpp b/kbugbuster/gui/severityselectdialog.cpp new file mode 100644 index 00000000..714e6f3a --- /dev/null +++ b/kbugbuster/gui/severityselectdialog.cpp @@ -0,0 +1,40 @@ +#include <qlayout.h> +#include <qbuttongroup.h> +#include <qradiobutton.h> + +#include <kdebug.h> + +#include "bugsystem.h" +#include "kbbprefs.h" + +#include "severityselectdialog.h" +#include "severityselectdialog.moc" + +SeveritySelectDialog::SeveritySelectDialog(QWidget *parent,const char *name) : + KDialogBase( parent, name, true, i18n("Select Severity"), Ok|Cancel ) +{ + mButtonGroup = new QButtonGroup( 1, Horizontal, i18n("Severity"), this ); + setMainWidget( mButtonGroup ); + + QValueList<Bug::Severity> severities = Bug::severities(); + QValueList<Bug::Severity>::ConstIterator it; + for( it = severities.begin(); it != severities.end(); ++it ) { + mButtonGroup->insert( + new QRadioButton( Bug::severityToString( *it ), mButtonGroup ), int(*it) ); + } +} + +void SeveritySelectDialog::setSeverity( Bug::Severity s ) +{ + mButtonGroup->setButton( s ); +} + +Bug::Severity SeveritySelectDialog::selectedSeverity() +{ + return (Bug::Severity)mButtonGroup->id( mButtonGroup->selected() ); +} + +QString SeveritySelectDialog::selectedSeverityAsString() +{ + return Bug::severityToString( selectedSeverity() ); +} diff --git a/kbugbuster/gui/severityselectdialog.h b/kbugbuster/gui/severityselectdialog.h new file mode 100644 index 00000000..12f36fe5 --- /dev/null +++ b/kbugbuster/gui/severityselectdialog.h @@ -0,0 +1,23 @@ +#ifndef SEVERITYSELECTDIALOG_H +#define SEVERITYSELECTDIALOG_H + +#include <kdialogbase.h> + +#include "bug.h" + +class SeveritySelectDialog : public KDialogBase +{ + Q_OBJECT + public: + SeveritySelectDialog(QWidget *parent=0,const char *name=0); + + void setSeverity( Bug::Severity ); + + Bug::Severity selectedSeverity(); + QString selectedSeverityAsString(); + + private: + QButtonGroup *mButtonGroup; +}; + +#endif |