summaryrefslogtreecommitdiffstats
path: root/kbugbuster/gui
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitbd9e6617827818fd043452c08c606f07b78014a0 (patch)
tree425bb4c3168f9c02f10150f235d2cb998dcc6108 /kbugbuster/gui
downloadtdesdk-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')
-rw-r--r--kbugbuster/gui/Makefile.am24
-rw-r--r--kbugbuster/gui/README21
-rw-r--r--kbugbuster/gui/buglvi.cpp109
-rw-r--r--kbugbuster/gui/buglvi.h57
-rw-r--r--kbugbuster/gui/centralwidget.cpp507
-rw-r--r--kbugbuster/gui/centralwidget.h142
-rw-r--r--kbugbuster/gui/centralwidget_base.ui236
-rw-r--r--kbugbuster/gui/cwbugdetails.cpp212
-rw-r--r--kbugbuster/gui/cwbugdetails.h65
-rw-r--r--kbugbuster/gui/cwbugdetailscontainer.cpp269
-rw-r--r--kbugbuster/gui/cwbugdetailscontainer.h88
-rw-r--r--kbugbuster/gui/cwbugdetailscontainer_base.ui244
-rw-r--r--kbugbuster/gui/cwbuglistcontainer.cpp328
-rw-r--r--kbugbuster/gui/cwbuglistcontainer.h99
-rw-r--r--kbugbuster/gui/cwloadingwidget.cpp256
-rw-r--r--kbugbuster/gui/cwloadingwidget.h87
-rw-r--r--kbugbuster/gui/cwsearchwidget.cpp69
-rw-r--r--kbugbuster/gui/cwsearchwidget.h46
-rw-r--r--kbugbuster/gui/cwsearchwidget_base.ui198
-rw-r--r--kbugbuster/gui/kbbbookmarkmanager.h23
-rw-r--r--kbugbuster/gui/kbbmainwindow.cpp504
-rw-r--r--kbugbuster/gui/kbbmainwindow.h144
-rw-r--r--kbugbuster/gui/kbugbusterui.rc78
-rw-r--r--kbugbuster/gui/loadallbugsdlg.cpp92
-rw-r--r--kbugbuster/gui/loadallbugsdlg.h43
-rw-r--r--kbugbuster/gui/messageeditor.cpp117
-rw-r--r--kbugbuster/gui/messageeditor.h33
-rw-r--r--kbugbuster/gui/msginputdialog.cpp226
-rw-r--r--kbugbuster/gui/msginputdialog.h55
-rw-r--r--kbugbuster/gui/packagelvi.cpp38
-rw-r--r--kbugbuster/gui/packagelvi.h51
-rw-r--r--kbugbuster/gui/packageselectdialog.cpp214
-rw-r--r--kbugbuster/gui/packageselectdialog.h64
-rw-r--r--kbugbuster/gui/preferencesdialog.cpp306
-rw-r--r--kbugbuster/gui/preferencesdialog.h76
-rw-r--r--kbugbuster/gui/serverconfigdialog.cpp82
-rw-r--r--kbugbuster/gui/serverconfigdialog.h28
-rw-r--r--kbugbuster/gui/severityselectdialog.cpp40
-rw-r--r--kbugbuster/gui/severityselectdialog.h23
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 &amp;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>&amp;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&amp;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&amp;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&amp;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&amp;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&amp;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 &amp;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&amp;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>&amp;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 &amp;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>&amp;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 &amp;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>&amp;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>&amp;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>&amp;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&amp;earch</text>
+ <Action name="search_package" />
+ <Action name="search_bugnumber" />
+ <Action name="search_description" />
+ </Menu>
+ <Action name="bookmarks"/>
+ <Menu name="commands"><text>&amp;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>&amp;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 &quotedMsg,
+ 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 &quotedMsg );
+
+ 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