diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-09 10:18:22 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-09 10:18:22 +0000 |
commit | a4e1f41de249a24f3a3607b3ed5d5f02c094e8b5 (patch) | |
tree | 7e484840aaf31fc0d4780295b342592f3dd87a72 /adept | |
download | adept-a4e1f41de249a24f3a3607b3ed5d5f02c094e8b5.tar.gz adept-a4e1f41de249a24f3a3607b3ed5d5f02c094e8b5.zip |
Added adept (KDE3 version abandoned by original author)
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/adept@1072021 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'adept')
275 files changed, 24486 insertions, 0 deletions
diff --git a/adept/COPYING b/adept/COPYING new file mode 100644 index 0000000..5ce2405 --- /dev/null +++ b/adept/COPYING @@ -0,0 +1,29 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of [original copyright holder] nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/adept/Makefile.am b/adept/Makefile.am new file mode 100644 index 0000000..d0531ef --- /dev/null +++ b/adept/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = kubuntu_upgrader adept installer manager updater notifier icons batch diff --git a/adept/NEWS b/adept/NEWS new file mode 100644 index 0000000..a3dc72a --- /dev/null +++ b/adept/NEWS @@ -0,0 +1,2 @@ +good bye kapture, hello ept +ept - kde apt frontend based on libapt-front diff --git a/adept/TODO b/adept/TODO new file mode 100644 index 0000000..504a439 --- /dev/null +++ b/adept/TODO @@ -0,0 +1,33 @@ +the 1.88 milestone: +* the most "intrusive" changes to ui should be done at this point: the detailed + package view and package browsing interface, improvements to the filtering ui +- make the filter area resize itself to fit the contained filters [done] +- clean up individual filters (their extended state that is) [done] +- implement a sidebar for listing available filtering options +- implement "buckets" for wanted and unwanted tags (these are basically a + want/unwant anded tag filters) +- implement drag&drop from sidebar to buckets and to filter list +- implement shuffling of items in the filter list by d&d (needs fixes in + extendablelist) +- implement detailed package view +- implement package browsing (needs thinking) + +* basic pinning support in the libraries should be done (the ui will possibly + have to wait till beta) + +* the ui should be fully i18n'd +- libapt-front needs to be i18n'd +- strings in libept and apps need to be wrapped in i18n + +* skeleton of the update notifier should be done + +* purge and reinstall options in the UI +- need respective options in libapt-front +- add actions to context menu +- think about semantics... + +* support for individual deb handling in the libraries (possibly without + ui) + +* at least basic support for konsole hiding (eventually without "waiting + for input" detection) diff --git a/adept/adept/Makefile.am b/adept/adept/Makefile.am new file mode 100644 index 0000000..ffec465 --- /dev/null +++ b/adept/adept/Makefile.am @@ -0,0 +1,35 @@ +noinst_LTLIBRARIES = libadept.la +libadept_la_SOURCES = changelog.cpp\ + acqprogresswidgetui.ui acqprogress.cpp \ + tagchooser.cpp filtersidebarui.ui filtersidebar.cpp \ + application.cpp \ + tagfilterui.ui tagfilter.cpp taglist.cpp \ + packageinfoui.ui packageinfo.cpp \ + commitprogressui.ui commitprogress.cpp \ + progress.cpp \ + sourceseditorui.ui sourceseditor.cpp \ + acqprogresswidget.cpp dpkgpm.cpp \ + dpkgpm-gui.cpp \ + extendablelist.cpp \ + desktopentryui.ui desktoplist.cpp \ + groupeddesktopselector.cpp \ + packagedetailsui.ui packagedetails.cpp view.cpp \ + listerextenderui.ui lister.cpp filterlist.cpp \ + filterwidget.cpp \ + quickfilterui.ui quickfilter.cpp \ + statefilterui.ui statefilter.cpp \ + easytagfilterui.ui easytagfilter.cpp \ + actor.h threadutils.cpp \ + installerviewui.ui installerview.cpp +libadept_la_LDFLAGS = -L/usr/lib/debug $(all_libraries) +libadept_la_LIBADD = -lapt-front $(LIBTAGCOLL2_LIBS) + +acqprogress.cpp: acqprogress.moc + +INCLUDES = -I$(srcdir)/.. -I.. $(all_includes) $(LIBEPT_CFLAGS) $(LIBTAGCOLL2_CFLAGS) $(LIBAPT_FRONT_CFLAGS) $(LIBWIBBLE_CFLAGS) +KDE_CXXFLAGS = $(USE_EXCEPTIONS) -DQT_NO_ASCII_CAST -DQT_NO_CAST_ASCII -DDEFAULT_KONSOLE_HIDDEN=true +METASOURCES = AUTO + +messages: rc.cpp + $(EXTRACTRC) `find . -name \*.ui -o -name \*.rc` > rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/libept.pot diff --git a/adept/adept/acqprogress.cpp b/adept/adept/acqprogress.cpp new file mode 100644 index 0000000..4b0643f --- /dev/null +++ b/adept/adept/acqprogress.cpp @@ -0,0 +1,295 @@ +// -*- C++ -*- + +#include <qprogressbar.h> +#include <klistview.h> +#include <kapplication.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qstyle.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kdebug.h> + +#include "acqprogress.h" +#include <apt-pkg/acquire-item.h> +#include <apt-pkg/acquire-worker.h> +#include <apt-pkg/strutl.h> +#include <apt-pkg/error.h> +#include <apt-pkg/configuration.h> + +#include <adept/utils.h> + +#include <stdio.h> +#include <signal.h> +#include <iostream> + +#define _(a...) (a) // XXX + +using namespace std; + +namespace adept { + +AcqStatus::Item::Item (KListView *parent, pkgAcquire::ItemDesc &item, bool hit) +: KListViewItem( parent ) +{ + m_pbcol = 0; + m_prog = new ItemProgress( 0, 0 ); + m_prog->setStatus( "waiting" ); + m_prog->setTotalSteps( 100 ); + m_item = item; + m_id = m_item.Owner->ID; + /* if (item.Owner->FileSize > 0) + setText( 1, SizeToStr( item.Owner->FileSize ).c_str() + QString( "B" ) ); */ + setText( 1, u8( item.Description ) ); + // cerr << "create: id = " << item . Owner -> ID << ", myId = " << m_item . Owner -> ID << endl; + if (hit) { + m_prog->setStatus( "hit" ); + } else + m_prog->setStatus( "waiting" ); + // QString (SizeToStr (Itm.Owner -> FileSize) . c_str ()) + QString ("B"), + // /* QString (Itm . Owner -> ID) + */ QString (Itm.Description . c_str ())); +} + +AcqStatus::Item::~Item () +{ + delete m_prog; +} + +int AcqStatus::Item::compare (QListViewItem *i, int /*col*/, bool /*ascend*/) const +{ + int id1 = m_id; + int id2 = ((Item *) i) -> m_id; + return (id2 >= id1) - (id2 <= id1); +} + +void AcqStatus::Item::pulse (pkgAcquire::Worker *w) +{ + if (w) { + if (w->TotalSize) + setStatus( "progress", long( double( + w -> CurrentSize * 100.0) + / double( w->TotalSize ) ) ); + else + setStatus( "downloading", 0 ); + } +} + +void AcqStatus::Item::setStatus( const std::string &s, int i ) +{ + m_prog->setStatus( s, i ); +} + +void AcqStatus::Item::paintCell (QPainter *p, const QColorGroup &cg, + int column, int width, int alignment ) +{ + QColorGroup _cg( cg ); + QColor c = _cg.text(); + + if ( column == m_pbcol ) { + const QRect bar = QRect( 0, 0, width, height() ); + m_prog->resize( width, height() ); + QPixmap pm = QPixmap::grabWidget( m_prog ); + // p->fillRect( bar, listView()->paletteBackgroundColor() ); + p->drawPixmap( bar.x(), bar.y(), pm ); + } else { + QPixmap pm( width, height() ); + QPainter _p( &pm ); + _cg.setColor( QColorGroup::Text, c ); + KListViewItem::paintCell( &_p, _cg, column, width, alignment ); + p->drawPixmap( 0, 0, pm ); + } +} + +AcqStatus::Item *AcqStatus::findItem (pkgAcquire::ItemDesc &Itm) +{ + if ( Itm.Owner->ID < m_idOffset ) + return 0; + if ( Itm.Owner->ID - m_idOffset >= m_items.size() ) + return 0; + return m_items[ Itm.Owner->ID - m_idOffset ]; +} + +AcqStatus::AcqStatus(QWidget *parent, const char *name) + : KListView (parent, name), m_idOffset( 0 ), m_continue( true ) +{ + // m_lastItem = 0; + addColumn( i18n( "Progress" ) ); + addColumn( i18n( "Description" ) ); + setSorting (1); + setColumnWidth (0, 220); + setColumnWidth (1, 300); + setResizeMode (LastColumn); + ID = 0; +} + +void AcqStatus::Done (pkgAcquire::ItemDesc &Itm) +{ + Item *i = findItem (Itm); + if (i) { + i->setStatus( "done" ); + } + emit statusChanged( StWaiting ); + triggerUpdate(); + KApplication::kApplication()->processEvents(); +} + +void AcqStatus::clear() +{ + KListView::clear(); + m_idOffset += m_items.size(); + m_items.clear(); // got deleted by klistview already +} + +void AcqStatus::Start() +{ + clear(); + pkgAcquireStatus::Start(); + kdDebug() << "AcqStatus::Start ()" << endl; + _config -> Set ("APT::Fetcher::Select-Timeout-Usec", 100000); + emit statusChanged( StWaiting ); + triggerUpdate(); + KApplication::kApplication()->processEvents(); +} + +void AcqStatus::IMSHit(pkgAcquire::ItemDesc &Itm) +{ + Itm.Owner->ID = ID++; + Item *i = new Item( this, Itm, true ); + // ensureItemVisible( i ); + i->setStatus( "hit" ); + m_items.push_back( i ); + + kdDebug() << "imshit called on ID = " << ID - 1 << " i = " << (void *)i << endl; + triggerUpdate(); + KApplication::kApplication()->processEvents(); +}; + +void AcqStatus::Fetch(pkgAcquire::ItemDesc &Itm) + // an item started to download +{ + Update = true; + if (Itm.Owner->Complete == true) // XXX? + return; + + Itm.Owner->ID = ID++; + + Item *i = new Item( this, Itm ); + // ensureItemVisible( i ); + m_items.push_back( i ); + + kdDebug() << "fetch called on ID = " << ID - 1 << " i = " << (void *)i << endl; + emit statusChanged( StDownloading ); + triggerUpdate(); + KApplication::kApplication()->processEvents(); +}; + +void AcqStatus::Fail(pkgAcquire::ItemDesc &Itm) + // item failed to download +{ + kdDebug() << "fail, status = " << Itm.Owner->Status + << " ID = " << Itm.Owner->ID << endl; + // Ignore certain kinds of transient failures (bad code) + if (Itm.Owner->Status == pkgAcquire::Item::StatIdle) { + kdDebug() << "fail with StatIdle, ignoring" << endl; + return; + } + + Item *i = findItem (Itm); + kdDebug() << "fail, i = " << i << endl; + if (! i) + return; + if (Itm.Owner->Status == pkgAcquire::Item::StatDone) { + i->setStatus( "ignored" ); + } else { + i->setStatus( "error" ); + } + + triggerUpdate(); + KApplication::kApplication()->processEvents(); +}; + +void AcqStatus::Stop() +{ + pkgAcquireStatus::Stop(); + emit statusChanged( StDone ); + triggerUpdate (); + KApplication::kApplication()->processEvents(); +} + +bool AcqStatus::Pulse(pkgAcquire *Owner) +{ + pkgAcquireStatus::Pulse(Owner); + + for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0; + I = Owner->WorkerStep(I)) { + if (I -> CurrentItem) { + Item *i = findItem (* (I -> CurrentItem)); + if (i) + i -> pulse (I); + } + } + + triggerUpdate (); + // repaint (); + + if (TotalBytes > 0) + emit totalProgress( + long( double( + (CurrentBytes + + CurrentItems)*100.0)/double(TotalBytes+TotalItems) ) ); + else + emit totalProgress (-1); + KApplication::kApplication () -> processEvents (); + + if ( m_continue ) + return true; + + m_continue = true; + return false; +} + +bool AcqStatus::MediaChange(string Media,string Drive) +{ + int res = KMessageBox::warningContinueCancel( + this, i18n( "Please insert the disc " + "labeled '%1' in the drive " + "'%2' and press enter" ).arg( + u8( Media ) ).arg( u8( Drive ) ), + i18n( "Media Change" ) ); + if ( res == KMessageBox::Cancel ) + cancel(); + return true; +} + +void AcqStatus::cancel() +{ + m_continue = false; +} + +AcqStatusDialog::AcqStatusDialog (QWidget *parent, const char *name, bool modal) + : KDialogBase( parent, name, modal, + u8( "progress dialog (FIXME: waiting for headers, done)" ), + Ok|Cancel, Cancel, true ) +{ + m_status = new AcqStatus (this, ""); + setMainWidget( m_status.data() ); + enableButton (Ok, false); + connect (m_status.data(), SIGNAL (statusChanged (AcqStatus::Status)), + this, SLOT (statusChange (AcqStatus::Status))); +} + +void AcqStatusDialog::statusChange (AcqStatus::Status st) +{ + if (st == AcqStatus::StDownloading || st == AcqStatus::StWaiting) { + enableButton (Ok, false); + // XXX: cancel should be true; but needs implementation first + enableButton (Cancel, false); + } else if (st == AcqStatus::StDone) { + enableButton (Ok, true); + enableButton (Cancel, false); + } +} + +} + +#include "acqprogress.moc" diff --git a/adept/adept/acqprogress.h b/adept/adept/acqprogress.h new file mode 100644 index 0000000..9510825 --- /dev/null +++ b/adept/adept/acqprogress.h @@ -0,0 +1,127 @@ +/** -*- C++ -*- + @file adept/acqprogress.h + @author Peter Rockai <me@mornfall.net> +*/ + +#ifndef ACQPROGRESS_H +#define ACQPROGRESS_H + +#include <klocale.h> +#include <kdialogbase.h> +#include <klistview.h> +#include <kprogress.h> + +#include <vector> +#include <apt-pkg/acquire.h> +#include <apt-front/progresscallback.h> + +class AcqStatus; +class QLabel; +class QProgressBar; +class QSpacer; +class QGridLayout; + +namespace adept { + +class AcqStatus : public KListView, public aptFront::ProgressCallback +{ + Q_OBJECT +protected: + class ItemProgress: public KProgress { + public: + ItemProgress( QWidget *parent, const char *name = 0 ) + : KProgress( parent, name ), m_spin( 0 ) {} + void setStatus( const std::string &s, + int prog = 0 ) { + m_status = s; + if (m_status == "hit" + || m_status == "ignored" + || m_status == "done") + prog = 100; + if (m_status == "waiting") { + prog = 0; + } + if (m_status == "progress" && prog != 100) + setFormat( i18n( "downloading (%p%)" ) ); + else if (prog == 100) // who cares about hit/ignore anyway? + setFormat( i18n( "done (%p%)" ) ); + else + setFormat( m_status ); + setProgress( prog ); + } + protected: + std::string m_status; + int m_spin; + }; + class Item : public KListViewItem { + protected: + ItemProgress *m_prog; + int m_pbcol; + unsigned long m_id; + pkgAcquire::ItemDesc m_item; + + public: + Item (KListView *parent, pkgAcquire::ItemDesc &item, + bool hit = false); + virtual ~Item (); + + virtual void paintCell (QPainter *p, const QColorGroup &cg, + int column, int width, int alignment); + + void setProgress (int); + virtual int compare (QListViewItem *i, int col, bool ascend) const; + virtual void pulse (pkgAcquire::Worker *); + void setStatus( const std::string &, int = 0 ); + + void setup() { + KListViewItem::setup(); + setHeight( height() + 6 ); + } + }; + unsigned long ID; + unsigned long m_idOffset; + std::vector <Item *> m_items; + bool m_continue; + +public: + + enum Status { StWaiting, StDownloading, StDone }; + + AcqStatus (QWidget *parent, const char *name); + Item *findItem (pkgAcquire::ItemDesc &Itm); + + virtual bool MediaChange (string Media,string Drive); + virtual void IMSHit (pkgAcquire::ItemDesc &Itm); + virtual void Fetch (pkgAcquire::ItemDesc &Itm); + virtual void Done (pkgAcquire::ItemDesc &Itm); + virtual void Fail (pkgAcquire::ItemDesc &Itm); + virtual void Start (); + virtual void Stop (); + void addLine (QWidget *l, QWidget *s, QWidget *prog); + void clear(); + + bool Pulse (pkgAcquire *Owner); + +public slots: + void cancel(); + +signals: + void statusChanged (AcqStatus::Status st); + void totalProgress (int percent); + + //AcqTextStatus(unsigned int &ScreenWidth,unsigned int Quiet); +}; + +class AcqStatusDialog : public KDialogBase +{ + Q_OBJECT +protected: + aptFront::SharedPtr<AcqStatus> m_status; +public: + aptFront::SharedPtr<aptFront::ProgressCallback> callback() { return m_status.data(); }; + AcqStatusDialog (QWidget *parent, const char *name, bool modal); +public slots: + void statusChange (AcqStatus::Status st); +}; +} +#endif diff --git a/adept/adept/acqprogresswidget.cpp b/adept/adept/acqprogresswidget.cpp new file mode 100644 index 0000000..dd02f03 --- /dev/null +++ b/adept/adept/acqprogresswidget.cpp @@ -0,0 +1,53 @@ +#include <kprogress.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <klocale.h> +#include "acqprogresswidget.h" +#include "acqprogress.h" + +using namespace adept; + +AcqProgressWidget::AcqProgressWidget( QWidget *parent, const char *name ) + : AcqProgressWidgetUi( parent, name ) +{ + m_statusRef = m_status; + m_progress->setTotalSteps( 100 ); + m_progress->setProgress( 0 ); + connect(m_status, SIGNAL( totalProgress( int ) ), + this, SLOT( setProgress( int ) ) ); + connect(m_status, SIGNAL( statusChanged( AcqStatus::Status ) ), + this, SLOT( statusChange( AcqStatus::Status ) ) ); + connect( m_cancel, SIGNAL( clicked() ), + m_status, SLOT( cancel() ) ); +} + +void AcqProgressWidget::statusChange( AcqStatus::Status s ) +{ + QString t; + switch (s) { + case AcqStatus::StWaiting: + t = i18n( "Waiting for headers (%p%)" ); + break; + case AcqStatus::StDownloading: + t = i18n( "Downloading (%p%)" ); + break; + case AcqStatus::StDone: + t = i18n( "Done (%p%)" ); + m_progress->setProgress( 100 ); + break; + } + m_progress->setFormat( t ); +} + +void AcqProgressWidget::setProgress( int p ) +{ + if (p < 0) { + m_progress->setTotalSteps( 0 ); + m_progress->setProgress( m_progress->progress() + 1 ); + } else { + m_progress->setTotalSteps( 100 ); + m_progress->setProgress( p ); + } +} + +#include "acqprogresswidget.moc" diff --git a/adept/adept/acqprogresswidget.h b/adept/adept/acqprogresswidget.h new file mode 100644 index 0000000..54359c7 --- /dev/null +++ b/adept/adept/acqprogresswidget.h @@ -0,0 +1,30 @@ +/** -*- C++ -*- + @file adept/acqprogresswidget.h + @author Peter Rockai <me@mornfall.net> + @todo Close button! +*/ + +#ifndef PROGRESSWIDGET_H +# define PROGRESSWIDGET_H + +#include <adept/acqprogresswidgetui.h> +#include <adept/acqprogress.h> + +namespace adept { + +class AcqProgressWidget : public AcqProgressWidgetUi { + Q_OBJECT +public: + AcqProgressWidget (QWidget *parent = 0, const char *name = 0); + aptFront::SharedPtr<aptFront::ProgressCallback> callback() { return m_statusRef.data(); }; +public slots: + void statusChange( AcqStatus::Status ); + void setProgress( int ); +protected: + aptFront::SharedPtr<AcqStatus> m_statusRef; +}; + +} + +#endif /* ifndef PROGRESSWIDGET_H */ + diff --git a/adept/adept/acqprogresswidgetui.ui b/adept/adept/acqprogresswidgetui.ui new file mode 100644 index 0000000..26baa21 --- /dev/null +++ b/adept/adept/acqprogresswidgetui.ui @@ -0,0 +1,79 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::AcqProgressWidgetUi</class> +<widget class="QWidget"> + <property name="name"> + <cstring>adept::AcqProgressWidgetUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>705</width> + <height>289</height> + </rect> + </property> + <property name="caption"> + <string>Download Progress</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="adept::AcqStatus" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_status</cstring> + </property> + <property name="minimumSize"> + <size> + <width>300</width> + <height>150</height> + </size> + </property> + </widget> + <widget class="KProgress" row="1" column="0"> + <property name="name"> + <cstring>m_progress</cstring> + </property> + </widget> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>m_cancel</cstring> + </property> + <property name="text"> + <string>Cancel Download</string> + </property> + </widget> + </grid> +</widget> +<customwidgets> + <customwidget> + <class>adept::AcqStatus</class> + <header location="global">acqprogress.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</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="PNG" length="1002">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082</data> + </image> +</images> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>adept/acqprogress.h</includehint> + <includehint>kprogress.h</includehint> +</includehints> +</UI> diff --git a/adept/adept/actor.h b/adept/adept/actor.h new file mode 100644 index 0000000..115b202 --- /dev/null +++ b/adept/adept/actor.h @@ -0,0 +1,43 @@ +/** -*- C++ -*- + @file adept/actor.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qobject.h> +#include <apt-front/cache/entity/entity.h> +#include <apt-front/actor.h> + +#ifndef EPT_ACTOR_H +#define EPT_ACTOR_H + +namespace adept { + +using namespace aptFront; + +class EntityActor : public QObject +{ + Q_OBJECT +public: + EntityActor( actor::Bound< cache::entity::Entity > a ) + : m_actor( a ), m_dead( false ) + {} + actor::Bound< cache::entity::Entity > actor() const { + return m_actor; + } +public slots: + void act() { m_actor(); } + void destructiveAct() { + // in case we don't get deleted soon enough + if ( m_dead ) return; + m_dead = true; + act(); + deleteLater(); + } +protected: + actor::Bound< cache::entity::Entity > m_actor; + bool m_dead; +}; + +} + +#endif diff --git a/adept/adept/application.cpp b/adept/adept/application.cpp new file mode 100644 index 0000000..5f2eb2a --- /dev/null +++ b/adept/adept/application.cpp @@ -0,0 +1,350 @@ +/** -*- C++ -*- + @file adept/application.cpp + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qprocess.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kapplication.h> +#include <kstatusbar.h> +#include <kdebug.h> + +#include <apt-front/init.h> +#include <apt-front/cache/component/packages.h> +#include <apt-front/cache/component/state.h> + +#include <adept/commitprogress.h> +#include <adept/application.h> +#include <adept/packageinfo.h> +#include <adept/progress.h> +#include <adept/utils.h> + +namespace adept { +using namespace cache; + +#ifdef KUBUNTU +#include <qstringlist.h> +#define DPKG_FIXER_ARGS QStringList::split(QString(" "), QString("dpkg --configure -a"), false) + +DpkgFixer::DpkgFixer(struct Application* parent) + : m_parent(parent) +{ + m_fixer = 0; + m_waiter = 0; + m_output = ""; + m_done = false; +} + +DpkgFixer::~DpkgFixer() +{ + if (m_fixer != 0) { + delete m_fixer; + } + if (m_waiter != 0) { + delete m_waiter; + } + + std::cout << "Got output " << m_output.latin1() << std::endl; +} + +void DpkgFixer::fixDpkgLock() +{ + kdDebug() << "Asking user if they would like to fix dpkg lock..." << endl; + int decision = KMessageBox::warningYesNoCancel(m_parent->mainWindow(), + i18n("Another process is using the packaging system database " + "(probably some other Adept application or apt-get or " + "aptitude).\nWould you like to attempt to resolve this problem? " + "No will enter read-only mode and Cancel to quit and resolve " + "this issue yourself."), + i18n( "Database Locked" ) ); + switch (decision) { + case KMessageBox::Yes: + kdDebug() << "User opted to fix the dpkg database. Trying to run the process..." << endl; + cache::Global::get().close(); + // Call the dpkg fixer. + m_fixer = new QProcess(dynamic_cast<QObject*>(this)); + m_fixer->setArguments(DPKG_FIXER_ARGS); + + // Handle when the process exits + connect(dynamic_cast<QObject*>(m_fixer), SIGNAL( processExited() ), + dynamic_cast<QObject*>(this), SLOT( retryOpen() )); + + // Handle when the process has stdout output + connect(dynamic_cast<QObject*>(m_fixer), SIGNAL( readyReadStdout() ), + dynamic_cast<QObject*>(this), SLOT( handleStdout() )); + + // Handle when the process has stderr output + connect(dynamic_cast<QObject*>(m_fixer), SIGNAL( readyReadStderr() ), + dynamic_cast<QObject*>(this), SLOT( handleStderr() )); + + // Fire off the waiter... + m_waiter = new KProgressDialog(m_parent->mainWindow(), "waiter", + i18n("Unlocking; Please Wait..."), i18n("Unlocking dpkg database; Please wait...")); + m_waiter->setAllowCancel(false); + m_waiter->show(); + + m_fixer->start(); + kdDebug() << "dpkg fixer fired off." << endl; + + break; + + case KMessageBox::Cancel: + kdDebug() << "User opted to cancel and repair manually." << endl; + exit(1); + break; + + default: + kdDebug() << "User opted to continue in read-only mode." << endl; + m_parent->updateStatusbar(); + m_parent->cacheOpenedNowFinishInit(); + break; + } + + return; +} + +void DpkgFixer::retryOpen() +{ + kdDebug() << "Retrying the open..." << endl; + m_waiter->setLabel(i18n("Reopening the dpkg database...")); + m_waiter->progressBar()->setValue(50); + try { + if (!m_fixer->normalExit()) { + kdDebug() << "The fixer command did not exit normally. Throwing exception." << endl; + throw 0; + } + + kdDebug() << "The fixer command exited normally, trying to reopen the database." << endl; + cache::Global::get().open( m_parent->openFlags() ); + } catch (...) { + KMessageBox::information(m_parent->mainWindow(), + i18n( "Failed to unlock the database. " + "Please try to resolve this issue. " + "`sudo dpkg --configure -a` may help." ), + i18n( "Unlock Failed." ) ); + exit( 1 ); + } + + m_waiter->progressBar()->setValue(100); + m_waiter->close(); + m_parent->updateStatusbar(); + m_parent->cacheOpenedNowFinishInit(); +} + +void DpkgFixer::outputUpdated() +{ +} + +void DpkgFixer::handleStdout() +{ +// m_output += m_fixer->readStdout(); +// outputUpdated(); +} + +void DpkgFixer::handleStderr() +{ +// m_output += m_fixer->readStderr(); +// outputUpdated(); +} +#endif // KUBUNTU + +Application::Application() + : m_acceptReadOnly( false ), m_main( 0 ), m_history( 0 ), m_statusBar( 0 ) +{ +#ifdef KUBUNTU + m_dpkgfixer = 0; +#endif // KUBUNTU +} + +Application::~Application() +{ +#ifdef KUBUNTU + if (m_dpkgfixer != 0) { + delete m_dpkgfixer; + } +#endif // KUBUNTU +} + +void Application::openCache( unsigned flags ) +{ + m_flags = flags; + bool ro = m_acceptReadOnly; + bool root = ::getuid() == 0 || ::geteuid() == 0; + + try { + cache::Global::get().open( m_flags ); + } catch (...) { + try { + cache::Global::get().open( m_flags | Cache::OpenReadOnly ); + if ( ro && root ) { +#ifndef KUBUNTU + kdDebug() << "ro && root -- Database locked." << endl; + KMessageBox::information( + m_main, i18n( + "You will not be able to change your system settings " + "in any way (install, remove or upgrade software), " + "because another process is using the packaging system database " + "(probably some other Adept application or apt-get or " + "aptitude). Please close the other application before " + "using this one." ), + i18n( "Read Only mode: Database Locked" ) ); +#else + kdDebug() << "Firing off the Kubuntu dpkg database lock fixer..." << endl; + m_dpkgfixer = new DpkgFixer(this); + m_dpkgfixer->fixDpkgLock(); + return; +#endif // KUBUNTU + } else if ( !root && ro ) { + kdDebug() << "!root && ro -- Need root privileges." << endl; + KMessageBox::information( + m_main, i18n( + "You will not be able to change your system settings " + "in any way (install, remove or upgrade software), " + "because this application needs special administrator " + "(root) privileges. Please run it as root or " + "through kdesu or sudo programs to be able to perform " + "these actions" ), + i18n( "Read Only mode: Need root privileges" ) ); + } else if ( root && !ro ) { +#ifndef KUBUNTU + kdDebug() << "root && !ro -- Database locked." << endl; + KMessageBox::information(m_main, + i18n("Another process is using the packaging system database " + "(probably some other Adept application or apt-get or " + "aptitude). Please close the other application before " + "using this one." ), + i18n( "Read Only mode: Database Locked" ) ); +#else + kdDebug() << "Firing off the Kubuntu dpkg database lock fixer..." << endl; + m_dpkgfixer = new DpkgFixer(this); + m_dpkgfixer->fixDpkgLock(); + return; +#endif // KUBUNTU + } else if ( !root && !ro ) { + kdDebug() << "!root && !ro -- Needs root privileges." << endl; + KMessageBox::information( + m_main, i18n( "This application needs special administrator " + "(root) privileges. Please run it as root or " + "through kdesu or sudo programs" ), + i18n( "Need root privileges" ) ); + } + if ( !ro ) { + kdDebug() << "cannot continue, exiting" << endl; + exit( 1 ); + } + } catch (...) { + KMessageBox::sorry( + m_main, i18n( + "The APT Database could not be opened!" + " This may be caused by incorrect APT configuration" + " or some similar problem. Try running apt-setup and" + " apt-get update in terminal and see if it helps" + " to resolve the problem." ), i18n( "Could not open cache" )); + exit( 1 ); + } + } + + updateStatusbar(); + cacheOpenedNowFinishInit(); +} + +void Application::initHistory() { + cache::Global::get().addComponent( + m_history = new History() ); +} + +void Application::initKDEDebconf() +{ + // xxx unhardcode the package name somehow? + if (cache::Global::get().packages() + .packageByName( "libqt-perl" ).isInstalled()) + putenv( "DEBIAN_FRONTEND=kde" ); +} + +void Application::initialize() +{ + CommitProgress::initSystem(); + aptFront::init(); + openCache(); +} + +void Application::cacheOpenedNowFinishInit() { + initKDEDebconf(); + initHistory(); + observeComponent< component::State >(); + + initFinished(); +} + +void Application::checkpoint() { + if ( !history() ) return; + setHistoryEnabled( false ); + history()->checkpoint(); + setHistoryEnabled( true ); +} + +void Application::undo() { + if ( !history() ) return; + setHistoryEnabled( false ); + history()->undo(); + setHistoryEnabled( true ); +} + +void Application::redo() { + if ( !history() ) return; + setHistoryEnabled( false ); + history()->redo(); + setHistoryEnabled( true ); +} + +QString Application::changeString() { + component::State &s = cache().state(); + return i18n( " Install %1, upgrade %2, remove %3 " ) + .arg( s.newInstallCount() ).arg( s.upgradeCount() ) + .arg( s.removeCount() ); +} + +QString Application::statusString() { + component::State &s = cache().state(); + return i18n( " %1 installed, %2 upgradable, %3 available " ) + .arg( s.installedCount() ).arg( s.upgradableCount() ) + .arg( s.availableCount() ); +} + +QString Application::sizesString() { + QString dl = cache().state().downloadSizeString(); + QString inst = cache().state().installSizeString(); + return i18n( " download: %1, installation: %2 " ).arg( dl ).arg( inst ); +} + +void Application::setStatusBar( KStatusBar *s ) { + m_statusBar = s; + if ( s ) { + s->message( i18n( "Initializing..." ) ); + s->insertItem( u8( "" ), 0 ); + s->insertItem( u8( "" ), 1 ); + s->insertItem( u8( "" ), 2 ); + adjustFontSize( s, -1 ); + + adept::Progress *pr = new adept::Progress(); + pr->setStatusBar( s ); + cache::Global::get().setProgress( pr ); + } +} + +void Application::notifyPostChange( component::Base * ) +{ + updateStatusbar(); +} + +void Application::updateStatusbar() +{ + if ( m_statusBar ) { + m_statusBar->changeItem( changeString(), 0 ); + m_statusBar->changeItem( statusString(), 1 ); + m_statusBar->changeItem( sizesString(), 2 ); + } +} + +} diff --git a/adept/adept/application.h b/adept/adept/application.h new file mode 100644 index 0000000..0416b70 --- /dev/null +++ b/adept/adept/application.h @@ -0,0 +1,102 @@ +/** -*- C++ -*- + @file adept/application.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <vector> + +#include <qobject.h> +#include <qprocess.h> +#include <kprogress.h> + +#include <apt-front/cache/cache.h> +#include <apt-front/cache/component/state.h> +#include <apt-front/cache/component/history.h> + +#ifndef EPT_APPLICATION_H +#define EPT_APPLICATION_H + +#define KUBUNTU + +class KStatusBar; + +namespace adept { +using namespace aptFront; +using cache::Cache; + +class Lister; + +#ifdef KUBUNTU +class DpkgFixer : public QObject { + Q_OBJECT; +public: + DpkgFixer(struct Application* app); + ~DpkgFixer(); + + bool done() { return m_done; }; +public slots: + void fixDpkgLock(); + + +protected slots: + void retryOpen(); + void outputUpdated(); + void handleStdout(); + void handleStderr(); + +protected: + QProcess* m_fixer; + Application* m_parent; + QString m_output; + KProgressDialog* m_waiter; + bool m_done; +}; +#endif // KUBUNTU + +struct Application : cache::Observer { + Application(); + ~Application(); + void setAcceptReadOnly( bool ro ) { m_acceptReadOnly = ro; } + bool writeable() { return cache::Global::get().writeable(); } + Cache &cache() { return cache::Global::get(); } + void openCache( unsigned flags = Cache::OpenDefault | Cache::OpenDebtags ); + void initialize(); + void cacheOpenedNowFinishInit(); + void initKDEDebconf(); + void initHistory(); + void setMainWidget( QWidget *w ) { m_main = w; } + void setStatusBar( KStatusBar *s ); + void updateStatusbar(); + virtual void initFinished() { return; }; + virtual void checkpoint(); + virtual void undo(); + virtual void redo(); + + int test_this_shit; + + virtual void notifyPostChange( cache::component::Base * ); + + QString changeString(); + QString statusString(); + QString sizesString(); + QWidget* mainWindow() { return m_main; }; + unsigned openFlags() { return m_flags; }; + +protected: + virtual void setHistoryEnabled( bool ) {} + typedef cache::component::History< cache::component::State > History; + virtual History *history() { return m_history; } + bool m_acceptReadOnly; + unsigned m_flags; + QWidget *m_main; + KStatusBar *m_statusBar; + History *m_history; + +#ifdef KUBUNTU + DpkgFixer* m_dpkgfixer; +#endif // KUBUNTU +}; + +} + +#endif diff --git a/adept/adept/changelog.cpp b/adept/adept/changelog.cpp new file mode 100644 index 0000000..5dd47ed --- /dev/null +++ b/adept/adept/changelog.cpp @@ -0,0 +1,145 @@ +/* -*- C++ -*- */ +#include <qstring.h> +#include <qstringlist.h> +#include <qhttp.h> +#include <qbuffer.h> + +#include <kdebug.h> + +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/entity/package.h> + +#include <adept/lister.h> + +#include "changelog.h" + +using namespace adept; + +#ifdef KUBUNTU +ItemChangelog::ItemChangelog() { + connect(this, SIGNAL( changelogNeeded() ), + this, SLOT( requestChangelog() )); + m_http = 0; + m_content_catcher = 0; +} + +ItemChangelog::~ItemChangelog() { + if (m_http != 0) { + delete m_http; + } + if (m_content_catcher != 0) { + delete m_content_catcher; + } +} + +/* + * So this method is *very* specific to the ubuntu package + * changelog repository. If you want to modify this to meet the needs + * of another distro, you may want to implement your own method here. + */ +QString ItemChangelog::changelogUrl() { + // The list of known sections... + QStringList knownSections(QString("main")); + knownSections += QString("multiverse"); + knownSections += QString("restricted"); + knownSections += QString("universe"); + + // The parts of the package that form the URL... + QStringList pkgParts( QString(BASE_CHANGELOG_URL) ); + QStringList sectionParts; + QString section; + QString urlBase; + QString pkgName; + bool found = false; + + try { + if (&m_pkg == 0x0) { + throw 0; + } + std::string theSection(m_pkg.section(std::string("/"))); + if (!theSection.length()) { + throw 0; + } + //// Get the section + section = QString( theSection ); + /* now convert the section into something + usable for the changelog URL. */ + sectionParts = QStringList::split(QString("/"), section); + + /* If we have more than one piece, that means we've got a + non-main repo. Let's make sure it's one we can use. */ + if (sectionParts.size() > 1) { + // Walk through known sections + for (QStringList::Iterator it = knownSections.begin(); + it != knownSections.end(); ++it) { + // If we found it, let's say we found it. + if (sectionParts[0] == *it) { + pkgParts += sectionParts[0]; + found = true; + break; + } + } + if (!found) { + return QString::null; // didn't find the repo! + } + } else { + pkgParts += QString("main"); + } + + //// Get the package name and prefix + pkgName += QString( m_pkg.source() ); + pkgParts += QString(pkgName[0]); + pkgParts += pkgName; + + //// Get the version string. + QString version = QString( m_pkg.candidateVersion().versionString() ); + int epoch = version.find(':'); + if (epoch > -1) { + version = version.mid(epoch + 1); + } + pkgName += "_" + version; + pkgParts += pkgName; + pkgParts += QString("changelog"); + + return pkgParts.join(QString("/")); + } catch (...) { + kdDebug() << "GOT ME AN EXCEPTION!!!! THIS IS NOT GOOD!!!!"; + } + + return QString::null; +} + +void ItemChangelog::requestChangelog() { +// emit changelogReady(changelogUrl()); + +// return; + + /* Removing temporarilly */ + m_http = new QHttp(QString(BASE_CHANGELOG_HOST), + BASE_CHANGELOG_PORT, + this, "changelog_loader"); + connect(dynamic_cast<QObject*>(m_http), SIGNAL( requestFinished(int,bool) ), + dynamic_cast<QObject*>(this), SLOT( contentReady(int,bool) )); + m_content_catcher = new QBuffer(); + QString theUrl( changelogUrl() ); + + if ( theUrl == QString::null ) { + emit changelogReady(QString("No change log found.")); + } else { + m_http->get( changelogUrl(), dynamic_cast<QIODevice*>(m_content_catcher) ); + } +} + +void ItemChangelog::contentReady( int id, bool error ) { + QString msg("Unable to fetch the Developer Changelog."); + + if (!error) { + msg = QString( m_content_catcher->buffer() ); + } else { + msg += ": " + m_http->errorString(); + } + + emit changelogReady( msg ); +} + +#endif /*KUBUNTU*/ diff --git a/adept/adept/changelog.h b/adept/adept/changelog.h new file mode 100644 index 0000000..8db861b --- /dev/null +++ b/adept/adept/changelog.h @@ -0,0 +1,45 @@ +/* -*- C++ -*- */ +#ifndef CHANGELOG_H +#define CHANGELOG_H + +#include <qobject.h> +#include <qstring.h> +#include <qhttp.h> +#include <qbuffer.h> + +#include <adept/lister.h> + +#ifdef KUBUNTU +#define BASE_CHANGELOG_HOST "changelogs.ubuntu.com" +#define BASE_CHANGELOG_PORT 80 +#define BASE_CHANGELOG_URL "/changelogs/pool" + +namespace adept { + + class ItemChangelog : public QObject { + Q_OBJECT + public: + ItemChangelog(); + ~ItemChangelog(); + + // Give me the changelog's URL + QString changelogUrl(); + void setParent(entity::Package parent) { m_pkg = parent; } + signals: + void changelogNeeded(); + void changelogReady(QString content); + + protected slots: + // Give me the changelog's text + void requestChangelog(); + void contentReady(int id, bool error); + + protected: + entity::Package m_pkg; + QHttp* m_http; + QBuffer* m_content_catcher; + }; +} + +#endif /* KUBUNTU */ +#endif /*CHANGELOG_H*/ diff --git a/adept/adept/commitprogress.cpp b/adept/adept/commitprogress.cpp new file mode 100644 index 0000000..9322e27 --- /dev/null +++ b/adept/adept/commitprogress.cpp @@ -0,0 +1,117 @@ +#include <cassert> + +#include <qwidgetstack.h> +#include <qpushbutton.h> +#include <qlabel.h> +#include <kprogress.h> +#include <qlayout.h> +#include <qtimer.h> + +#include <klocale.h> +#include <kdebug.h> +#include <ktrader.h> +#include <klibloader.h> + +#include <apt-front/init.h> +#include <adept/commitprogress.h> +#include <adept/utils.h> + +using namespace adept; +using namespace aptFront; + +PkgSystem *CommitProgress::s_system = 0; + +void CommitProgress::initSystem() { + CommitProgress::s_system = new PkgSystem(); +} + +CommitProgress::CommitProgress( QWidget *p, const char *n ) + : CommitProgressUi( p, n ) +{ + assert( s_system ); + m_konsoleFrame->installEventFilter( this ); + loadKonsole(); + connect( s_system, SIGNAL( statusChanged( int, QString ) ), + this, SLOT( updateProgress( int, QString ) ) ); + connect( m_details, SIGNAL( clicked() ), + this, SLOT( toggleDetails() ) ); + m_progress->setTotalSteps( 100 ); +} + +bool CommitProgress::eventFilter( QObject *o, QEvent *e ) { + // o == m_konsoleFrame + if ( e->type() == QEvent::Resize ) { + QResizeEvent *re = dynamic_cast< QResizeEvent * >( e ); + if ( !re ) return false; + m_konsole->widget()->setGeometry( 0, 0, re->size().width(), re->size().height() ); + m_occlude->setGeometry( 0, 0, re->size().width(), re->size().height() ); + } + return false; +}; + +void CommitProgress::toggleDetails() +{ + if ( !m_occlude->isVisible() ) { + // if ( m_stack->visibleWidget() == m_konsole->widget() ) { // hide + // m_stack->raiseWidget( m_emptyPage ); + m_occlude->show(); + m_occlude->setFocus(); + m_bottomSpace->changeSize( 10, 10, QSizePolicy::Fixed, QSizePolicy::Expanding ); + m_details->setText( i18n( "Show Details" ) ); + } else { // show + m_occlude->hide(); + m_konsole->widget()->setFocus(); + // m_stack->raiseWidget( m_konsole->widget() ); + m_bottomSpace->changeSize( 10, 10, QSizePolicy::Fixed, QSizePolicy::Fixed ); + m_details->setText( i18n( "Hide Details" ) ); + } +} + +void CommitProgress::updateProgress( int p, QString msg ) +{ + m_operation->setText( msg ); + m_progress->setProgress( p ); +} + +void CommitProgress::loadKonsole() +{ + if ( s_system->terminal() ) + kdDebug() << "WARNING: Hijacking PkgSystem terminal" << endl; + + KLibFactory* factory = KLibLoader::self()->factory( "libsanekonsolepart" ); + if (!factory) + factory = KLibLoader::self()->factory( "libkonsolepart" ); + + assert( factory ); + + delete m_occlude; + m_konsole = static_cast<KParts::Part*>( + factory->create( m_konsoleFrame, "konsolepart", "QObject", + u8( "KParts::ReadOnlyPart" ) ) ); + // m_konsole->widget()->setGeometry( QRect( 0, 0, 40, 40 ) ); + + m_occlude = new QFrame( m_konsoleFrame, "m_occlude" ); + // m_occlude->setGeometry( QRect( 0, 0, 10, 10 ) ); + m_occlude->setFrameShape( QFrame::NoFrame ); + + assert( terminal() ); + + terminal()->setAutoDestroy( false ); + terminal()->setAutoStartShell( false ); + // m_stack->addWidget( m_konsole->widget() ); + + QStrList l; l.append( "echo" ); l.append( "-n" ); + terminal()->startProgram( u8( "/bin/echo" ), l ); + + s_system->setTerminal( m_konsole ); + + // m_stack->raiseWidget( m_konsole->widget() ); + // m_konsole->widget()->show(); + // m_stack->raiseWidget( m_emptyPage ); + m_operation->setText( i18n( "Idle" ) ); + QTimer::singleShot( 0, this, SLOT( toggleDetails() ) ); + if ( DEFAULT_KONSOLE_HIDDEN ) + QTimer::singleShot( 0, this, SLOT( toggleDetails() ) ); + QTimer::singleShot( 0, this, SLOT( hide() ) ); +} + diff --git a/adept/adept/commitprogress.h b/adept/adept/commitprogress.h new file mode 100644 index 0000000..ed557d7 --- /dev/null +++ b/adept/adept/commitprogress.h @@ -0,0 +1,41 @@ +/* -*- C++ -*- file adept/commitprogress.h + written by Peter Rockai <me@mornfall.net> */ + +#include <kde_terminal_interface.h> +#include <adept/dpkgpm-gui.h> +#include <adept/commitprogressui.h> +#include <kparts/part.h> + +#ifndef EPT_COMMITPROGRESS_H +#define EPT_COMMITPROGRESS_H + +namespace adept { + +class CommitProgress : public CommitProgressUi +{ + Q_OBJECT +public: + CommitProgress( QWidget *p = 0, const char *n = 0 ); + + ExtTerminalInterface *terminal() { + return static_cast<ExtTerminalInterface*>( + m_konsole->qt_cast( "ExtTerminalInterface" ) ); + } + + // needs to be called before aptFront::init() :'(( + static void initSystem(); + virtual bool eventFilter( QObject *o, QEvent *e ); + +public slots: + void updateProgress( int p, QString msg ); + void toggleDetails(); +protected: + void loadKonsole(); + KParts::Part *m_konsole; + static adept::PkgSystem *s_system; // bla... +}; + +} + + +#endif diff --git a/adept/adept/commitprogressui.ui b/adept/adept/commitprogressui.ui new file mode 100644 index 0000000..5ccecbf --- /dev/null +++ b/adept/adept/commitprogressui.ui @@ -0,0 +1,197 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::CommitProgressUi</class> +<widget class="QWidget"> + <property name="name"> + <cstring>CommitProgressUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>542</width> + <height>303</height> + </rect> + </property> + <property name="caption"> + <string>Form1</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>1</number> + </property> + <widget class="QFrame"> + <property name="name"> + <cstring>m_konsoleFrame</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <widget class="QFrame"> + <property name="name"> + <cstring>m_occlude</cstring> + </property> + <property name="geometry"> + <rect> + <x>40</x> + <y>10</y> + <width>460</width> + <height>60</height> + </rect> + </property> + <property name="frameShape"> + <enum>StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + </widget> + </widget> + <spacer> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>m_details</cstring> + </property> + <property name="text"> + <string>(details)</string> + </property> + </widget> + <widget class="KProgress" row="1" column="0"> + <property name="name"> + <cstring>m_progress</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_operation</cstring> + </property> + <property name="text"> + <string>Preparing...</string> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>m_bottomSpace</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>80</height> + </size> + </property> + </spacer> + <spacer> + <property name="name"> + <cstring>spacer6_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>32</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kprogress.h</includehint> +</includehints> +</UI> diff --git a/adept/adept/desktopentryui.ui b/adept/adept/desktopentryui.ui new file mode 100644 index 0000000..a40c766 --- /dev/null +++ b/adept/adept/desktopentryui.ui @@ -0,0 +1,116 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::DesktopEntryUi</class> +<widget class="adept::ItemExtender"> + <property name="name"> + <cstring>DesktopEntryUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>509</width> + <height>52</height> + </rect> + </property> + <property name="caption"> + <string>Form1</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>6</number> + </property> + <property name="spacing"> + <number>5</number> + </property> + <widget class="QLabel" row="0" column="1" rowspan="2" colspan="1"> + <property name="name"> + <cstring>m_icon</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QCheckBox" row="0" column="0" rowspan="2" colspan="1"> + <property name="name"> + <cstring>m_check</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> + </widget> + <widget class="QLabel" row="0" column="3"> + <property name="name"> + <cstring>m_name</cstring> + </property> + <property name="text"> + <string>(name)</string> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel" row="1" column="3"> + <property name="name"> + <cstring>m_description</cstring> + </property> + <property name="text"> + <string>(description)</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <spacer row="0" column="2" rowspan="2" colspan="1"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>6</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> +</widget> +<includes> + <include location="global" impldecl="in declaration">adept/extendablelist.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/adept/adept/desktoplist.cpp b/adept/adept/desktoplist.cpp new file mode 100644 index 0000000..de64f11 --- /dev/null +++ b/adept/adept/desktoplist.cpp @@ -0,0 +1,194 @@ +/** -*- C++ -*- + @file adept/desktoplist.cpp + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qimage.h> +#include <qlabel.h> +#include <qcursor.h> +#include <qcheckbox.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <kapplication.h> +#include <klocale.h> +#include <kdebug.h> + +#include <adept/desktoplist.h> +#include <adept/utils.h> + +namespace adept { + +DesktopEntry::DesktopEntry( QWidget *p, const char *n ) + : DesktopEntryUi( p, n ) +{ + adjustFontSize( m_description, -1 ); +} + +void DesktopEntry::resize( int w, int h ) +{ + // kdDebug() << "DesktopEntry::resize( " << w << ", " << h << " )" << endl; + int margin = layout()->margin() + layout()->spacing() * 2 + + 6 /* spacer */ + m_icon->width() + m_check->width(); + if ( m_check->isVisible() ) margin += m_check->width() + layout()->spacing(); + int hFW1 = m_name->heightForWidth( w - margin ); + int hFW2 = m_description->heightForWidth( w - margin ); + /* kdDebug() << "margin = " << margin << ", hFW1 = " << hFW1 << ", hFW2 = " + << hFW2 << endl; */ + int height = 2 * layout()->margin() + layout()->spacing() + hFW1 + hFW2; + if ( height < 32 + 2*layout()->margin() /* icon size + margin */ ) + height = 32 + 2*layout()->margin(); + // m_description->resize( w - margin, m_description->heightForWidth( w - margin ) ); + QWidget::resize( w, height ); +} + +void DesktopEntry::setItem( ExtendableItem *i ) { + m_polished = false; + ItemExtender::setItem( i ); + m_name->setText( u8( "<b>" ) + u8( entity().name() ) + u8( "</b>" ) ); + m_description->setText( u8( entity().description() ) ); + if ( !item()->list()->displayCheckboxes() ) { + m_check->hide(); + } + if ( !package().valid() || !package().hasVersion() ) { + setEnabled( false ); + } else { + connect( m_check, SIGNAL( toggled( bool ) ), + this, SLOT( toggled() ) ); + notifyPostChange(); + } +} + +void DesktopEntry::mousePressEvent( QMouseEvent *e ) { + kdDebug() << "DesktopEntry::mousePressEvent" << endl; + e->ignore(); +} + +void DesktopEntry::mouseReleaseEvent( QMouseEvent *e ) { + kdDebug() << "DesktopEntry::mouseReleaseEvent" << endl; + e->ignore(); +} + +void DesktopEntry::showEvent( QShowEvent *e ) { + DesktopEntryUi::showEvent( e ); + // DesktopEntryUi::polish(); + if ( m_polished ) return; + item()->list()->polishing(); + kdDebug() << "polish for " << entity().name() << endl; + QImage icon( KGlobal::iconLoader()->iconPath( entity().icon(), -32, true ) ); + if ( icon.isNull() ) { + icon = QImage( KGlobal::dirs()->findResource( "desktopicon", entity().icon() ) ); + } + m_icon->setPixmap( icon.isNull() ? item()->list()->emptyIcon() : + QPixmap( icon.smoothScale( 32, 32, QImage::ScaleMin ) ) ); + item()->list()->polished(); + m_polished = true; +} + +void DesktopEntry::toggled() { + /* if ( package().isInstalled() ) { + if ( package().markedRemove() ) + package().markKeep(); + else + package().markRemove(); + } else if ( package().markedInstall() ) + package().markKeep(); + else + package().markInstall(); */ + + if ( package().isInstalled() ) { + if ( package().markedRemove() ) + item()->list()->fireRequest( package(), component::State::AKeep ); + else + item()->list()->fireRequest( package(), component::State::ARemove ); + } else if ( package().markedInstall() ) + item()->list()->fireRequest( package(), component::State::AKeep ); + else + item()->list()->fireRequest( package(), component::State::AInstall ); + notifyPostChange(); +} + +void DesktopList::polishing() { + if ( m_polishing == 0 ) + QApplication::setOverrideCursor( QCursor( Qt::BusyCursor ) ); + m_polishing++; + if ( m_polishing % 10 == 0 ) + kapp->processEvents(); +} + +void DesktopList::polished() { + if ( m_polishing == childCount() ) + QApplication::restoreOverrideCursor(); +} + +void DesktopList::notifyPostChange( component::Base * ) { + utils::Range< ExtendableItem * > r = extenders(); + for ( ; r != r.end(); ++r ) { + dynamic_cast< DesktopEntry * >( (*r)->extender() )->notifyPostChange(); + } +} + +void DesktopEntry::notifyPostChange() { + if ( !package().valid() || !package().hasVersion() ) + return; + + m_check->blockSignals( true ); + m_check->setChecked( ( package().isInstalled() + || entity().package().markedInstall() ) + && !entity().package().markedRemove() ); + m_check->blockSignals( false ); +} + +DesktopList::DesktopList( QWidget *parent, const char *name ) + : ExtendableList( parent, name ), m_polishing( 0 ), m_displayCheckboxes( true ) +{ + observeComponent< component::State >(); + addColumn( i18n( "Application" ) ); + setResizeMode( LastColumn ); + setToggleColumn( -1 ); // no toggling, thanks + setExtenderHighlight( true ); + m_emptyIcon = QPixmap( + QImage( + KGlobal::iconLoader()->iconPath( u8( "exec" ), -32, false ) + ).smoothScale( 32, 32, QImage::ScaleMin ) ); + connect( this, SIGNAL( clicked( QListViewItem *, const QPoint &, int ) ), + this, SLOT( processClick( QListViewItem *, const QPoint &, int ) ) ); +} + +void DesktopList::processClick( QListViewItem *it, const QPoint &, int ) { + kdDebug() << "DesktopList::processClick..." << endl; + DesktopItem *i = dynamic_cast< DesktopItem * >( it ); + if ( !i ) return; + emit showDescription( i->entity() ); +} + +void DesktopList::insertRange( Range r ) { + m_range = r; + DesktopItem *last = 0; + int i = 0; + QApplication::setOverrideCursor( QCursor( Qt::BusyCursor ) ); + for( ; r != r.end(); r.advance() ) { + if ( i % 20 == 0 ) + kapp->processEvents(); + if ( !r->package( entity::Package() ).valid() ) + continue; + DesktopItem *i = last ? new DesktopItem( this, last ) : new DesktopItem( this ); + last = i; + i->setEntity( *r ); + ++ i; + } + QApplication::restoreOverrideCursor(); +} + +ItemExtender *DesktopItem::createExtender() { + return new DesktopEntry(); +} + +DesktopItem *DesktopEntry::item() const { + return dynamic_cast< DesktopItem * >( m_item ); +} + +entity::Desktop DesktopEntry::entity() const { + return item()->entity(); +} + +} diff --git a/adept/adept/desktoplist.h b/adept/adept/desktoplist.h new file mode 100644 index 0000000..207b9a7 --- /dev/null +++ b/adept/adept/desktoplist.h @@ -0,0 +1,117 @@ +/** -*- C++ -*- + @file adept/desktoplist.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qimage.h> +#include <klocale.h> + +#include <apt-front/cache/entity/desktop.h> +#include <adept/extendablelist.h> +#include <adept/desktopentryui.h> + +#ifndef EPT_DESKTOPLIST_H +#define EPT_DESKTOPLIST_H + +class QPopupMenu; + +namespace adept { +using namespace aptFront; +using namespace aptFront::cache; + +class DesktopItem; + +class DesktopList : public ExtendableList, public cache::Observer +{ + Q_OBJECT +public: + typedef utils::Range< entity::Desktop > Range; + DesktopList( QWidget *parent = 0, const char *name = 0 ); + void insertRange( Range ); + QPixmap emptyIcon() { return m_emptyIcon; } + void polishing(); + void polished(); + + void setTitle( QString s ) { + setColumnText( 0, i18n( "Application (" ) + s + i18n( ")" ) ); + } + + void setDisplayCheckboxes( bool d ) { m_displayCheckboxes = d; } + bool displayCheckboxes() { return m_displayCheckboxes; } + virtual void notifyPostChange( cache::component::Base * ); + void fireRequest( entity::Package p, component::State::Action a ) { + emit request( p, a ); + } +protected slots: + void processClick( QListViewItem *, const QPoint &, int ); +signals: + void request( cache::entity::Package, cache::component::State::Action ); + void showDescription( cache::entity::Desktop ); +protected: + Range m_range; + QPixmap m_emptyIcon; + int m_polishing; + bool m_displayCheckboxes; +}; + +class DesktopEntry : public DesktopEntryUi +{ + Q_OBJECT +public: + DesktopEntry( QWidget * = 0, const char * = 0 ); + DesktopItem *item() const; + entity::Desktop entity() const; + void setItem( ExtendableItem * ); + entity::Package package() { return entity().package(); } + virtual void notifyPostChange(); + virtual void resize( int, int ); + // virtual void polish(); +public slots: + void toggled(); +protected: + virtual void mousePressEvent( QMouseEvent *e ); + virtual void mouseReleaseEvent( QMouseEvent *e ); + virtual void showEvent( QShowEvent * ); + bool m_polished; +}; + +class DesktopItem : public ExtendableItem +{ +public: + ItemExtender *createExtender(); + DesktopItem( DesktopList *l ) + : ExtendableItem( l ), m_delayedDone( false ) + { + } + DesktopItem( DesktopList *v, DesktopItem *i ) + : ExtendableItem( v, i ), m_delayedDone( false ) + { + } + + void setup() { + ExtendableItem::setup(); + if (m_delayedDone) + return; + m_delayedDone = true; + showExtender(); + } + + DesktopList *list() { return dynamic_cast< DesktopList * >( listView() ); } + + QString text( int ) const { return QString( "you shouldn't see this" ); } + entity::Desktop entity() const { return m_entity; } + void setEntity( entity::Desktop e ) { m_entity = e; } + + virtual bool less( const ExtendableItem *other ) const { + const DesktopItem *o = dynamic_cast< const DesktopItem * >( other ); + return entity() < o->entity(); + } + +protected: + entity::Desktop m_entity; + bool m_delayedDone:1; +}; + +} + +#endif diff --git a/adept/adept/dpkgpm-gui.cpp b/adept/adept/dpkgpm-gui.cpp new file mode 100644 index 0000000..828d18f --- /dev/null +++ b/adept/adept/dpkgpm-gui.cpp @@ -0,0 +1,258 @@ +/** -*- C++ -*- + @file adept/dpkgpm-gui.cpp + @author Peter Rockai <me@mornfall.net> +*/ + +#include <fcntl.h> +#include <iostream> + +#include <qstrlist.h> +#include <kapplication.h> +#include <klistbox.h> +#include <klocale.h> +#include <kparts/part.h> + +#include <apt-pkg/configuration.h> +#include <apt-pkg/error.h> + +#include <apt-front/cache/cache.h> +#include <apt-front/cache/component/packages.h> +#include <apt-front/cache/entity/package.h> + +#include <adept/dpkgpm-gui.h> +#include <adept/utils.h> + +using namespace aptFront; +using namespace cache; + +namespace adept { + +PkgSystem::PkgSystem() + : m_terminalPart( 0 ) +{ + std::cerr << "kapture::PkgSystem::PkgSystem()" << std::endl; + Label = "adeptDPkgSystem"; +} + +void PkgSystem::setTerminal( KParts::Part *t ) +{ + m_terminalPart = t; +} + +pkgPackageManager *PkgSystem::CreatePM( pkgDepCache *c ) const +{ + std::cerr << "kapture::PkgSystem::CreatePM()" << std::endl; + adept::DPkgPM *pm = new adept::DPkgPM( c, m_terminalPart ); + connect( pm, SIGNAL( statusChanged( int, QString ) ), + this, SIGNAL( statusChanged( int, QString ) ) ); + return pm; +} + +DPkgPM::DPkgPM( pkgDepCache *cache, KParts::Part *t ) + : aptFront::DPkgPM (cache), m_terminalPart (t) +{ +} + +bool DPkgPM::forkDpkg( char *const argv[] ) +{ + bool ok = true; + std::cerr << "adept::DPkgPM::forkDpkg ()" << std::endl; + QStrList l; + for (int i = 0; argv[i]; i ++) + l.append( argv[i] ); + + m_processRunning = true; + connect( m_terminalPart, SIGNAL( processExited( KProcess * ) ), + this, SLOT( processExit( KProcess * ) ) ); + connect( m_terminalPart, SIGNAL( processExited( const KProcess * ) ), + this, SLOT( processExitC( const KProcess * ) ) ); + connect( m_terminalPart, SIGNAL( forkedChild() ), + this, SLOT( setupDpkgChild() ) ); + + terminal()->startProgram( u8( argv[0] ), l ); + + ::close( m_dpkgPipe[1] ); + ::fcntl( m_dpkgPipe[0], F_SETFL, O_NONBLOCK ); + + while (m_processRunning) { + dpkgMonitor(); + usleep( 50000 ); + } + + if (m_exitedProcess->normalExit()) { + if (m_exitedProcess->exitStatus() != 0) { + ok = _error->Error( "Child for %s exited with error %d", + argv [0], m_exitedProcess->exitStatus()); + } + } else { + ok = _error->Error( "Child for %s was killed by signal %d", + argv [0], m_exitedProcess->exitSignal()); + } + + if (ok) // do we run scripts in case dpkg died??? + ok = runScripts ("DPkg::Post-Invoke", false); + + return ok; +} + +ExtTerminalInterface *DPkgPM::terminal() { + return static_cast<ExtTerminalInterface *>( + m_terminalPart->qt_cast( "ExtTerminalInterface" ) ); +} + +bool DPkgPM::forkScript (const char *cmd, bool fP) +{ + std::cerr << "adept::DPkgPM::forkScript(\"" << cmd << "\")" << std::endl; + if (fP) { + if (pipe( m_scriptPipe ) != 0) + return _error->Errno( + "pipe","Failed to create IPC pipe to subprocess"); + SetCloseExec (m_scriptPipe[0], true); + SetCloseExec (m_scriptPipe[1], true); + } + QStrList l; + l.append ("/bin/sh"); + l.append ("-c"); + l.append (cmd); + if (fP) { + connect( m_terminalPart, SIGNAL( forkedChild() ), + this, SLOT( setupScriptPipe() ) ); + } + + connect( m_terminalPart, SIGNAL( processExited( KProcess * ) ), + this, SLOT( processExit( KProcess * ) ) ); + connect( m_terminalPart, SIGNAL( processExited( const KProcess * ) ), + this, SLOT( processExitC( const KProcess * ) ) ); + + m_processRunning = true; + terminal()->startProgram( u8( "/bin/sh" ), l); + + if (fP) { + if (!feedPackages()) + return _error->Error("Failed feeding packages to script"); + } + + while (m_processRunning) { + kapp->processEvents(); + usleep(50000); + } + + std::cerr << "END: adept::DPkgPM::forkScript(\"" + << cmd << "\")" << std::endl; + + if (m_exitedProcess->normalExit()) { + if (m_exitedProcess->exitStatus() != 0) { + return _error -> Error("Child for %s exited with error %d", + cmd, m_exitedProcess->exitStatus()); + } else { + return true; + } + } else { + return _error->Error("Child for %s was killed by signal %d", + cmd, m_exitedProcess->exitSignal()); + } +} + +void DPkgPM::processExit(KProcess *p) { + processExitC( p ); +} + +void DPkgPM::processExitC(const KProcess *p) +{ + std::cerr << "a process exited!" << std::endl; + m_processRunning = false; + m_exitedProcess = p; +} + +void DPkgPM::setupScriptPipe() +{ + // setupScript(); + // std::cerr << "setupScriptPipe()" << std::endl; + dup2 (m_scriptPipe[0], STDIN_FILENO); +} + +void DPkgPM::setupDpkgChild() +{ + // setupScript(); + // std::cerr << "setupDpkgChild()" << std::endl; + setupChild(); +} + +bool DPkgPM::Go( int ) +{ + std::cerr << "kapture::DPkgPM::Go ()" << std::endl; + statusChanged( 0, i18n( "Preparing..." ) ); + bool ret = aptFront::DPkgPM::Go(-1); + QStrList l; + l.append("echo"); + l.append("dpkg run finished!"); + terminal()->startProgram( u8( "echo" ), l ); + statusChanged( 100, i18n( "Done" ) ); + return ret; +} + +void DPkgPM::dpkgMonitor () +{ + aptFront::DPkgPM::dpkgMonitor(); + kapp->processEvents(); +} + +void DPkgPM::updateStatus( std::string pkg, std::string ev, std::string r ) +{ + std::string op, msg; + aptFront::DPkgPM::updateStatus( pkg, ev, r ); + entity::Package p = cache::Global::get().packages().packageByName( pkg ); + + if ( m_currentOp == OInstall ) { + if ( p.markedNewInstall() ) { + if ( ev == "half-installed" ) + msg = u8( i18n( "Preparing installation of %1..." ) ); + else if ( ev == "unpacked" ) + msg = u8( i18n( "Unpacking %1..." ) ); + } else if ( p.markedUpgrade() ) { + if ( ev == "half-installed" ) + msg = u8( i18n( "Preparing upgrade of %1..." ) ); + else if ( ev == "unpacked" || ev == "half-configured" ) + msg = u8( i18n( "Replacing %1 with new version..." ) ); + } + } else if ( m_currentOp == OConfigure ) { + if ( p.markedNewInstall() ) { + if ( ev == "unpacked" ) + msg = u8( i18n( "Preparing to configure %1..." ) ); + else if ( ev == "half-configured" ) + msg = u8( i18n( "Configuring %1..." ) ); + else if ( ev == "installed" ) + msg = u8( i18n( "Installed %1" ) ); + } else if ( p.markedUpgrade() ) { + if ( ev == "unpacked" ) + msg = u8( i18n( "Preparing to configure new version of %1..." ) ); + else if ( ev == "half-configured" ) + msg = u8( i18n( "Configuring new version of %1..." ) ); + else if ( ev == "installed" ) + msg = u8( i18n( "Upgraded %1" ) ); + } + } else if ( m_currentOp == ORemove ) { + if ( ev == "installed" ) + msg = u8( i18n( "Preparing to remove %1..." ) ); + else if ( ev == "half-configured" || ev == "half-installed" ) + msg = u8( i18n( "Removing %1..." ) ); + else if ( ev == "config-files" || ev == "not-installed" ) + msg = u8( i18n( "Removed %1" ) ); + } else if ( m_currentOp == OPurge ) { + if ( ev == "config-files" ) + msg = u8( i18n( "Preparing to purge %1..." ) ); + else if ( ev == "not-installed" ) + msg = u8( i18n( "Purged %1" ) ); + } + + std::cerr << "updateStatus( " << pkg << ", " << ev << ", " << r << ")" << std::endl; + std::cerr << "updateStatus: msg = " << msg << std::endl; + std::cerr << "updateStatus: seen = " << m_seenOpCount + << ", total = " << m_totalOpCount << std::endl; + statusChanged( ( m_seenOpCount * 100 ) / m_totalOpCount, + u8( msg ).arg( pkg ) + ( ( r == "") ? "" : (" (" + r + ")") ) ); +} + +} + +#include "dpkgpm-gui.moc" diff --git a/adept/adept/dpkgpm-gui.h b/adept/adept/dpkgpm-gui.h new file mode 100644 index 0000000..435ee7f --- /dev/null +++ b/adept/adept/dpkgpm-gui.h @@ -0,0 +1,68 @@ +/** -*- C++ -*- + @file adept/dpkgpm-gui.h + @author Peter Rockai <me@mornfall.net> +*/ + +#ifndef EPT_DPKGPM_H +# define EPT_DPKGPM_H + +#include <apt-pkg/debsystem.h> +#include <adept/dpkgpm.h> +#include <kde_terminal_interface.h> +#include <kprocess.h> +#include <kdialogbase.h> + +class KListBox; +namespace KParts { +class Part; +} + +namespace adept { + +class PkgSystem : public QObject, public debSystem +{ + Q_OBJECT +public: + PkgSystem (); + virtual pkgPackageManager *CreatePM( pkgDepCache *Cache ) const; + virtual void setTerminal( KParts::Part *t ); + KParts::Part *terminal() { return m_terminalPart; } + virtual int Score( Configuration const &Cnf ) { + return debSystem::Score (Cnf) + 2; }; +protected: + KParts::Part *m_terminalPart; +signals: + void statusChanged( int p, QString m ); +}; + +class DPkgPM : public QObject, public aptFront::DPkgPM +{ + Q_OBJECT +public: + DPkgPM (pkgDepCache *c, KParts::Part *t); + virtual bool forkDpkg (char *const argv[]); + virtual void dpkgMonitor (void); + virtual bool Go (int); + virtual bool forkScript (const char *, bool); + ExtTerminalInterface *terminal(); + virtual void updateStatus( std::string pkg, std::string ev, std::string r ); + +public slots: + void processExitC(const KProcess *p); + void processExit(KProcess *p); + void setupScriptPipe(); + void setupDpkgChild(); + +signals: + void statusChanged( int p, QString m ); + +protected: + KParts::Part *m_terminalPart; + // DPkgProgress *m_prog; + bool m_processRunning:1; + const KProcess *m_exitedProcess; +}; + +} + +#endif diff --git a/adept/adept/dpkgpm.cpp b/adept/adept/dpkgpm.cpp new file mode 100644 index 0000000..f4b4f0d --- /dev/null +++ b/adept/adept/dpkgpm.cpp @@ -0,0 +1,462 @@ +/** -*- C++ -*- + @file adept/dpkgpm.cpp + @author Peter Rockai <me@mornfall.net> +*/ + +#include <apt-pkg/configuration.h> +#include <apt-pkg/error.h> +#include "dpkgpm.h" +#include <signal.h> +#include <sys/wait.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include <apt-front/cache/cache.h> +#include <apt-front/cache/component/packages.h> +#include <apt-front/cache/entity/package.h> + +#include <iostream> +#include <sstream> + +using namespace std; +using namespace aptFront; +using namespace cache; + +/* === PkgSystem === */ +DPkgPM::DPkgPM (pkgDepCache *C) + : pkgDPkgPM (C), m_seenOpCount( 0 ), m_totalOpCount( 0 ) +{ +} + +bool DPkgPM::Go( int ) +{ + cerr << "DPkgPM::Go()" << endl; + computeTotals(); + if (runScripts ("DPkg::Pre-Invoke", false) == false) + return false; + if (runScripts ("DPkg::Pre-Install-Pkgs", true) == false) + return false; + + for (vector<Item>::iterator I = List.begin(); I != List.end();) { + char *const *argv; + if (! setupArgs (&argv, I)) + return false; + + cerr << "running '"; + for (unsigned int k = 0; argv [k]; k++) + cerr << argv[k] << ' '; + cerr << "'" << endl; + if (_config->FindB("Debug::pkgDPkgPM",false) == true) + { + for (unsigned int k = 0; argv [k]; k++) + cerr << argv[k] << ' '; + cerr << endl; + continue; + } + + if (! forkDpkg (argv)) + return false; + delete[] argv; + if (! runScripts ("DPkg::Post-Invoke", false)) + return false; + } + return true; +} + +void DPkgPM::computeTotals() +{ + m_totalOpCount = 0; + for (vector<Item>::iterator I = List.begin(); I != List.end();I++) + { + entity::Package p = cache::Global::get().packages().packageByName( + I->Pkg.Name() ); + int x = 0; + switch ( I->Op ) { + case Item::Remove: x = 4; break; + case Item::Install: p.markedUpgrade() ? x = 3 : x = 2; break; + case Item::Purge: x = 2; break; + case Item::Configure: x = 3; break; + } + m_totalOpCount += x; + } +} + +bool DPkgPM::forkDpkg (char *const argv[]) +{ + cerr << "DPkgPM::forkDpkg ()" << endl; + cout << flush; + clog << flush; + cerr << flush; + + /* Mask off sig int/quit. We do this because dpkg also does when + it forks scripts. What happens is that when you hit ctrl-c it sends + it to all processes in the group. Since dpkg ignores the signal + it doesn't die but we do! So we must also ignore it */ + sighandler_t old_SIGQUIT = signal(SIGQUIT,SIG_IGN); + sighandler_t old_SIGINT = signal(SIGINT,SIG_IGN); + + // Fork dpkg + pid_t Child = ExecFork(); + if (Child == 0) { + if (! setupChild ()) { + cerr << "Error in dpkg post-fork setup!" << endl; + _exit (100); + } + execvp (argv [0], argv); + cerr << "Error executing dpkg!" << endl; + _exit (100); + } + + close( m_dpkgPipe[1] ); + fcntl( m_dpkgPipe[0], F_SETFL, O_NONBLOCK ); + + int Status = 0; + int ret = 0; + while ((ret = waitpid (Child, &Status, WNOHANG)) != Child) { + if (errno == EINTR || ret == 0) { + dpkgMonitor (); + usleep (200000); // 0.2 second hang + continue; + } + runScripts ("DPkg::Post-Invoke", false); + + signal(SIGQUIT,old_SIGQUIT); + signal(SIGINT,old_SIGINT); + return _error -> Errno ("waitpid","Couldn't wait for subprocess"); + } + + signal(SIGQUIT,old_SIGQUIT); + signal(SIGINT,old_SIGINT); + + // Check for an error code. + if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0) + { + runScripts ("DPkg::Post-Invoke", false); + if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV) + return _error->Error("Sub-process %s received a segmentation fault.", argv [0]); + + if (WIFEXITED(Status) != 0) + return _error->Error("Sub-process %s returned an error code (%u)", argv[0], WEXITSTATUS(Status)); + + return _error->Error("Sub-process %s exited unexpectedly", argv[0]); + } + + return true; +} + +bool DPkgPM::setupArgs (char *const**a, std::vector<Item>::iterator &I) +{ + cerr << "DPkgPM::setupArgs ()" << endl; + unsigned int MaxArgs = _config->FindI("Dpkg::MaxArgs",350); + unsigned int MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes",8192); + + vector<Item>::iterator J = I; + for (; J != List.end() && J->Op == I->Op; J++); + + // Generate the argument list + const char **Args = new const char *[MaxArgs + 50]; + if (J - I > (signed)MaxArgs) + J = I + MaxArgs; + + unsigned int n = 0; + unsigned long Size = 0; + string Tmp = _config->Find("Dir::Bin::dpkg","dpkg"); + Args[n++] = Tmp.c_str(); + Size += strlen(Args[n-1]); + + // Stick in any custom dpkg options + Configuration::Item const *Opts = _config->Tree("DPkg::Options"); + if (Opts != 0) + { + Opts = Opts->Child; + for (; Opts != 0; Opts = Opts->Next) + { + if (Opts->Value.empty() == true) + continue; + Args[n++] = Opts->Value.c_str(); + Size += Opts->Value.length(); + } + } + + pipe( m_dpkgPipe ); + stringstream fds; + fds << m_dpkgPipe[1]; + std::cerr << "reading end of the pipe: " << m_dpkgPipe[0] << std::endl; + + Args[n++] = "--status-fd"; + Size += strlen(Args[n-1]); + // bah, we leak a string every time we run dpkg... silly eh + Args[n++] = ( new string( fds.str() ) )->c_str(); + Size += strlen(Args[n-1]); + + switch (I->Op) + { + case Item::Remove: + Args[n++] = "--force-depends"; + Size += strlen(Args[n-1]); + Args[n++] = "--force-remove-essential"; + Size += strlen(Args[n-1]); + Args[n++] = "--remove"; + Size += strlen(Args[n-1]); + m_currentOp = ORemove; + break; + + case Item::Purge: + Args[n++] = "--force-depends"; + Size += strlen(Args[n-1]); + Args[n++] = "--force-remove-essential"; + Size += strlen(Args[n-1]); + Args[n++] = "--purge"; + Size += strlen(Args[n-1]); + m_currentOp = OPurge; + break; + + case Item::Configure: + Args[n++] = "--configure"; + Size += strlen(Args[n-1]); + m_currentOp = OConfigure; + break; + + case Item::Install: + Args[n++] = "--unpack"; + Size += strlen(Args[n-1]); + m_currentOp = OInstall; + break; + } + + // Write in the file or package names + if (I->Op == Item::Install) + { + for (;I != J && Size < MaxArgBytes; I++) + { + if (I->File[0] != '/') + return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str()); + Args[n++] = I->File.c_str(); + Size += strlen(Args[n-1]); + } + } + else + { + for (;I != J && Size < MaxArgBytes; I++) + { + Args[n++] = I->Pkg.Name(); + Size += strlen(Args[n-1]); + } + } + Args[n] = 0; + J = I; + *a = (char *const *)Args; + return true; +} + +bool DPkgPM::setupChild () +{ + // cerr << "DPkgPM::setupChild ()" << endl; + if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0) + return false; + + if (_config->FindB("DPkg::FlushSTDIN",true) == true && isatty(STDIN_FILENO)) + { + int Flags,dummy; + if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0) + return false; + + // Discard everything in stdin before forking dpkg + if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0) + return false; + + while (read(STDIN_FILENO,&dummy,1) == 1); + + if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0) + return false; + } + + /* No Job Control Stop Env is a magic dpkg var that prevents it + from using sigstop */ + putenv("DPKG_NO_TSTP=yes"); + close( m_dpkgPipe[0] ); + + return true; +} + +void DPkgPM::dpkgMonitor () +{ + char buf[1024]; + int r = read( m_dpkgPipe[0], buf, 1023 ); + + if ( r > 0 ) { + buf[r] = 0; + std::string b( buf ); + + // parse status updates from dpkg + while ( true ) { + std::string::size_type colon, nl = b.find( '\n' ); + m_statusBuffer.append( string( b, 0, nl ) ); + if ( nl == std::string::npos ) + break; + + // cerr << "dpkg status completed line: " << m_statusBuffer << endl; + colon = m_statusBuffer.find( ": " ); + string l( m_statusBuffer, 0, colon ); + string r( m_statusBuffer, colon + 2, string::npos ); + + if ( l == "status" ) { + colon = r.find( ": " ); + std::string p( r, 0, colon ); + r = string( r, colon + 2, string::npos ); + + colon = r.find( ": " ); + std::string e( r, 0, colon ); + if ( colon == string::npos ) + r = ""; + else + r = string( r, colon + 2, string::npos ); + updateStatus( p, e, r ); + } + + b = string( b, nl + 1, string::npos ); + m_statusBuffer = string(); + nl = b.find( '\n' ); + } + } +} + +void DPkgPM::updateStatus( std::string pkg, std::string ev, std::string r ) +{ + //std::cerr << "DPkgPM::updateStatus " << pkg << " " << ev << " " << r + // << std::endl; + if (ev.find("error") != string::npos) { + char* list[5]; + char *line = strdup(m_statusBuffer.c_str()); + TokSplitString(':', line, list, sizeof(list)/sizeof(list[0])); + WriteApportReport(list[1], list[3]); + free(line); + return; + } + + OpAndStatus os = std::make_pair( m_currentOp, ev ); + if ( m_seenOps[ std::make_pair( os, pkg ) ] == 0 ) { + m_seenOpCount++; + m_seenOps[ std::make_pair( os, pkg ) ] = 1; + } +} + +bool DPkgPM::runScripts (const char *Cnf, bool sP) +{ + cerr << "DPkgPM::runScripts ('" << Cnf << "', " << sP << ")" << endl; + Configuration::Item const *Opts = _config->Tree(Cnf); + if (Opts == 0 || Opts->Child == 0) + return true; + Opts = Opts->Child; + + unsigned int Count = 1; + for (; Opts != 0; Opts = Opts->Next, Count++) + { + if (Opts->Value.empty() == true) + continue; + + // Determine the protocol version + string OptSec = Opts->Value; + string::size_type Pos; + if ((Pos = OptSec.find(' ')) == string::npos || Pos == 0) + Pos = OptSec.length(); + OptSec = "DPkg::Tools::Options::" + string(Opts->Value.c_str(),Pos); + + m_version = _config->FindI (OptSec + "::Version", 1); + + // Purified Fork for running the script + // pid_t Process = ExecFork(); + forkScript (Opts->Value.c_str(), sP); + } + + return true; +} + +bool DPkgPM::SendV1Pkgs (FILE *F) +{ + bool Die = false; + for (vector<Item>::iterator I = List.begin(); I != List.end(); ++I) + { + // Only deal with packages to be installed from .deb + if (I->Op != Item::Install) + continue; + + // No errors here.. + if (I->File[0] != '/') + continue; + + /* Feed the filename of each package that is pending install + into the pipe. */ + fprintf(F,"%s\n",I->File.c_str()); + if (ferror(F) != 0) + { + Die = true; + break; + } + } + return ! Die; +} + +bool DPkgPM::forkScript (const char *cmd, bool fP) +{ + cerr << "DPkgPM::forkScript ()" << endl; + if (fP) { + if (pipe( m_scriptPipe ) != 0) + return _error -> Errno("pipe", "Failed to create IPC pipe to subprocess"); + SetCloseExec( m_scriptPipe[ 0 ], true ); + SetCloseExec( m_scriptPipe[ 1 ], true ); + } + pid_t Process = ExecFork (); + if (Process == 0) + { + setupScript (cmd, fP); + + const char *Args[4]; + Args[0] = "/bin/sh"; + Args[1] = "-c"; + Args[2] = cmd; + Args[3] = 0; + execv(Args[0],(char **)Args); + _exit(100); + } + + if (fP) { + if (! feedPackages ()) + return _error -> Error ("Failed feeding packages to script"); + } + + // Clean up the sub process + if (ExecWait (Process, cmd) == false) + return _error -> Error("Failure running script %s", cmd); +} + +void DPkgPM::setupScript (const char * /*cmd*/, bool fP) +{ + cerr << "DPkgPM::setupScript ()" << endl; + if (fP) { + dup2 (m_scriptPipe [0], STDIN_FILENO); + SetCloseExec(STDOUT_FILENO, false); + SetCloseExec(STDIN_FILENO, false); + SetCloseExec(STDERR_FILENO, false); + } +} + +bool DPkgPM::feedPackages () +{ + close(m_scriptPipe[ 0 ]); + + FILE *F = fdopen(m_scriptPipe[ 1 ], "w"); + if (F == 0) + return _error->Errno("fdopen","Faild to open new FD"); + + // Feed it the filenames. + bool Die = false; + if (m_version <= 1) + Die = !SendV1Pkgs (F); + else + Die = !SendV2Pkgs(F); + + fclose(F); + return ! Die; +} diff --git a/adept/adept/dpkgpm.h b/adept/adept/dpkgpm.h new file mode 100644 index 0000000..b899693 --- /dev/null +++ b/adept/adept/dpkgpm.h @@ -0,0 +1,49 @@ +/** -*- C++ -*- + @file adept/dpkgpm.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <apt-pkg/dpkgpm.h> +#include <string> +#include <vector> +#include <map> + +#ifndef DPKGPM_H +# define DPKGPM_H + +namespace aptFront { + +class DPkgPM : public pkgDPkgPM { +protected: + enum Op { ORemove, OPurge, OConfigure, OInstall }; + Op m_currentOp; + int m_dpkgPipe[2]; + int m_scriptPipe[2]; + unsigned m_version; + std::string m_statusBuffer; + typedef std::pair< Op, std::string > OpAndStatus; + typedef std::map< std::pair< OpAndStatus, std::string >, int > SeenOps; + SeenOps m_seenOps; + int m_totalOpCount; + int m_seenOpCount; +public: + DPkgPM (pkgDepCache *C); + virtual bool Go ( int ); + virtual void computeTotals(); + virtual bool setupArgs (char *const **a, std::vector<Item>::iterator &I); + virtual bool forkDpkg (char *const argv[]); + virtual bool forkScript (const char *, bool); + virtual bool runScripts (const char *, bool); + virtual bool setupChild (); + virtual void setupScript (const char *, bool); + virtual void dpkgMonitor (void); + virtual bool SendV1Pkgs (FILE *); + virtual bool feedPackages (void); + virtual void updateStatus( std::string pkg, std::string ev, std::string r ); +}; + +} + + +#endif /* ifndef DPKGPM_H */ + diff --git a/adept/adept/easytagfilter.cpp b/adept/adept/easytagfilter.cpp new file mode 100644 index 0000000..3049d60 --- /dev/null +++ b/adept/adept/easytagfilter.cpp @@ -0,0 +1,81 @@ +#include <apt-front/predicate/combinators.h> +#include <apt-front/predicate/factory.h> +#include <klocale.h> +#include <kdebug.h> +#include <qcombobox.h> +#include <qpushbutton.h> +#include "easytagfilter.h" + +using namespace aptFront; +using namespace adept; + +static void fillCombo( QComboBox *c, const std::string f ) { + Cache &cache = cache::Global::get(); // FIXME? + std::set< ept::debtags::Tag > t; + t = cache.tags().tags( f ); + for (std::set< ept::debtags::Tag >::iterator i = t.begin(); i != t.end(); ++ i) { + c->insertItem( i->name() ); + } +} + +EasyTagFilterWidget::EasyTagFilterWidget( QWidget *parent, const char *name ) + : EasyTagFilterUi( parent, name ) +{ + fillCombo( m_use, "use" ); + fillCombo( m_interface, "interface" ); + fillCombo( m_worksWith, "works-with" ); + fillCombo( m_role, "role" ); + connect( m_use, SIGNAL( activated( int ) ), + this, SLOT( widgetsChanged() ) ); + connect( m_interface, SIGNAL( activated( int ) ), + this, SLOT( widgetsChanged() ) ); + connect( m_worksWith, SIGNAL( activated( int ) ), + this, SLOT( widgetsChanged() ) ); + connect( m_role, SIGNAL( activated( int ) ), + this, SLOT( widgetsChanged() ) ); + connect( m_reset, SIGNAL( clicked() ), + this, SLOT( reset() ) ); +} + +static void setFacet( QComboBox *c, const std::string fac, + EasyTagFilter< entity::Package > &f ) +{ + if (c->currentItem()) + f.set( fac, c->currentText() ); +} + +EasyTagFilterWidget::Predicate EasyTagFilterWidget::predicate() +{ + EasyTagFilter< entity::Package > f; + setFacet( m_use, "use", f ); + setFacet( m_interface, "interface", f ); + setFacet( m_worksWith, "works-with", f ); + setFacet( m_role, "role", f ); + return predicate::adapt< entity::Entity >( f ); +} + +static void setCombo( QComboBox *c, const std::string &t ) { + c->blockSignals( true ); + if (t == "") + c->setCurrentItem( 0 ); + else + c->setCurrentText( t ); + c->blockSignals( false ); +} + +void EasyTagFilterWidget::predicateChanged() { + typedef EasyTagFilter< entity::Package > F; + F f = downcast< F >( m_pred ); + setCombo( m_use, f.get( "use" ) ); + setCombo( m_interface, f.get( "interface" ) ); + setCombo( m_role, f.get( "role" ) ); + setCombo( m_worksWith, f.get( "works-with" ) ); +} + +void EasyTagFilterWidget::reset() { + setCombo( m_use, "" ); + setCombo( m_interface, "" ); + setCombo( m_role, "" ); + setCombo( m_worksWith, "" ); + emit widgetsChanged(); +} diff --git a/adept/adept/easytagfilter.h b/adept/adept/easytagfilter.h new file mode 100644 index 0000000..66977d5 --- /dev/null +++ b/adept/adept/easytagfilter.h @@ -0,0 +1,93 @@ +/** -*- C++ -*- + @file adept/quickfilter.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <klocale.h> +#include <qlayout.h> +#include <kdebug.h> + +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/entity/package.h> +//#include <apt-front/cache/component/tags.h> +#include <apt-front/predicate/factory.h> + +#include <adept/easytagfilterui.h> +#include <adept/filterlist.h> +#include <adept/lister.h> + +#ifndef EPT_EASYTAGFILTER_H +#define EPT_EASYTAGFILTER_H + +namespace adept { + +template< typename T > +struct EasyTagFilter : predicate::Implementation< T, EasyTagFilter< T > >, + InterfacingPredicate +{ + typedef std::map< std::string, std::string > Tags; + + EasyTagFilter() { + setupPredicate(); + } + + void setupPredicate() { + Cache &cache = cache::Global::get(); // FIXME? + m_op = predicate::True< T >(); + for (Tags::iterator i = m_tags.begin(); i != m_tags.end(); ++i ) { + m_op = m_op and predicate::Factory< T >::tag( + cache.tags().tagByName( i->first + "::" + i->second ) ); + // kdDebug() << t.summary() << endl; + } + } + + std::string summary() const { + std::string r( i18n( "EasyTag filter: " ).local8Bit() ); + for (Tags::const_iterator j, i = m_tags.begin(); + i != m_tags.end(); ++i ) { + j = i; ++j; + r += i->first + ": " + i->second; + if (j != m_tags.end()) + r += ", "; + } + return r; + } + + void parseArguments( const predicate::ArgumentList & ) {} + + bool operator==( const EasyTagFilter &o ) const { + return o.m_tags == m_tags; + } + + bool operator()( const T &p ) { + return m_op( p ); + } + + void set( const std::string &f, const std::string &t ) { + m_tags[f] = t; + setupPredicate(); + } + + std::string get( const std::string &f ) { + return m_tags[ f ]; + } + +protected: + Tags m_tags; + predicate::Predicate< T > m_op; +}; + +class EasyTagFilterWidget : public EasyTagFilterUi +{ + Q_OBJECT +public: + EasyTagFilterWidget( QWidget *parent, const char *name = 0 ); + virtual Predicate predicate(); +public slots: + void predicateChanged(); + void reset(); +}; + +} + +#endif diff --git a/adept/adept/easytagfilterui.ui b/adept/adept/easytagfilterui.ui new file mode 100644 index 0000000..998bf2b --- /dev/null +++ b/adept/adept/easytagfilterui.ui @@ -0,0 +1,201 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::EasyTagFilterUi</class> +<widget class="adept::PredicateInterface"> + <property name="name"> + <cstring>EasyTagFilterUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>611</width> + <height>116</height> + </rect> + </property> + <property name="caption"> + <string>QuickFilterUi</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>2</number> + </property> + <property name="spacing"> + <number>1</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_title</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><b>Easy Tag Filter</b></string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="1" column="2"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Works With:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Role:</string> + </property> + </widget> + <widget class="QComboBox" row="1" column="3"> + <item> + <property name="text"> + <string>Anything</string> + </property> + </item> + <property name="name"> + <cstring>m_worksWith</cstring> + </property> + </widget> + <widget class="QPushButton" row="1" column="4"> + <property name="name"> + <cstring>m_reset</cstring> + </property> + <property name="text"> + <string>Reset Filter</string> + </property> + </widget> + <widget class="QComboBox" row="0" column="3"> + <item> + <property name="text"> + <string>Any</string> + </property> + </item> + <property name="name"> + <cstring>m_interface</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Use:</string> + </property> + </widget> + <widget class="QComboBox" row="0" column="1"> + <item> + <property name="text"> + <string>Any</string> + </property> + </item> + <property name="name"> + <cstring>m_use</cstring> + </property> + </widget> + <widget class="QComboBox" row="1" column="1"> + <item> + <property name="text"> + <string>Any</string> + </property> + </item> + <property name="name"> + <cstring>m_role</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Interface:</string> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>130</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<includes> + <include location="global" impldecl="in declaration">adept/filterlist.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/adept/adept/extendablelist.cpp b/adept/adept/extendablelist.cpp new file mode 100644 index 0000000..c3abf1d --- /dev/null +++ b/adept/adept/extendablelist.cpp @@ -0,0 +1,339 @@ +#include <kdebug.h> +#include <qtimer.h> +#include <qobjectlist.h> +#include <qpainter.h> +#include <qimage.h> +#include <kiconeffect.h> +#include <kiconloader.h> + +#include <adept/extendablelist.h> +#include <adept/utils.h> + +using namespace adept; + +ExtendableList::ExtendableList( QWidget *p, const char *n ) + : KListView( p, n ), + m_toggleColumn( 0 ), m_inDtor( false ), + m_extenderUpdateScheduled( false ), + m_needSort( false ), + m_extenderHighlight( false ) +{ + // kdDebug() << "connecting processClick har har" << endl; + connect( this, SIGNAL( clicked( QListViewItem *, + const QPoint &, int ) ), + this, SLOT( processClick( QListViewItem *, + const QPoint &, int ) ) ); + connect( this, SIGNAL( moved() ), + this, SLOT( delayedUpdateExtenders() ) ); + connect( this, SIGNAL( collapsed( QListViewItem * ) ), + this, SLOT( delayedUpdateExtenders() ) ); + connect( this, SIGNAL( expanded( QListViewItem * ) ), + this, SLOT( delayedUpdateExtenders() ) ); + setTreeStepSize( 15 ); + + m_baseIcon = SmallIcon( u8( "extender_closed" ) ); + m_extendedIcon = SmallIcon( u8( "extender_opened" ) ); + QImage img; + img = m_baseIcon; + KIconEffect::toGray( img, 1.0 ); + m_unextendableIcon = QPixmap( img ); +} + +void ExtendableList::keyPressEvent( QKeyEvent *e ) { + ExtendableItem *item = dynamic_cast< ExtendableItem* >( currentItem() ); + if ( item ) { + if ( item->extendable() ) { + if ( item->extender() && e->key() == Qt::Key_Left ) { + return item->hideExtender(); + } else if ( !item->extender() && e->key() == Qt::Key_Right ) { + return item->showExtender(); + } + } + KListView::keyPressEvent( e ); + if ( e->key() == Qt::Key_Left || e->key() == Qt::Key_Right ) + item->updateIcon(); + } else return KListView::keyPressEvent( e ); +} + +void ExtendableList::openToplevel() { + QListViewItem *i; + for ( i = firstChild(); i != 0; i = i->nextSibling() ) { + i->setOpen( true ); + } +} + +int ExtendableList::extenderOffset( ExtendableItem *i ) +{ + int c = 0, x = 0; + + while( c < m_toggleColumn ) { + x += columnWidth( c ); + c ++; + } + + if ( m_toggleColumn >= 0 ) { + // *sigh* + if ( i->pixmap( m_toggleColumn ) ) + x += i->pixmap( m_toggleColumn )->width(); + if ( rootIsDecorated() ) + x += treeStepSize(); + if ( i->parent() ) + x += treeStepSize(); + } + + return x + 2; // + 2 = icon margin, apparently... gnah +} + +void ExtendableList::updateExtender( ExtendableItem *i ) +{ + // setUpdatesEnabled( false ); + + // since updateGeometries is private, we use this dirty trick to + // get at it (since setContentsPos in QListView calls it + setContentsPos( contentsX(), contentsY() ); + + if ( !i->isVisible() || ( i->parent() && !i->parent()->isOpen() ) ) { + kdDebug() << "hiding invisible item's extender" << endl; + i->hideExtender(); + return; + } + + // QRect rect = itemRect( i ); + addChild( i->extender(), extenderOffset( i ), itemPos( i ) ); + // addChild( i->extender(), x, rect.y() ); + i->extender()->show(); + i->extender()->resize( visibleWidth() - extenderOffset( i ), + i->extender()->height() ); + if ( i->height() != i->extender()->frameSize().height() ) { + i->setHeight( i->extender()->frameSize().height() ); + delayedUpdateExtenders(); // re-update since we broke layout + } + + i->extender()->setupColors(); + + // setUpdatesEnabled( true ); + // addChild( i->extender(), x, itemPos( i ) ); + // QTimer::singleShot( 0, this, SLOT( triggerUpdate() ) ); + // QTimer::singleShot( 0, i->extender(), SLOT( setupColors() ) ); +} + +void ExtendableList::delayedUpdateExtenders() +{ + if ( m_extenderUpdateScheduled ) + return; + m_extenderUpdateScheduled = true; + // kdDebug() << "ExtendableList::delayedUpdateExtenders()" << endl; + QTimer::singleShot( 0, this, SLOT( updateExtenders() ) ); +} + +void ExtendableList::clear() +{ + kdDebug() << "ExtendableList::clear()" << endl; + KListView::clear(); + kdDebug() << "end of ExtendableList::clear()" << endl; +} + +void ExtendableList::show() +{ + KListView::show(); + updateExtenders(); +} + +void ExtendableList::showEvent( QShowEvent *e ) +{ + KListView::showEvent( e ); + updateExtenders(); +} + +void ExtendableList::resizeEvent( QResizeEvent *e ) +{ + KListView::resizeEvent( e ); + updateExtenders(); + // delayedUpdateExtenders(); +} + +void ExtendableList::updateExtenders() +{ + m_extenderUpdateScheduled = false; + setUpdatesEnabled( false ); + // updateGeometries(); + // since updateGeometries is private, we use this dirty trick to + // get at it (since setContentsPos in QListView calls it + setContentsPos( contentsX(), contentsY() ); + extendersChanged(); + kdDebug() << "ExtendableList::updateExtenders(); count = " + << m_extenders.size() << endl; + if ( m_needSort ) { + std::sort( m_extenders.begin(), m_extenders.end(), ExtendableItem::s_less ); + m_needSort = false; + } + + std::for_each( m_extenders.begin(), m_extenders.end(), + std::bind1st( std::mem_fun( &ExtendableList::updateExtender ), + this ) ); + + setUpdatesEnabled( true ); + // triggerUpdate(); + if ( !m_extenderUpdateScheduled ) + QTimer::singleShot( 0, this, SLOT( triggerUpdate() ) ); + /* if ( m_extenders.empty() ) + QTimer::singleShot( 0, this, SLOT( triggerUpdate() ) ); */ + // QTimer::singleShot( 0, this, SIGNAL( extendersChanged() ) ); +} + +void ExtendableList::addExtender( ExtendableItem *item ) +{ + m_extenders.push_back( item ); + m_needSort = true; + // std::sort( m_extenders.begin(), m_extenders.end(), ExtendableItem::s_less ); + // updateExtender( item ); + delayedUpdateExtenders(); +} + +void ExtendableList::removeExtender( ExtendableItem *i ) +{ + kdDebug() << "ExtendableList::removeExtender( " << i << " )" << endl; + m_extenders.erase( std::remove( m_extenders.begin(), + m_extenders.end(), i ), + m_extenders.end() ); + // the above retains ordering so no need to re-sort + if (!m_inDtor) + delayedUpdateExtenders(); +} + +void ExtendableList::processClick( QListViewItem *it, + const QPoint &pt, int c ) +{ + // if (! it) return; + ExtendableItem *item = dynamic_cast< ExtendableItem* >( it ); + if (!item) return; + kdDebug() << "ExtendableList::processClick (a real item)" << endl; + + if (c == m_toggleColumn) + item->toggleExtender(); + if ( item->extender() ) + item->extender()->setupColors(); + delayedUpdateExtenders(); + /* if (item->extender()) { + if (c == m_toggleColumn) + item->toggleExtender(); + } else + item->toggleExtender(); */ +} + +ExtendableList::~ExtendableList() { +} + +ExtendableList *ExtendableItem::list() +{ + return dynamic_cast< ExtendableList * >( listView() ); +} + +bool ExtendableItem::s_less( + const ExtendableItem *a, const ExtendableItem *b ) +{ + return a->less( b ); +} + +int ExtendableItem::compare( QListViewItem *i, int c, bool asc ) const +{ + ExtendableItem *o = dynamic_cast< ExtendableItem * >( i ); + return int( o->less( this ) ) - int( less( o ) ); +} + +void ExtendableItem::updateIcon() { + QPixmap p; + if ( !extender() ) { + p = list()->baseIcon(); + if ( !extendable() && !firstChild() ) { + p = list()->unextendableIcon(); + } else if ( isOpen() ) { + p = list()->extendedIcon(); + } + } else { + p = list()->extendedIcon(); + } + setPixmap( list()->toggleColumn(), p ); + setUpdatedIcon(p); + + // umm hack + if ( dynamic_cast< ExtendableItem * >( parent() ) ) + dynamic_cast< ExtendableItem * >( parent() )->updateIcon(); +} + + +void ExtendableItem::toggleExtender() +{ + if (m_extender) { + setup(); + if( list() ) // this could as well be 0... bah + list()->removeExtender( this ); + delete m_extender; + m_extender = 0; + } else { + m_extender = createExtender(); + if (m_extender) { + m_extender->setItem( this ); + list()->addExtender( this ); + } + if ( !m_extender && firstChild() ) { + setOpen( !isOpen() ); + } + } + updateIcon(); +} + +void ExtendableItem::paintBranches( QPainter *p, + const QColorGroup &cg, int w, int y, int h ) +{ + /* if (!isAlternate()) + p->setBackgroundColor( + KGlobalSettings::alternateBackgroundColor() ); + p->eraseRect( 0, y, w, h ); */ + p->eraseRect( 0, 0, w, h ); +} + +/* void ExtendableItem::paintCell( QPainter *p, const QColorGroup &cg, + int column, int width, int alignment ) +{ + QPixmap pm( width, height() ); + QPainter _p( &pm ); + KListViewItem::paintCell( &_p, cg, column, width, alignment ); + p->drawPixmap( 0, 0, pm ); + } */ + + +static void setcolor( QWidget *w, ExtendableItem *i ) { + if ( i->isSelected() && i->list()->extenderHighlight() ) + w->setPaletteBackgroundColor( w->colorGroup().highlight() ); + else if ( i->isAlternate() ) + w->setPaletteBackgroundColor( + KGlobalSettings::alternateBackgroundColor() ); + else + w->setPaletteBackgroundColor( w->colorGroup().base() ); + // w->setBackgroundMode( QWidget::PaletteBase ); +} +void ItemExtender::setupColors() +{ + if ( !item() ) return; + setcolor( this, item() ); + QObjectList *chld = queryList( "QWidget" ); + QObjectListIt it( *chld ); + QWidget *o; + while ((o = dynamic_cast< QWidget * >( it.current() )) != 0) { + setcolor( o, item() ); + ++it; + } +} + +ExtendableItem::~ExtendableItem() +{ + // kdDebug() << "~ExtendableList; list = " << list() << endl; + // kdDebug() << "extender() = " << extender() << endl; + while ( firstChild() ) + delete firstChild(); // har har + if( extender() && list() ) // list() could be 0... + list()->removeExtender( this ); + if (extender()) + extender()->deleteLater(); +} diff --git a/adept/adept/extendablelist.h b/adept/adept/extendablelist.h new file mode 100644 index 0000000..e95df03 --- /dev/null +++ b/adept/adept/extendablelist.h @@ -0,0 +1,166 @@ +// -*- C++ -*- +#include <klistview.h> +#include <qpixmap.h> +#include <qlayout.h> +#include <kglobalsettings.h> +#include <vector> + +#include <apt-front/utils/range.h> + +#ifndef EPT_EXTENDABLELIST_H +#define EPT_EXTENDABLELIST_H +namespace adept { + +using namespace aptFront; + +class ExtendableItem; +class ExtendableList; +class ItemExtender; + +class ExtendableList : public KListView { + Q_OBJECT +public: + typedef bool(*ItemCompare)( const ExtendableItem *, + const ExtendableItem * ); + ExtendableList( QWidget *p = 0, const char *n = 0 ); + virtual ~ExtendableList(); + QPixmap extendedIcon() { return m_extendedIcon; } + QPixmap baseIcon() { return m_baseIcon; } + QPixmap unextendableIcon() { return m_unextendableIcon; } + int extenderOffset( ExtendableItem *i ); + void setExtenderHighlight( bool e ) { m_extenderHighlight = e; } + bool extenderHighlight() { return m_extenderHighlight; } +public slots: + void addExtender( ExtendableItem *i ); + void removeExtender( ExtendableItem *i ); + void updateExtender( ExtendableItem *i ); + void delayedUpdateExtenders(); + void updateExtenders(); + void setToggleColumn( int c ) { + m_toggleColumn = c; + } + unsigned toggleColumn() { return m_toggleColumn; } + virtual void show(); + virtual void clear(); + utils::Range< ExtendableItem * > extenders() { + return utils::range( m_extenders.begin(), m_extenders.end() ); } + void openToplevel(); +protected slots: + void processClick( QListViewItem *, const QPoint &, int ); +signals: + void extendersChanged(); +protected: + virtual void resizeEvent( QResizeEvent * ); + virtual void showEvent( QShowEvent * ); + virtual void keyPressEvent( QKeyEvent * ); + std::vector< ExtendableItem * > m_extenders; + QPixmap m_extendedIcon; + QPixmap m_baseIcon; + QPixmap m_unextendableIcon; + int m_toggleColumn; + bool m_inDtor:1; + bool m_extenderUpdateScheduled:1; + bool m_needSort:1; + bool m_extenderHighlight:1; +}; + +class ExtendableItem : public KListViewItem { +public: + + ExtendableItem( ExtendableList *l ) + : KListViewItem( l ), m_extender( 0 ) { + } + + ExtendableItem( ExtendableList *l, ExtendableItem *prev ) + : KListViewItem( l, prev ), m_extender( 0 ) { + } + + ExtendableItem( ExtendableItem *p, ExtendableItem *prev ) + : KListViewItem( p, prev ), m_extender( 0 ) { + } + + ExtendableItem( ExtendableItem *p ) + : KListViewItem( p ), m_extender( 0 ) { + } + + virtual void setup() { + KListViewItem::setup(); + updateIcon(); + } + void toggleExtender(); + + void hideExtender() { + if (extender()) + toggleExtender(); + } + + void showExtender() { + if (!extender()) + toggleExtender(); + } + + ItemExtender *extender() { return m_extender; } + + static bool s_less( const ExtendableItem *a, const ExtendableItem *b ); + + ExtendableList *list(); + + virtual void updateIcon(); + virtual void setUpdatedIcon(QPixmap& pm) { return; }; + + virtual void paintBranches( QPainter *, const QColorGroup &, int, int, int ); + + virtual ItemExtender *createExtender() = 0; + virtual bool extendable() const { return false; } + virtual bool less( const ExtendableItem * ) const = 0; + virtual int compare( QListViewItem *other, int col, bool ascending ) const; + + virtual ~ExtendableItem(); + virtual void setHeight( int h ) { KListViewItem::setHeight( h ); } +protected: + ItemExtender *m_extender; +}; + +class ItemExtender : public QWidget { + Q_OBJECT +public: + // ItemExtender( ExtendableItem *item ); + ItemExtender( QWidget *parent, const char *n ) + : QWidget( parent, n ), m_item( 0 ) + {} + + virtual void setItem( ExtendableItem *i ) { + m_item = i; + } + + virtual void polish() { + setupColors(); + } + + ExtendableItem *item() { + return m_item; + } + + void resize( int w, int h ) { + setUpdatesEnabled( false ); + QWidget::resize( w, h ); + setUpdatesEnabled( true ); + QWidget::resize( w, layout()->minimumSize().height() ); + } + + void resize( const QSize &s ) { + resize( s.width(), s.height() ); + } + +public slots: + void setupColors(); +protected: + virtual void mouseReleaseEvent( QMouseEvent *e ) { + e->accept(); + } // throw away mouse clicks :-) + ExtendableItem *m_item; +}; + +} + +#endif diff --git a/adept/adept/filterlist.cpp b/adept/adept/filterlist.cpp new file mode 100644 index 0000000..bb798cd --- /dev/null +++ b/adept/adept/filterlist.cpp @@ -0,0 +1,232 @@ +#include <kdebug.h> +#include <qpopupmenu.h> +#include <qheader.h> +#include <klineedit.h> + +//#include <tagcoll/InputMerger.h> + +//#include <apt-front/cache/component/tags.h> +#include <apt-front/cache/entity/package.h> + +#include <adept/lister.h> +#include <adept/filterlist.h> +#include <adept/quickfilter.h> +#include <adept/statefilter.h> +#include <adept/easytagfilter.h> +#include <adept/tagfilter.h> + + +using namespace adept; + +/* +// TODO: Beat enrico till this lands in some of our libs... +template< typename PKG, typename TAG > +class TagcollConsumerAdaptor : + public utils::ConsumerImpl< PKG,TagcollConsumerAdaptor<PKG, TAG> > +{ +protected: + Consumer<PKG, TAG>& m_out; + +public: + TagcollConsumerAdaptor( Consumer<PKG, TAG>& out) : m_out( out ) {} + virtual void consume( const PKG& a ) { + if (a != PKG()) + m_out.consume(a, a.tags()); + } +}; +*/ + +PredicateInterface::PredicateInterface( QWidget *w, const char *n ) + : ItemExtender( w, n ) +{ +} + +void PredicateInterface::widgetsChanged() { + kdDebug() << "PredicateInterface::widgetsChanged()" << endl; + emit predicateDrop( m_pred ); + m_pred = predicate(); + emit predicateAdd( m_pred ); + downcast< FilterItem >( item() ).setPredicate( m_pred ); +} + +FilterList::FilterList( QWidget *parent, const char *name ) + : ExtendableList( parent, name ), + m_pred( predicate::True< entity::Entity >() ), + m_hidden( predicate::True< entity::Entity >() ) +{ + m_itemsSeen = 0; + // addColumn( " ", 20 ); + addColumn( i18n( "Active filters" ), 240 ); + // setSortColumn( -1 ); + /* setItemsMovable( true ); + setDragEnabled( true ); + setAcceptDrops( true ); */ + setResizeMode( LastColumn ); + setAllColumnsShowFocus (true); + + resize( 240, 180 ); + connect( this, SIGNAL( + contextMenuRequested( QListViewItem *, const QPoint + &, int ) ), + this, SLOT( contextMenu( QListViewItem *, const + QPoint &, int) ) ); + connect( this, SIGNAL( extendersChanged() ), + this, SLOT( updateHeight() ) ); +} + +void FilterList::emitPredicateChanged() { + predicateChanged( m_hidden and m_pred ); +} + +void FilterList::updateHeight() { + int h = header()->height() + 4; + for ( QListViewItem *i = firstChild(); i != 0; i = i->nextSibling() ) { + h += i->totalHeight(); + } + // int h = contentsHeight() + header()->height() + 4; // magic constant + setMinimumHeight( h ); + setMaximumHeight( h ); +} + +void FilterList::drawContents( QPainter *p, int a, int b, int c, int d ) { + if ( m_itemsSeen != childCount() ) { + m_itemsSeen = childCount(); + updateHeight(); + } // hmm, doesn't work... bah :p + KListView::drawContents( p, a, b, c, d ); +} + +void FilterList::plugLister( Lister *l ) { + m_lister = l; + connect( this, SIGNAL( predicateChanged( ListerPredicate ) ), + l, SLOT( baseSet( ListerPredicate ) ) ); +} + +void FilterList::setPredicate( Predicate p ) { + clear(); + m_pred = p; + appendPredicate( p ); + emitPredicateChanged(); +} + +void FilterList::setHiddenPredicate( Predicate p ) { + m_hidden = p; + emitPredicateChanged(); +} + +void FilterList::editorPredicateDrop( Predicate p ) { + m_pred = predicate::remove( m_pred, p ); + emitPredicateChanged(); +} + +void FilterList::editorPredicateAdd( Predicate p ) { + kdDebug() << "FilterList::editorPredicateAdd" << endl; + m_pred = m_pred and p; + emitPredicateChanged(); +} + +void FilterList::appendPredicate( Predicate p ) { + if (p.is< And >()) { + And a = p; + for (utils::Range< Predicate > r = a.parts(); + r != r.end(); ++r ) + appendPredicate( *r ); + } else if (p.is< predicate::True< entity::Entity > >() ) { + // we generally ignore truth + } else { + m_pred = m_pred and p; + // kdDebug() << p.serialize() << endl; + // kdDebug() << p.prettyPrint() << endl; + FilterItem *i; + i = new FilterItem( this ); + i->setPredicate( p ); + } +} + +void FilterList::contextMenu( QListViewItem *it, const QPoint &pt, int /*c*/ ) +{ + std::cerr << "FilterList::contextMenu(p);" << std::endl; + FilterItem *i = dynamic_cast< FilterItem * >( it ); + if (! i) + return; + QPopupMenu *m = new QPopupMenu( this ); + m->insertItem( i18n( "Reset Filter" ), 1 ); + m->insertItem( i18n( "Remove Filter" ), 0 ); + m->insertSeparator(); + m->insertItem( i18n( "Add Quick Filter" ), 8 ); + m->insertItem( i18n( "Add State Filter" ), 9 ); + m->insertItem( i18n( "Add Tag Filter" ), 10 ); + m->insertItem( i18n( "Add Easy Tag Filter" ), 11 ); + // m->insertItem( "Add Tag Filter", tagMenu() ); + m_context = i; + connect(m, SIGNAL(activated(int)), this, SLOT(contextActivated(int))); + m->exec(pt); + delete m; +} + + +void FilterList::contextActivated( int i ) +{ + predicate::Predicate< entity::Entity > p; + switch (i) { + case 0: + m_pred = predicate::remove( m_pred, m_context->predicate() ); + delete m_context; + emitPredicateChanged(); + return; + case 1: + m_context->reset(); + return; + case 8: + p = predicate::adapt< entity::Entity >( + QuickFilter< entity::Package >() ); + break; + case 9: + p = predicate::adapt< entity::Entity >( + StateFilter< entity::Package >() ); + break; + case 10: + p = predicate::adapt< entity::Entity >( + TagFilter< entity::Package >() ); + break; + case 11: + p = predicate::adapt< entity::Entity >( + EasyTagFilter< entity::Package >() ); + break; + } + if (p.impl()) { + kdDebug() << "summary: " << + downcast< InterfacingPredicate >( p ).summary() << endl; + appendPredicate( p ); + emitPredicateChanged(); + } +} + +ItemExtender *FilterItem::createExtender() +{ + PredicateInterface *o = 0; + if (m_pred.is< QuickFilter< entity::Package > >()) { + o = new QuickFilterWidget( list(), 0 ); + } else if (m_pred.is< StateFilter< entity::Package > >()) { + o = new StateFilterWidget( list(), 0 ); + } else if (m_pred.is< EasyTagFilter< entity::Package > >()) { + o = new EasyTagFilterWidget( list(), 0 ); + } else if (m_pred.is< TagFilter< entity::Package > >()) { + o = new TagFilterWidget( list(), 0 ); + } + if (o) { + o->setPredicate( m_pred ); + QObject::connect( o, SIGNAL( predicateAdd( Predicate ) ), + list(), SLOT( editorPredicateAdd( Predicate ) ) ); + QObject::connect( o, SIGNAL( predicateDrop( Predicate ) ), + list(), SLOT( editorPredicateDrop( Predicate ) ) ); + } + return o; +} + +QString FilterItem::text( int c ) const { + InterfacingPredicate &ip = downcast< InterfacingPredicate >( m_pred.impl() ); + if (c == 0) + return ip.summary(); + return u8( "" ); +} diff --git a/adept/adept/filterlist.h b/adept/adept/filterlist.h new file mode 100644 index 0000000..212ab5a --- /dev/null +++ b/adept/adept/filterlist.h @@ -0,0 +1,149 @@ +/** -*- C++ -*- + @file adept/filterlist.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qtooltip.h> +#include <kdebug.h> + +#include <apt-front/predicate/matchers.h> +#include <apt-front/predicate/combinators.h> +#include <apt-front/predicate/factory.h> +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/component/packagetags.h> +//#include <apt-front/cache/component/tags.h> + +#include <adept/listerpredicate.h> +#include <adept/extendablelist.h> + +#ifndef EPT_FILTERLIST_H +#define EPT_FILTERLIST_H + +class QPopupMenu; + +namespace adept { +using namespace aptFront; +using namespace aptFront::cache; +class Lister; + +struct InterfacingPredicate +{ +public: + virtual std::string summary() const = 0; + virtual void reset() {} +signals: + void changed(); +}; + + +class PredicateInterface: public ItemExtender +{ + Q_OBJECT +public: + typedef predicate::Predicate< entity::Entity > Predicate; + PredicateInterface( QWidget *w = 0, const char *n = 0 ); + virtual Predicate predicate() = 0; +signals: + void predicateAdd( Predicate ); + void predicateDrop( Predicate ); +public slots: + virtual void setPredicate( const Predicate &p ) { + m_pred = p; + predicateChanged(); + } + virtual void widgetsChanged(); + virtual void predicateChanged() = 0; +protected: + predicate::Predicate< entity::Entity > m_pred; +}; + +class FilterItem; + +class FilterList : public ExtendableList +{ + Q_OBJECT +public: + friend class FilterItem; + typedef predicate::Predicate< entity::Entity > Predicate; + // typedef std::map< KListViewItem *, Predicate > Map; + FilterList( QWidget *parent = 0, const char *name = 0 ); + typedef predicate::And< entity::Entity > And; + void appendPredicate( Predicate p ); + void plugLister( Lister *l ); + void emitPredicateChanged(); +signals: + void predicateChanged( ListerPredicate p ); +public slots: + void setPredicate( Predicate p ); + void setHiddenPredicate( Predicate p ); +protected slots: + void editorPredicateDrop( Predicate ); + void editorPredicateAdd( Predicate ); + void contextMenu( QListViewItem *, const QPoint &, int ); + // QPopupMenu *tagMenu(); + void contextActivated( int ); + // void tagMenuActivated( int ); + void updateHeight(); +protected: + void drawContents( QPainter *, int, int, int, int ); + Predicate m_pred; + Predicate m_hidden; + FilterItem *m_context; + bool m_changed; + Lister *m_lister; + int m_itemsSeen; + std::vector< ept::debtags::Tag > m_tagMenuMap; +}; + +class FilterItem : public ExtendableItem +{ +public: + ItemExtender *createExtender(); + FilterItem( FilterList *l ) + : ExtendableItem( l ), m_delayedDone( false ) + { + } + void setup() { + ExtendableItem::setup(); + if (m_delayedDone) + return; + m_delayedDone = true; + showExtender(); + } + + QString text( int ) const; + + virtual bool less( const ExtendableItem *other ) const { + const FilterItem *o = dynamic_cast< const FilterItem * >( other ); + return downcast< InterfacingPredicate >( m_pred ).summary() < + downcast< InterfacingPredicate >( o->m_pred ).summary(); + } + + void setPredicate( predicate::Predicate< entity::Entity > p ) { + m_pred = p; + } + + FilterList::Predicate predicate() const { + return m_pred; + } + + FilterList *filterList() { return dynamic_cast< FilterList * >( list() ); } + + void reset() { + filterList()->editorPredicateDrop( m_pred ); + downcast< InterfacingPredicate >( m_pred ).reset(); + if ( extender() ) { + downcast< PredicateInterface >( extender() ).setPredicate( m_pred ); + extender()->setFocus(); + } + filterList()->editorPredicateAdd( m_pred ); + } + +protected: + predicate::Predicate< entity::Entity > m_pred; + bool m_delayedDone:1; +}; + +} + +#endif diff --git a/adept/adept/filtersidebar.cpp b/adept/adept/filtersidebar.cpp new file mode 100644 index 0000000..777fa44 --- /dev/null +++ b/adept/adept/filtersidebar.cpp @@ -0,0 +1,72 @@ +#include <functional> +#include <ext/functional> +#include <algorithm> +#include <cmath> +#include <ept/debtags/tag.h> +#include <ept/debtags/vocabulary.h> +#include <adept/filtersidebar.h> +#include <adept/tagchooser.h> + +using namespace adept; +using namespace aptFront; +using namespace std; +using namespace __gnu_cxx; + +template< typename H, typename G1, typename G2 > +struct _compose2_binary { + _compose2_binary( H _h, G1 _g1, G2 _g2 ) + : h( _h ), g1( _g1 ), g2( _g2 ) + {} + + typename H::result_type operator()( + typename G1::argument_type a, + typename G2::argument_type b ) + { + return h( g1( a ), g2( b ) ); + } + + H h; + G1 g1; + G2 g2; +}; + +template< typename H, typename G1, typename G2 > +_compose2_binary< H, G1, G2 > compose2_binary( H h, G1 g1, G2 g2 ) { + return _compose2_binary< H, G1, G2 >( h, g1, g2 ); +} + +void FilterSidebar::setCardinality( const Lister::Cardinality &c ) +{ + using namespace wibble::operators; + ept::debtags::Tag::Set all, smart; + + kdDebug() << "FilterSidebar::setCardinality" << endl; + Lister::Cardinality cprime; + remove_copy_if( c.begin(), c.end(), inserter( cprime, cprime.begin() ), + compose1( bind1st( equal_to< int >(), 0 ), + select2nd< + Lister::Cardinality::value_type >() ) ); + transform( cprime.begin(), cprime.end(), inserter( all, all.begin() ), + select1st< Lister::Cardinality::value_type >() ); + m_all->setTags( all ); + ept::debtags::Vocabulary &t = cache::Global().get().tags(); + m_easy->setTags( all & ( t.facetByName( "interface" ).tags() + | t.facetByName( "works-with" ).tags() + | t.facetByName( "use" ).tags() + | t.facetByName( "role" ).tags() ) ); + + typedef vector< pair< ept::debtags::Tag, int > > Vec; + Vec vec; + copy( cprime.begin(), cprime.end(), back_inserter( vec ) ); + sort( vec.begin(), vec.end(), + compose2_binary( less< int >(), + select2nd< Vec::value_type >(), + select2nd< Vec::value_type >() ) ); + Vec::reverse_iterator end = vec.rbegin(); + advance( end, vec.size() < 10 ? vec.size() : 10 ); + transform( vec.rbegin(), end, inserter( smart, smart.begin() ), + select1st< Vec::value_type >() ); + + m_smart->setTags( smart ); + m_smart->openToplevel(); +} diff --git a/adept/adept/filtersidebar.h b/adept/adept/filtersidebar.h new file mode 100644 index 0000000..0fac201 --- /dev/null +++ b/adept/adept/filtersidebar.h @@ -0,0 +1,26 @@ +/* -*- C++ -*- file adept/filtersidebar.h + written by Peter Rockai <me@mornfall.net> */ + +#include <adept/filtersidebarui.h> +#include <adept/lister.h> + +#ifndef EPT_FILTERSIDEBAR_H +#define EPT_FILTERSIDEBAR_H + +namespace adept { + +// using namespace aptFront; + +class FilterSidebar : public FilterSidebarUi { + Q_OBJECT +public: + FilterSidebar( QWidget *p = 0, const char *n = 0 ) + : FilterSidebarUi( p, n ) + {} +public slots: + void setCardinality( const Lister::Cardinality & ); +}; + +} + +#endif diff --git a/adept/adept/filtersidebarui.ui b/adept/adept/filtersidebarui.ui new file mode 100644 index 0000000..0f2efb4 --- /dev/null +++ b/adept/adept/filtersidebarui.ui @@ -0,0 +1,119 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::FilterSidebarUi</class> +<widget class="QWidget"> + <property name="name"> + <cstring>adept::FilterSidebarUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>227</width> + <height>469</height> + </rect> + </property> + <property name="caption"> + <string>Form2</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QTabWidget" row="0" column="0"> + <property name="name"> + <cstring>m_tabs</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab0</cstring> + </property> + <attribute name="title"> + <string>Smart</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="adept::TagChooser" row="0" column="0"> + <property name="name"> + <cstring>m_smart</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab1</cstring> + </property> + <attribute name="title"> + <string>Simple</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="adept::TagChooser" row="0" column="0"> + <property name="name"> + <cstring>m_easy</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab2</cstring> + </property> + <attribute name="title"> + <string>All</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="adept::TagChooser" row="0" column="0"> + <property name="name"> + <cstring>m_all</cstring> + </property> + </widget> + </grid> + </widget> + </widget> + </grid> +</widget> +<customwidgets> + <customwidget> + <class>adept::TagChooser</class> + <header location="global">adept/tagchooser.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </customwidget> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>adept/tagchooser.h</includehint> +</includehints> +</UI> diff --git a/adept/adept/filterwidget.cpp b/adept/adept/filterwidget.cpp new file mode 100644 index 0000000..f294327 --- /dev/null +++ b/adept/adept/filterwidget.cpp @@ -0,0 +1,36 @@ +#include <apt-front/predicate/combinators.h> +#include <apt-front/predicate/factory.h> +#include <klocale.h> +#include <klineedit.h> +#include "filterwidget.h" + +using namespace aptFront; +using namespace adept; + +void FilterWidget::connectLister( Lister *l ) { + connect( this, SIGNAL( drop( ListerPredicate ) ), + l, SLOT( interactiveDrop( ListerPredicate ) ) ); + connect( this, SIGNAL( changed( ListerPredicate ) ), + l, SLOT( interactiveAnd( ListerPredicate ) ) ); + connect( this, SIGNAL( apply( ListerPredicate ) ), + l, SLOT( baseAnd( ListerPredicate ) ) ); + +} + +void FilterWidget::changedInternal() { + setEnabled( false ); + emit drop( m_old ); + emit changed( m_old = predicate() ); + setEnabled( true ); + setFocus(); +} + +void FilterWidget::applyInternal() { + // check for emptiness? + setEnabled( false ); + emit drop( m_old ); + emit apply( m_old = predicate() ); + reset(); + setEnabled( true ); + setFocus(); +} diff --git a/adept/adept/filterwidget.h b/adept/adept/filterwidget.h new file mode 100644 index 0000000..78b0c38 --- /dev/null +++ b/adept/adept/filterwidget.h @@ -0,0 +1,39 @@ +/** -*- C++ -*- + @file adept/filterwidgets.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/entity/package.h> +#include <adept/lister.h> + +#ifndef EPT_FILTERWIDGET_H +#define EPT_FILTERWIDGET_H + +class KLineEdit; + +namespace adept { + +class FilterWidget : public QWidget +{ + Q_OBJECT +public: + FilterWidget( QWidget *parent = 0, const char *n = 0 ) + : QWidget( parent, n ) {} + virtual ListerPredicate predicate() = 0; + void connectLister( Lister *l ); +protected slots: + void changedInternal(); + void applyInternal(); + virtual void reset() = 0; +signals: + void changed( ListerPredicate op ); + void apply( ListerPredicate op ); + void drop( ListerPredicate op ); +protected: + ListerPredicate m_old; +}; + +} + +#endif diff --git a/adept/adept/groupeddesktopselector.cpp b/adept/adept/groupeddesktopselector.cpp new file mode 100644 index 0000000..68afa98 --- /dev/null +++ b/adept/adept/groupeddesktopselector.cpp @@ -0,0 +1,137 @@ +/** -*- C++ -*- + @file adept/groupeddestkopselector.cpp + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qobjectlist.h> +#include <qvbox.h> +#include <qlabel.h> +#include <qtimer.h> +#include <kiconloader.h> +#include <kglobal.h> +#include <kseparator.h> +#include <kapplication.h> + +#include <apt-front/cache/component/desktop.h> +#include <adept/groupeddesktopselector.h> +#include <adept/desktoplist.h> +#include <adept/utils.h> + +using namespace aptFront; +using namespace cache; + +namespace adept { + +GroupedDesktopSelector::GroupedDesktopSelector( QWidget *p, const char *n ) + : KJanusWidget( p, n, IconList ), m_policy( 0 ) +{ + observeComponent< cache::component::Packages >(); + m_pages.push_back( addPage( QString( "Initializing..." ) ) ); + QObjectList *chld = queryList( "QWidget" ); + QObjectListIt it( *chld ); QWidget *o; + while ((o = dynamic_cast< QWidget * >( it.current() )) != 0) { + if ( dynamic_cast< QLabel * >( o ) != 0 ) + o->hide(); + if ( dynamic_cast< KSeparator * >( o ) != 0 ) + o->hide(); + ++it; + } // *hack* + + // AAAA hack + QLayoutIterator li = layout()->iterator(); + QHBoxLayout *hbox = 0; + while ( li.current() != 0 ) { + hbox = dynamic_cast< QHBoxLayout * >( li.current() ); + if ( hbox ) break; + ++li; + } + kdDebug() << "hacking hbox = " << hbox << endl; + if ( hbox ) { + li = hbox->iterator(); + while ( li.current() != 0 ) { + QSpacerItem *spacer = dynamic_cast< QSpacerItem * >( li.current() ); + if ( spacer ) { + hbox->removeItem( spacer ); + delete spacer; + } + ++li; + } + } +} + +void GroupedDesktopSelector::notifyPreRebuild( component::Base * ) { + clear(); +} + +void GroupedDesktopSelector::notifyPostRebuild( component::Base * ) { + // QTimer::singleShot( 0, this, SLOT( fill() ) ); +} + +void GroupedDesktopSelector::clear() +{ + if ( !m_pages.empty() ) + showPage( m_pages.front() ); + while ( !m_pages.empty() ) { + removePage( m_pages.back() ); + delete m_pages.back(); + m_pages.pop_back(); + } +} + +void GroupedDesktopSelector::fill() +{ + component::Desktop &d = cache::Global::get().component< component::Desktop >(); + fill( d.entries() ); +} + +void GroupedDesktopSelector::fill( component::Desktop::EntityRange r ) +{ + component::Desktop &d = cache::Global::get().component< component::Desktop >(); + utils::Range< std::string > gr; + QString last = pageTitle( activePageIndex() ); + + clear(); + + bool shown = false; + + for ( gr = d.availableGroups( r ); gr != gr.end(); gr.advance() ) { + + component::Desktop::EntityRange cr = d.group( *gr ); + QString name = u8( *gr ); + std::cerr << "group for " << cr->name() << ": " << r->group() << std::endl; + name = ( name != u8( "" ) ? name : u8( "Legacy" ) ); + + QPixmap icon( KGlobal::iconLoader()->iconPath( + policy() ? policy()->iconForGroup( name ) : u8( "" ), -32 ) ); + + QVBox *b = addVBoxPage( name, name, icon ); + m_pages.push_back( b ); + std::cerr << "creating list for " << *gr << std::endl; + + DesktopList *l = new DesktopList( b ); + l->setTitle( name ); + connect( l, SIGNAL( request( cache::entity::Package, + cache::component::State::Action ) ), + this, SIGNAL( request( cache::entity::Package, + cache::component::State::Action ) ) ); + connect( l, SIGNAL( showDescription( cache::entity::Desktop ) ), + this, SIGNAL( showDescription( cache::entity::Desktop ) ) ); + + l->insertRange( intersectionRange( r, cr ) ); + // l->insertRange( cr ); + + std::cerr << "created list for " << *gr << std::endl; + if ( name == last ) { + showPage( b ); + shown = true; + } + kapp->processEvents(); + } + + if ( m_pages.empty() ) + m_pages.push_back( addPage( QString( "No Results" ) ) ); + if ( !shown ) + showPage( pageIndex( m_pages.front() ) ); +} + +} diff --git a/adept/adept/groupeddesktopselector.h b/adept/adept/groupeddesktopselector.h new file mode 100644 index 0000000..a54f7aa --- /dev/null +++ b/adept/adept/groupeddesktopselector.h @@ -0,0 +1,39 @@ +/** -*- C++ -*- + @file adept/groupeddestkopselector.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <kjanuswidget.h> +#include <apt-front/cache/entity/desktop.h> + +namespace adept { +using namespace aptFront; +using namespace aptFront::cache; + +// XXX needs fixing +class GroupedDesktopSelector : public KJanusWidget, cache::Observer +{ + Q_OBJECT +public: + struct IconPolicy { + virtual QString iconForGroup( QString group ) { return group; } + }; + GroupedDesktopSelector( QWidget *p = 0, const char *n = 0 ); + void fill( component::Desktop::EntityRange r ); + void setPolicy( IconPolicy *p ) { m_policy = p; } + IconPolicy *policy() { return m_policy; } + virtual void notifyPreRebuild( cache::component::Base * ); + virtual void notifyPostRebuild( cache::component::Base * ); +public slots: + void clear(); + void fill(); +signals: + void request( cache::entity::Package, cache::component::State::Action ); + void showDescription( cache::entity::Desktop ); +protected: + IconPolicy *m_policy; + std::vector< QWidget * > m_pages; + // IconPolicy m_defaultPolicy; +}; + +} diff --git a/adept/adept/installerview.cpp b/adept/adept/installerview.cpp new file mode 100644 index 0000000..052fa41 --- /dev/null +++ b/adept/adept/installerview.cpp @@ -0,0 +1,112 @@ +#include <qlineedit.h> +#include <qcombobox.h> +#include <qtextbrowser.h> +#include <qcheckbox.h> +#include <klocale.h> +#include <kconfig.h> + +#include <cmath> + +#include <apt-front/cache/entity/desktop.h> +#include <apt-front/predicate/factory.h> +#include <ept/debtags/vocabulary.h> +#include <adept/installerview.h> +#include <adept/packageinfo.h> +#include <adept/utils.h> + +using namespace adept; +using namespace aptFront; +using namespace cache; + +void InstallerView::rebuild() +{ + typedef predicate::Factory< entity::Desktop > Factory; + if ( m_inRebuild ) { + QTimer::singleShot( 500, this, SLOT( rebuild() ) ); + return; + } + m_inRebuild = true; + + component::Desktop &d = cache::Global::get().component< component::Desktop >(); + ept::debtags::Vocabulary &t = + cache::Global::get().tags(); + + Predicate p = predicate::True< entity::Desktop >(); + if ( m_search->text() != u8( "" ) ) { + Predicate tmp = Factory::name( u8( m_search->text() ) ) + or Factory::description( u8( m_search->text() ) ); + p = p and tmp; + } + + std::string st = ""; + int si = m_suite->currentItem(); + + if ( si == 0 ) st = "suite::kde"; + if ( si == 1 ) st = "suite::gnome"; + + if ( st != "" ) + p = p and Factory::tag( t.tagByName( st ) ); + + if ( !m_unsupported->isChecked() ) { + p = p and not Factory::sectionSubstring( "contrib" ) + and not Factory::sectionSubstring( "universe" ) + and not Factory::sectionSubstring( "multiverse" ); + } + + if ( !m_nonfree->isChecked() ) { + p = p and not Factory::sectionSubstring( "non-free" ) + and not Factory::sectionSubstring( "multiverse" ) + and not Factory::sectionSubstring( "restricted" ); + } + + selector()->fill( filteredRange( d.entries(), p ) ); + + m_inRebuild = false; +} + +InstallerView::InstallerView( QWidget *p , const char *n ) + : InstallerViewUi( p, n ), m_inRebuild( false ) +{ + connect( m_search, SIGNAL( textChanged( const QString & ) ), + this, SLOT( textChanged() ) ); + connect( &timer, SIGNAL( timeout() ), this, SLOT( rebuild() ) ); + connect( m_suite, SIGNAL( activated( int ) ), this, SLOT( rebuild() ) ); + connect( m_unsupported, SIGNAL( toggled( bool ) ), this, SLOT( rebuild() ) ); + connect( m_nonfree, SIGNAL( toggled( bool ) ), this, SLOT( rebuild() ) ); + connect( selector(), SIGNAL( showDescription( cache::entity::Desktop ) ), + this, SLOT( showDescription( cache::entity::Desktop ) ) ); +} + +void InstallerView::textChanged() { + timer.start( 1000, true ); +} + +void InstallerView::showDescription( entity::Desktop e ) +{ + kdDebug() << "InstallerView::showDescription..." << endl; + QString file("/usr/share/app-install/desktop/" + e.package().name() + ".desktop"); + KConfig desktopFile(QString("/usr/share/app-install/desktop/" + e.package().name() + ".desktop"), false, false); + QString name(desktopFile.name()); + + desktopFile.setGroup("Desktop Entry"); + int popularity = desktopFile.readNumEntry("X-AppInstall-Popcon"); + + int popcon_max = 64284; //FIXME should be read at startup, this will change + int rank = 0; + if (popularity > 0) { + rank = (int)(5.0* log(popularity) / log(popcon_max+1)); + } + + QString rankText(" "); + for (int i = 0; i < rank; i++) { + rankText = rankText + "<img src='/usr/share/icons/crystalsvg/16x16/actions/bookmark.png' />"; + } + + QString l = u8(e.package().longDescription( + u8( i18n( "No long description available" ) ) ) ); + + m_description->setText( u8( "<b>" ) + e.name() + u8( "</b>" ) + + u8("<br /><b>") + i18n("Rank: ") + u8("</b>") + rankText.latin1() + + i18n( "<br><b>Package:</b> " ) + e.package().name() + + formatLongDescription( l ) ); +} diff --git a/adept/adept/installerview.h b/adept/adept/installerview.h new file mode 100644 index 0000000..ed955dc --- /dev/null +++ b/adept/adept/installerview.h @@ -0,0 +1,33 @@ +/** -*- C++ -*- + @file adept/installerview.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qtimer.h> +#include <adept/installerviewui.h> +#include <adept/groupeddesktopselector.h> + +#ifndef EPT_INSTALLERVIEW_H +#define EPT_INSTALLERVIEW_H + +namespace adept { +class InstallerView : public InstallerViewUi +{ + Q_OBJECT +public: + typedef predicate::Predicate< entity::Desktop > Predicate; + InstallerView( QWidget *p = 0, const char *n = 0 ); + GroupedDesktopSelector *selector() { return m_selector; } +protected slots: + void textChanged(); + void showDescription( cache::entity::Desktop ); +public slots: + void rebuild(); +protected: + bool m_inRebuild; + QTimer timer; +}; + +} + +#endif diff --git a/adept/adept/installerviewui.ui b/adept/adept/installerviewui.ui new file mode 100644 index 0000000..b289650 --- /dev/null +++ b/adept/adept/installerviewui.ui @@ -0,0 +1,203 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>InstallerViewUi</class> +<widget class="QWidget"> + <property name="name"> + <cstring>InstallerViewUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>666</width> + <height>314</height> + </rect> + </property> + <property name="caption"> + <string>Form1</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLayoutWidget" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>4</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Search:</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_search</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>KDE</string> + </property> + </item> + <item> + <property name="text"> + <string>GNOME</string> + </property> + </item> + <item> + <property name="text"> + <string>Any Suite</string> + </property> + </item> + <property name="name"> + <cstring>m_suite</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="currentItem"> + <number>2</number> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Show:</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_unsupported</cstring> + </property> + <property name="text"> + <string>unsupported,</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_nonfree</cstring> + </property> + <property name="text"> + <string>proprietary software.</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + <widget class="adept::GroupedDesktopSelector" row="1" column="0"> + <property name="name"> + <cstring>m_selector</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>6</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QTextBrowser" row="1" column="1"> + <property name="name"> + <cstring>m_description</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>4</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </grid> +</widget> +<customwidgets> + <customwidget> + <class>adept::GroupedDesktopSelector</class> + <header location="local">adept/groupeddesktopselector.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</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="PNG" length="1122">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042949444154388db5954d6c545514c77ff7de37eff1a6a550da994e5ba798868f948fc847a2a2911816c436b0a02ed0083161a1981877ee10d90aa94656063491882c5cd4c4b8103f20cd806909a98604da8482341de80cb69de9bcd799799d79efba980f1da3a80b4f727273939bdff99f9b93f3175a6b6a21849080020c4002a29a8f0a5dcd002803bed63a1035f0d0d0504b6f6fef51d7758fa4d3e98d8ee3fc03af128ee3303939399548242eb8aefb09300f78464de9f0f0f0d148cc7caf3d5424de97a7ec17104220242805520a44557bbd4b21f083801d33e63a6d1bc7bf19c6064e0319a35a58b9ae7ba43d54e4d7c54b64dc097c7f09d30ef04b36736983cc7c11b4456b9b492c5e20dc54a6540e00896a8268a7017010f8bcae1830d2e9f4c69ebe3c197782b2ce60d94ddc9b30f9feeb45ae5d7181c5ead35636ef08d3ffe26a76ee3208b4031a56d80aa00768fda362e9380e25bf80ef3b587613d7afc099533380a4b5dda46fcb5aa42998b9eb7173dce5e6788e434763ec7fc942532008ea436003660d2caa7f8d69c3bd8910674e4d033e83877ad8d36fb0aa4d6058658ac5358c5df6383bf480f31fdda5a3632bbbfb6da4ccd5c00a10b2012cc12fd97cfb5516f0187c25cee0619396480ec3ca909d0f3372d1e5f9fe66de3ad605587c712ec55256a2540d5519d19ae24a29057329839f7ecc138944d833102290f3184ae1e6d6f0e98739c61229e6d21eafbed1c9c8c5558c8f3ee4ceed76946a1c43d97091828585223e2eebfbc295f60d45de89707628cb58224577bc85a79e5d4d786581cddb9b0148259711b20145836221400416e0232d1f6595c9ce4538773ac7b54406f0b15784e8e80aa1ac2594190220d021e49f2437960156b70ba095e95f96f18acd8c263cc6122962b1167a7ba34cdd7ec8c977a699bed546722a8fc2a02b6e2185fff78ab586ce78894ddb9ab9f5738ed14b1e030756929d8ff2e4ae5544632b38f96e89a99b298ebd6950cc2d12ed0eb3618b26f520788462ad09877df60db600f0f1fb49c646f21c7ebd836dcf94e9d9b4c0db27d6d3bd36c6426a96bce731703046d7da129a4670836284a054869d4f1b1c7e2dca67676ef3c1898091ef5ad8bc358c3205c93bf7c9a40ad4c660f4728edd7bbb3142ea2fc1da711cfc200011e08b45f6bd1c261adbce9717928c5f9d63fc6a19f0014567773303073790f8214bd6f5282dfbb8b9fa1f6b40d7c1939393533b92e63ad9240990484aec7e41b27d579cbb531e0f67023492d86316ebb768ba1e0f786e6f37e56550c62237aee7011e54abd7c1412291b8a06de378b4d3c0b215da9708e5a3a442192085404a83d4accfecac067c0c43e13a70e3fa12e96409e0325000966bbb354465339d04a6f9dd15fe6dde07ce030780278088d05ad72cc9a6b2f2daaaa74d75a1f0e8d0d5f60b40868a8364ead6248430000b0857a126ffcdf396abf03ce089ffcb4c7f033046c6b4a995e7a00000000049454e44ae426082</data> + </image> +</images> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>adept/groupeddesktopselector.h</includehint> +</includehints> +</UI> diff --git a/adept/adept/lister.cpp b/adept/adept/lister.cpp new file mode 100644 index 0000000..ddd70d8 --- /dev/null +++ b/adept/adept/lister.cpp @@ -0,0 +1,818 @@ +// -*- Mode: C++; c-basic-offset: 4; -*- +#include <qlabel.h> +#include <qtimer.h> +#include <qpainter.h> +#include <qpushbutton.h> +#include <qthread.h> +#include <qtextbrowser.h> +#include <qpixmap.h> +#include <qheader.h> + +#include <kpopupmenu.h> +#include <kdebug.h> +#include <klineedit.h> +#include <klocale.h> +#include <kapplication.h> +#include <kglobal.h> +#include <kiconloader.h> + +#include <functional> +#include <iostream> + +#include <apt-front/cache/cache.h> +#include <apt-front/actor.h> +#include <apt-front/cache/component/packages.h> +#include <apt-front/cache/component/state.h> +#include <apt-front/predicate/factory.h> + +#include <adept/utils.h> +#include <adept/lister.h> +#include <adept/packageinfo.h> + +using namespace aptFront; +using namespace aptFront::predicate; +using namespace aptFront::cache; +using namespace aptFront::utils; +using namespace adept; + +#ifdef KUBUNTU +QPixmap* main_icon = 0; +QPixmap* non_main_icon = 0; +#endif + +Lister::Lister( QWidget *parent, const char *name ) + : ExtendableList( parent, name ), + m_rangeProvider( 0 ), + m_baseF( predicate::True< entity::Entity >() ), + m_interactiveF( True<entity::Entity>() ), m_itemCount( -1 ), + m_rebuildScheduled( false ), m_inRebuild( false ), m_cancelRebuild( false ), + m_openToplevel( false ), m_rebuildMutex( true ) +{ + observeComponent< component::State >(); + observeComponent< component::Packages >(); + observeComponent< component::PackageTags >(); + setRootIsDecorated( false ); + setSelectionModeExt( Extended ); + setAllColumnsShowFocus (true); + +#ifdef KUBUNTU + // The tip + // ListerItemTooltip* i_tip = new ListerItemTooltip(this); + setTooltipColumn(Lister::ColIcon); +#endif //KUBUNTU + + m_icons[ u8( "package-install" ) ] = u8( "adept_install" ); + m_icons[ u8( "package-remove" ) ] = u8( "adept_remove" ); + m_icons[ u8( "package-upgrade" ) ] = u8( "adept_upgrade" ); + m_icons[ u8( "package-keep" )] = u8( "adept_keep" ); + m_icons[ u8( "package-reinstall" )] = u8( "adept_reinstall" ); + m_icons[ u8( "package-purge" )] = u8( "adept_purge" ); + + setSorting( -1 ); + // addColumn(" ", 40); + // addColumn(" ", 18); + QFontMetrics met( font() ); + + // BE SURE TO UPDATE THE Column ENUM WHEN YOU UPDATE HERE! + addColumn( i18n( "Package" ), 180); +#ifdef KUBUNTU + addColumn( i18n( " " ), 18); // This column is for identifying + // main packages. (manchicken) +#endif + addColumn( i18n( "Status" ), met.width( i18n( "not installed" ) ) + 10 ); + addColumn( i18n( "Requested" ), met.width( i18n( "Requested" ) ) + 10 ); + addColumn( i18n( "Description" ), 300); + setToggleColumn( Lister::ColFirst ); + + for ( int col = ColFirst; col < ColLast; ++col ) + setColumnAlignment( col, Qt::AlignLeft | Qt::AlignVCenter ); + + setResizeMode( LastColumn ); + connect( this, SIGNAL( selectionChanged() ), SLOT( updateActions() ) ); + connect( this, + SIGNAL( contextMenuRequested( QListViewItem *, + const QPoint &, int ) ), + this, SLOT( + contextMenu( QListViewItem *, const QPoint &, int) ) ); + m_tip = 0; + // m_tip = new ListerTooltip( viewport(), this ); +} + +Lister::~Lister() +{ + delete m_tip; +} + +void Lister::scheduleRebuild() +{ + if (!m_rebuildScheduled) { + // kdDebug() << "Lister scheduling rebuild" << endl; + QTimer::singleShot( 0, this, SLOT( rebuild() ) ); + } + m_rebuildScheduled = true; +} + +void Lister::updateActions() +{ + emit actionsChanged( this ); +} + +void Lister::notifyPostChange( component::Base * ) +{ + kdDebug() << "notifyRefresh()" << endl; + updateActions(); + triggerUpdate(); +} + +void Lister::notifyPreRebuild( component::Base *b ) +{ + kdDebug() << "Lister::notifyPreRebuild( " << b << " )" << endl; + // Cache &c = cache::Global::get( m_cache ); + setEnabled( false ); + if ( dynamic_cast< component::PackageTags * >( b ) != 0 ) { + kdDebug() << "clearing cardinality" << endl; + m_cardinality.clear(); + } + if ( dynamic_cast< component::Packages * >( b ) != 0 ) { + kdDebug() << "clearing lister" << endl; + clear(); + m_items.clear(); + m_cardinality.clear(); + } +} + +void Lister::notifyPostRebuild( component::Base *b ) +{ + kdDebug() << "Lister::notifyPostRebuild( " << b << " )" << endl; + scheduleRebuild(); + if ( dynamic_cast< component::State * >( b ) != 0 ) { + setEnabled( true ); + } +} + +bool lessByName( const entity::Entity &e1, const entity::Entity &e2 ) +{ + if ( e1.is< entity::Named >() && e2.is< entity::Named >() ) { + entity::Named &n1 = downcast< entity::Named >( e1 ), + &n2 = downcast< entity::Named >( e2 ); + return n1.name() < n2.name(); + } + return e1 < e2; +} + +bool Lister::cancelRebuild() { + // kdDebug() << "cancel rebuild: " << m_inRebuild << ", " << m_cancelRebuild << endl; + if ( m_inRebuild ) { + m_rebuildScheduled = false; + m_cancelRebuild = true; + } + if ( !cache::Global::get( m_cache ).isOpen() ) { + m_rebuildScheduled = false; + return true; + } + return m_cancelRebuild; +} + +void Lister::cleanRebuild() +{ + scheduleRebuild(); +} + +Lister::CreateItem::CreateItem( Lister *_l, ListerItem *p ) + : l( _l ), time( 0 ), items( 0 ), last( 0 ), parent( p ) +{ +} + +Lister::CreateItem::~CreateItem() +{ + // delete timer; +} + +Lister::Map::value_type Lister::CreateItem::operator()( entity::Entity e ) +{ + items ++; + if ( l->m_cancelRebuild ) throw 0; // XXX proper exception please + // kdDebug() << "trying to acquire mutex" << endl; + l->m_rebuildMutex.lock(); + // kdDebug() << "mutex acquired" << endl; + + // count tags + if ( e.is< entity::Package >() ) { + const std::set<ept::debtags::Tag> &tags = downcast< entity::Package >( e ).tags(); + for (std::set<ept::debtags::Tag>::iterator i = tags.begin(); i != tags.end(); ++ i ) + l->m_cardinality[ *i ] ++; + } + + if ( last ) { + if ( parent ) + last = new ListerItem( parent, last, e ); + else + last = new ListerItem( l, last, e ); + } else { + if ( parent ) + last = new ListerItem( parent, e ); + else + last = new ListerItem( l, e ); + } + l->m_rebuildMutex.unlock(); + if ( e.is< entity::Relation >() ) + // this should be safe because the parent thread is waiting + // for us and ensures that universe (libapt-front) is kept + // unchanged while we run + l->insertRangeInternal( InsertRangePair( + last, downcast< entity::Relation >( e ).targetPackages() ) ); + // we may want to use recursive async call instead? why? + /* Threads::enqueue( + asyncCall( std::bind2nd( std::mem_fun( &Lister::insertRangeInternal ), + InsertRangePair( + last, + downcast< entity::Relation >( e ).targetPackages() ) ), + l ), &(l->m_rebuildMutex) ); + */ + return std::make_pair( e, last ); +} + +void Lister::reallyUpdate() +{ + bool en = isUpdatesEnabled(); + setUpdatesEnabled( true ); + triggerUpdate(); + setUpdatesEnabled( en ); +} + +void Lister::insertRange( Range r ) { + insertRangeInternal( InsertRangePair( 0, r ) ); +} +void Lister::insertRangeInternal( InsertRangePair a ) +{ + // kdDebug() << "insertRange running..." << endl; + try { + std::transform( a.second, a.second.end(), + inserter( m_items, m_items.begin() ), + CreateItem( this, a.first ) ); + } catch ( ... ) {} + m_itemCount = m_items.size(); +} + +/* void Lister::rebuildInsertRange( Range r ) { + insertRange( 0, r ); + } */ + +void Lister::rebuild() +{ + Cache &c = cache::Global::get( m_cache ); + if ( cancelRebuild() ) { + scheduleRebuild(); + return; + } + + m_inRebuild = true; + m_rebuildMutex.lock(); + + emit rebuildStarted(); + + c.progress().OverallProgress( 0, 0, 0, i18n( "Filtering" ) ); + kdDebug() << "rebuild running" << endl; + clock_t _c = clock(), C; + for ( Cardinality::iterator i = m_cardinality.begin(); + i != m_cardinality.end(); ++i ) + i->second = 0; + + kdDebug() << "querying m_rangeProvider " << m_rangeProvider << "..." << endl; + + Range r = filteredRange( m_rangeProvider ? + m_rangeProvider->listerRange() : range( VectorRange() ), + m_baseF ); + C = (clock() - _c) / 1000; _c = clock(); + + setUpdatesEnabled( false ); + kdDebug() << "clearing..." << endl; + clear(); + m_items.clear(); + + kdDebug() << "asyncCall to rebuildInsertRange..." << endl; + QThread *t = asyncCall( std::bind2nd( + std::mem_fun( &Lister::insertRangeInternal ), + InsertRangePair( 0, r ) ), + this ); + + kdDebug() << "starting the thread..." << endl; + + QTimer timer; + connect( &timer, SIGNAL( timeout() ), + this, SLOT( reallyUpdate() ) ); + timer.start( 0 ); + + m_rebuildMutex.unlock(); + Threads::enqueue( t, &m_rebuildMutex ); + Threads::wait(); + + timer.stop(); + + kdDebug() << "thread finished..." << endl; + C = (clock() - _c) / 1000; _c = clock(); + kdDebug() << m_items.size() << " entities synced, time = " << C << endl; + + setUpdatesEnabled( true ); + c.progress().Done(); + if ( m_openToplevel ) openToplevel(); + triggerUpdate(); + + if ( !m_cancelRebuild ) { + for ( Cardinality::iterator i = m_cardinality.begin(); + i != m_cardinality.end(); ++i ) + if ( i->second == m_itemCount ) + i->second = -1; + emit cardinalityChanged( m_cardinality ); + } + + m_inRebuild = false; + m_rebuildScheduled = false; + m_cancelRebuild = false; + emit rebuildFinished(); +} + +void Lister::baseAnd( Predicate o ) +{ + m_baseF = predicate::predicate( m_baseF and o ); + // emit filterChanged( m_baseF ); + cancelRebuild(); + scheduleRebuild(); +} + +void Lister::baseSet( Predicate o ) +{ + m_baseF = o; + // emit filterChanged( m_baseF ); + cancelRebuild(); + scheduleRebuild(); +} + +void Lister::interactiveAnd( Predicate o ) +{ + m_interactiveF = predicate::predicate( m_interactiveF and o ); + cancelRebuild(); + scheduleRebuild(); +} + +void Lister::interactiveDrop( Predicate o ) +{ + m_interactiveF = predicate::remove( m_interactiveF, o ); + cancelRebuild(); + scheduleRebuild(); +} + +bool Lister::itemSelected( Map::value_type i ) +{ + return not i.second->isSelected(); +} + +entity::Entity Lister::extractKey( Map::value_type i ) +{ + return i.first; +} + +Lister::VectorRange Lister::selection() +{ + VectorRange ret; + Map m; + std::remove_copy_if( m_items.begin(), m_items.end(), + inserter( m, m.begin() ), + itemSelected ); + std::transform( m.begin(), m.end(), + consumer( ret ), + extractKey ); + return ret; +} + +Lister::VectorRange Lister::content() +{ + VectorRange ret; + std::transform( m_items.begin(), m_items.end(), + consumer( ret ), + extractKey ); + return ret; +} + +QString ListerItem::text( int column ) const +{ + // if (column == 0) return ""; // until we redo paintcell for the col + if (entity().is<entity::Package>()) { + entity::Package p = entity(); + switch (column) { + + case Lister::ColPackage: return u8( p.name( u8( i18n( "n/a" ) ) ) ); + case Lister::ColStatus: return u8( p.statusString( u8( i18n( "n/a" ) ) ) ); + case Lister::ColRequested: return u8( p.actionString( u8( i18n( "n/a" ) ) ) ); + case Lister::ColDescription: return u8( p.shortDescription( u8( i18n( "n/a" ) ) ) ); + // case 2: return p.candidateVersion().versionString(); + } + } + if ( entity().is< entity::Relation >() && column == 0 ) + return downcast< entity::Relation >( entity() ).format(); + return u8( "" ); +} + +#ifdef KUBUNTU +const QPixmap* ListerItem::pixmap( int column ) const +{ + if (entity().is<entity::Package>()) { + entity::Package p = entity(); + + // Are we in a main repo? A slash indicates a non-main repo. + if (column == Lister::ColIcon && + p.section(string("/")).find("/") == string::npos) { + + // Load the icon if it hasn't been created. + if (main_icon == 0) { + main_icon = new QPixmap(SmallIcon(u8("adept_main_indicator"))); + } + + // Return the icon... + return main_icon; + } else if (column == Lister::ColFirst) { + return static_cast<const QPixmap*>(&m_pixmap); + } + } + + if (non_main_icon == 0) { + non_main_icon = new QPixmap(); + } + + return non_main_icon; +} +#endif /* KUBUNTU */ + +ListerItem::~ListerItem() +{ +} + +void ListerItem::paintCell ( QPainter *p, const QColorGroup &cg, + int column, int width, int alignment ) +{ + if ( width <= 0 ) + return; + QColorGroup _cg( cg ); + QColor c = _cg.text(); + QPixmap pm( width, height() ); + QPainter _p( &pm ); + if ( entity().is<entity::Package>() ) { + entity::Package p = entity(); + + // Paint the status column + if ( column == Lister::ColStatus ) { + c = statusColor( p ); + } + + // Paint the action column + if ( column == Lister::ColRequested ) { + c = actionColor( p ); + } + } + _cg.setColor( QColorGroup::Text, c ); + if ( extender() ) { // make the icon appear at top... this + // probably breaks big-text displays? + // --> somewhat, but not too badly + alignment &= ~AlignVertical_Mask; + alignment |= AlignTop; + } + KListViewItem::paintCell( &_p, _cg, column, width, alignment ); + p->drawPixmap( 0, 0, pm ); +} + +void Lister::contextMenu( QListViewItem *it, const QPoint &pt, int /*c*/ ) +{ + if (! it) // check for actor when we have one... + return; + m_context = dynamic_cast< ListerItem * >( it ); + VectorRange sel = selection(); + // entity::Package p = (dynamic_cast<ListerItem *>(it)->entity()); + KPopupMenu *m = new KPopupMenu (this); + utils::Range< Actor > r = actor::Global< entity::Package >::list(); + int id = 8; + try { + for (; r != r.end(); ++r) { + m->insertItem( SmallIconSet( m_icons[ u8( r->name() ) ] ), + i18n(QString(r->prettyName()).ascii()), id ); + m->setItemEnabled( + id, r->possible( utils::upcastRange< entity::Package >( sel ) ) ); + ++id; + } + } catch ( std::bad_cast ) {} // ignore (this is broken, but + // easiest fix) + bool open = m_context->extender(); + m->insertItem( open ? i18n( "Hide details" ) : + i18n( "Show details" ), open ? 1 : 0 ); + connect(m, SIGNAL(activated(int)), this, SLOT(contextActivated(int))); + m->exec(pt); + delete m; +} + +void Lister::contextActivated( int id ) +{ + VectorRange sel = selection(); + try { + if (id >= 8) { + utils::Range< Actor > r = actor::Global< entity::Package >::list(); + std::advance( r, id - 8 ); + (*r)( utils::upcastRange< entity::Package >( sel ) ); + updateActions(); + } + if (id < 8) { + VectorRange i = sel.begin(); + while (i != i.end()) { + if (id == 0) + m_items[*i]->showExtender(); + if (id == 1) + m_items[*i]->hideExtender(); + ++ i; + } + } + } catch ( std::bad_cast ) {} // ignore (this is broken, but +} + +ListerItemExtender::~ListerItemExtender() +{ +} + +ListerItemExtender::ListerItemExtender( QWidget *parent, const char * n) + : ListerItemExtenderUi( parent, n ) +{ + observeComponent< component::State >(); + adjustFontSize( m_description, -1 ); + connect( m_details, SIGNAL( clicked() ), + this, SLOT( detailsClicked() ) ); + + m_packageInfo->adjustFontSize( -1 ); + m_packageInfo->hideStatus(); +} + +void ListerItemExtender::detailsClicked() { + detailsRequested( m_entity ); +} + +ListerItem *ListerItemExtender::item() +{ + return dynamic_cast< ListerItem * >( m_item ); +} + +void ListerItemExtender::mouseReleaseEvent( QMouseEvent *e ) { + e->ignore(); + if ( childAt( e->pos() ) != static_cast< QWidget * >( m_name ) ) + e->accept(); +} +void ListerItemExtender::setItem( ExtendableItem *i ) +{ + ItemExtender::setItem( i ); + m_entity = item()->entity(); + // setupColors(); + m_indicator->setPixmap(*(item()->pixmap(Lister::ColIcon))); + m_indicator->setMinimumWidth(18); + + kdDebug() << "ListerItemExtender::setItem connecting" << endl; + connect( this, SIGNAL( detailsRequested( Lister::Entity ) ), + item()->list(), SIGNAL( detailsRequested( Lister::Entity ) ) ); + + entity::Version v; + entity::Package p; + + if ( m_entity.is< entity::Version >() ) { + v = m_entity; + p = v.package(); + } + + if ( m_entity.is< entity::Package >() ) { + p = m_entity; + v = p.anyVersion(); + } + + if ( !v.valid() ) { + m_logical->setText( i18n( "Immutable" ) ); + m_logical->setEnabled( false ); + m_details->setEnabled( false ); + return; + } + + m_name->setText( /* QString( "<b>" ) + */ + v.package().name( std::string( "oops" ) ) /* + "</b>" */ ); + QString l = u8( v.longDescription( + u8( i18n( "No long description available" ) ) ) ); + + m_description->setText( QString( "<qt>" ) + + formatLongDescription( l ) + "</qt>" ); + m_description->adjustSize(); + m_description->installEventFilter( this ); + + m_packageInfo->setVersion( v, m_entity.is< entity::Version >() ); + + notifyPostChange( 0 ); +} + +void ListerItemExtender::notifyPostRebuild( component::Base *b ) +{ // need to catch undo/redo effects + return notifyPostChange( b ); +} + +void ListerItemExtender::notifyPostChange( component::Base * ) +{ + // without the timer to break it, there could be a loop where + // we connect the clicked() signal to a slot which would be + // invoked right away when we return -> evil + QTimer::singleShot( 0, this, SLOT( updateLogical() ) ); +} + +void ListerItemExtender::updateLogical() { + entity::Package pkg = entity(); + EntityActor *a = 0; + + m_status->setText( colorify( + statusColor( pkg ), + u8( pkg.statusString( u8( i18n( "Unknown" ) ) ) ) ) ); + m_change->setText( colorify( + actionColor( pkg ), + u8( pkg.actionString( u8( i18n( "Unknown" ) ) ) ) ) ); + + + m_logical->setEnabled( true ); + if (pkg.canKeep()) { + a = new EntityActor( pkg.keep() ); + } else if (pkg.canUpgrade()) { + a = new EntityActor( pkg.upgrade() ); + } else if (pkg.canInstall()) { + a = new EntityActor( pkg.install() ); + } else if (pkg.canRemove()) { + a = new EntityActor( pkg.remove() ); + } + + if (a) { + m_logical->setText( u8( a->actor().prettyName() ) ); + connect( m_logical, SIGNAL( clicked() ), + a, SLOT( destructiveAct() ) ); + } else { + m_logical->setText( i18n( "Immutable" ) ); + m_logical->setEnabled( false ); + } + +} + +bool ListerItemExtender::eventFilter( QObject *o, QEvent *e ) +{ + if (o == m_description && e->type() == QEvent::Wheel) { + // kdDebug() << "discarding wheel event..." << endl; + QApplication::sendEvent( this, e ); + return true; + } + return false; +} + +void ListerItemExtender::resize( int w, int h ) +{ + // XXX the magic constants are probably style-dependent... AW + int namew = - item()->lister()->extenderOffset( item() ) + - layout()->margin() + - layout()->spacing() + + item()->lister()->columnWidth( 0 ); + int statw = item()->lister()->columnWidth( Lister::ColStatus ) + - layout()->spacing(); + int chw = item()->lister()->columnWidth( Lister::ColRequested ) + - layout()->spacing() - 3; // wth... + m_name->setMinimumWidth( namew ); + m_status->setMinimumWidth( statw ); + m_change->setMinimumWidth( chw ); + m_packageInfo->adjustSize(); + m_leftHeight = m_name->height() + m_packageInfo->height() + + m_logical->height() + 20; + QWidget::resize( w, 500 ); + QWidget::resize( + w, + QMAX( m_description->contentsHeight() + 16, + m_leftHeight ) ); +} + +bool entityLess::operator()( entity::Entity e1, entity::Entity e2 ) +{ + if ( e1.is< entity::Package >() ) { + if ( e2.is< entity::Package >() ) + return e1 < e2; + return true; + } + + if ( e1.is< entity::Version >() ) { + if ( e2.is< entity::Package >() ) + return false; + if ( e2.is< entity::Version >() ) + return e1 < e2; + return true; + } + + if ( e1.is< entity::Relation >() ) { + if ( e2.is< entity::Package >() ) + return false; + if ( e2.is< entity::Version >() ) + return false; + if ( e2.is< entity::Relation >() ) + return e1 < e2; + return true; + } + return true; +} + +bool ListerItem::less( const ExtendableItem *b ) const +{ + entity::Entity e1 = entity(), e2 = dynamic_cast< const ListerItem * >( b )->entity(); + return entityLess()( e1, e2 ); +} + +bool ListerItem::keepLess( const ListerItem *o ) const +{ + const ListerItem *b = o; + while ( b != 0 ) { + if ( b == this ) + return false; + b = b->m_previous; + } + while ( o != 0 ) { + o = dynamic_cast< const ListerItem * >( o->nextSibling() ); + if ( o == this ) + return true; + } + return false; +} + +QString ListerTooltip::format( const QString &what, + const QString &txt, bool nobr ) +{ + QString ret = "<b>" + what + "</b> " + (nobr ? "<nobr>" : "") + + txt + (nobr ? "</nobr>" : "") + "<br>"; + return ret; +} + +void ListerTooltip::maybeTip( const QPoint &pt ) +{ + if ( !m_parent ) + return; + kdDebug() << "ListTreeWidgetTooltip::maybeTip ()" << endl; + ListerItem *x = dynamic_cast<ListerItem *>( m_parent->itemAt( pt ) ); + if ( !x ) + return; + if ( x->extender() ) + return; // no tips for extended items, thank you + QString str = u8( "<qt>" ); + QString descr, cand, cur; + descr = cand = cur = i18n( "<i>Not available</i>" ); + entity::Package p( x->entity() ); + descr = p.shortDescription( std::string( + i18n( "<i>Not available</i>" ).local8Bit() ) ); + try { + cand = u8( p.candidateVersion().versionString() ); + } catch (...) {} + try { + cur = u8( p.installedVersion().versionString() ); + } catch (...) {} + + str += format( i18n( "Package:" ), u8( p.name() ) ); + str += format( i18n( "Description:" ), descr ); + str += format( i18n( "Current Version:" ), cur ); + str += format( i18n( "Candidate Version:" ), cand ); + + str.append( u8( "</qt>" ) ); + tip( m_parent->itemRect( x ), str ); +} + +void ListerItemTooltip::maybeTip(const QPoint& pt) { + if (!m_parent) { + return; + } + + // Grab the column + const int col = m_parent->header()->sectionAt(pt.x()); + if (col != Lister::ColIcon) { + return; + } + + // Grab the item + const QListViewItem* item = m_parent->itemAt(pt); + if (!item) { + return; + } else if (item->pixmap(col) != main_icon) { + // Ignore items without pixmaps, as they have no indicator. + return; + } + + // Grab the item rectangle + const QRect irect = m_parent->itemRect(item); + if (!irect.isValid()) { + return; + } + + // Grab the header rectangle + const QRect hrect = m_parent->header()->sectionRect(col); + if (!hrect.isValid()) { + return; + } + + // Grab the cell rectangle + const QRect cell(hrect.left(), irect.top(), + hrect.width(), irect.height()); + tip(cell, i18n("This logo indicates that this package is officially supported by the Kubuntu development and support teams.")); +} diff --git a/adept/adept/lister.h b/adept/adept/lister.h new file mode 100644 index 0000000..6270c42 --- /dev/null +++ b/adept/adept/lister.h @@ -0,0 +1,261 @@ +/** -*- C++ -*- + @file adept/lister.h + @author Peter Rockai <me@mornfall.net> +*/ + +#define KUBUNTU + +#include <qtooltip.h> +#include <qmap.h> +#include <qmutex.h> +#include <set> +#include <qpixmap.h> + +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/entity/package.h> +#include <apt-front/actor.h> +#include <apt-front/predicate/matchers.h> +#include <apt-front/predicate/combinators.h> +#include <apt-front/utils/range.h> + +#include <adept/extendablelist.h> +#include <adept/listerextenderui.h> +#include <adept/actor.h> +#include <adept/listerpredicate.h> + +#ifndef EPT_LISTER_H +#define EPT_LISTER_H + +class KLineEdit; + +namespace adept { + +using namespace aptFront; +using namespace aptFront::cache; +class ListerTooltip; +class ListerItemTooltip; +class ListerItemExtender; +class ListerItem; +class Lister; + +struct entityLess { + bool operator()( entity::Entity e1, entity::Entity e2 ); +}; + +class Lister: public ExtendableList, public Observer +{ + Q_OBJECT; +public: + static const int ColPackage = 0; +#ifdef KUBUNTU + static const int ColIcon = 1; + static const int ColStatus = 2; + static const int ColRequested = 3; + static const int ColDescription = 4; + static const int ColLast = 4; +#else + static const int ColStatus = 1; + static const int ColRequested = 2; + static const int ColDescription = 3; + static const int ColLast = 3; +#endif + static const int ColFirst = 0; + typedef entity::Entity Entity; + typedef std::vector< Entity > Vector; + typedef utils::Range< Entity > Range; + typedef utils::VectorRange< Entity > VectorRange; + typedef std::set< Entity > Set; + typedef std::map< Entity, ListerItem *, entityLess > Map; + typedef actor::Actor< entity::Package > Actor; + typedef predicate::Predicate< Entity > Predicate; + typedef std::map< ept::debtags::Tag, int > Cardinality; + struct RangeProvider { + virtual Range listerRange() = 0; + }; + + Lister (QWidget *parent = 0, const char *name = 0); + ~Lister(); + void setSource(); + virtual void notifyPostChange( component::Base * ); + virtual void notifyPreRebuild( component::Base * ); + virtual void notifyPostRebuild( component::Base * ); + VectorRange selection(); + VectorRange content(); + int itemCount() { return m_itemCount; } + // void setRange( const Range &r ) { m_range = r; } + void setRangeProvider( RangeProvider *r ) { m_rangeProvider = r; } + void insertRange( Range ); + void setOpenToplevel( bool o ) { m_openToplevel = o; } + + bool busy() { return m_rebuildScheduled || m_inRebuild; } + +signals: + // this is adept::Lister because of braindead moc + void actionsChanged( adept::Lister * ); + void cardinalityChanged( const Lister::Cardinality & ); + void detailsRequested( Lister::Entity ); + void rebuildStarted(); + void rebuildFinished(); + // void filterChanged( Lister::Predicate ); + +public slots: + virtual void cleanRebuild(); + virtual void rebuild(); + virtual void baseAnd( ListerPredicate ); + virtual void interactiveDrop( ListerPredicate ); + virtual void interactiveAnd( ListerPredicate ); + virtual void baseSet( ListerPredicate ); + virtual void updateActions(); + virtual void scheduleRebuild(); + virtual void reallyUpdate(); +protected slots: + void contextMenu( QListViewItem *, const QPoint &, int ); + void contextActivated( int ); +protected: + typedef std::pair< ListerItem *, Range > InsertRangePair; + void insertRangeInternal( InsertRangePair ); + ListerTooltip *m_tip; + + static Entity extractKey( Map::value_type ); + static bool itemSelected( Map::value_type ); + + struct CreateItem { + CreateItem( Lister *, ListerItem * ); + ~CreateItem(); + Map::value_type operator()( Entity ); + Lister *l; + int time; + int items; + ListerItem *last; + ListerItem *parent; + }; + + bool cancelRebuild(); + void rebuildInsertRange( Range ); + + ListerItem *m_context; + QMap< QString, QString > m_icons; + Map m_items; + Vector m_all; + RangeProvider *m_rangeProvider; + Predicate m_baseF, m_interactiveF; + int m_itemCount; + bool m_rebuildScheduled:1; + bool m_inRebuild:1; + bool m_cancelRebuild:1; + bool m_openToplevel:1; + Cardinality m_cardinality; + QMutex m_rebuildMutex; +}; + +class ListerTooltip : public QToolTip +{ +public: + ListerTooltip (QWidget *v, Lister *p) : QToolTip (v, 0), m_parent (p) {}; + ListerTooltip(Lister*p) : QToolTip(p,0), m_parent(p) {}; +protected: + QString format( const QString &, const QString &, bool = true ); + virtual void maybeTip (const QPoint &p); + Lister *m_parent; +}; + +class ListerItemTooltip : public QToolTip { +public: + ListerItemTooltip(const Lister* parent) : + QToolTip(parent->viewport(),0), + m_parent(parent) {}; + +protected: + const Lister* m_parent; + virtual void maybeTip (const QPoint& p); +}; + +class ListerItemExtender : public ListerItemExtenderUi, + public cache::Observer { + Q_OBJECT +public: + ListerItemExtender( QWidget *parent = 0, const char * n = 0 ); + ~ListerItemExtender(); + virtual void resize( int w, int h ); + void setItem( ExtendableItem *i ); + ListerItem *item(); + entity::Entity entity() const { return m_entity; } + void notifyPostChange( component::Base * ); + void notifyPostRebuild( component::Base * ); +protected slots: + void detailsClicked(); + void updateLogical(); +signals: + void detailsRequested( Lister::Entity ); +protected: + bool eventFilter( QObject *o, QEvent *e ); + void mouseReleaseEvent( QMouseEvent *e ); + entity::Entity m_entity; + unsigned m_leftHeight; +}; + +class ListerItem: public ExtendableItem +{ +public: + ListerItem(Lister *v, entity::Entity e) + : ExtendableItem (v), m_previous( 0 ), m_entity( e ) + {}; + + ListerItem(Lister *v, ListerItem *i, entity::Entity e) + : ExtendableItem( v, i ), m_previous( i ), m_entity( e ) + {}; + + ListerItem(ListerItem *p, ListerItem *i, entity::Entity e) + : ExtendableItem( p, i ), m_previous( i ), m_entity( e ) + {}; + + ListerItem(ListerItem *p, entity::Entity e) + : ExtendableItem( p ), m_previous( 0 ), m_entity( e ) + {}; + + ~ListerItem(); + + virtual ItemExtender *createExtender() { + if ( extendable() ) + return new ListerItemExtender(); + return 0; + } + + /* virtual void updateIcon( const QPixmap &p ) { + if ( m_entity.is< entity::Package >() + || m_entity.is< entity::Version >() ) + return ExtendableItem::updateIcon( p ); + setPixmap( list()->toggleColumn(), QPixmap() ); + } */ + + virtual QString text( int column ) const; +#ifdef KUBUNTU + virtual void setUpdatedIcon(QPixmap& pm) { m_pixmap=pm; }; + virtual const QPixmap* pixmap( int column ) const; +#endif + entity::Entity entity() { return m_entity; } + const entity::Entity entity() const { return m_entity; } + virtual void paintCell (QPainter *p, const QColorGroup &cg, + int column, int width, int alignment); + virtual bool less( const ExtendableItem * ) const; + Lister *lister() { + return dynamic_cast< Lister* >( listView() ); + } + + // beware, makes sort O(n^2lg(n^2)) + bool keepLess( const ListerItem *o ) const; + virtual bool extendable() const { + return ( entity().is< entity::Package >() + || m_entity.is< entity::Version >() ); + } + +protected: + ListerItem *m_previous; + entity::Entity m_entity; + QPixmap m_pixmap; + // ListerItemTooltip* m_tip; +}; + +} + +#endif /* ifndef PKGLIST_H */ diff --git a/adept/adept/listerextenderui.ui b/adept/adept/listerextenderui.ui new file mode 100644 index 0000000..3f89eaf --- /dev/null +++ b/adept/adept/listerextenderui.ui @@ -0,0 +1,309 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::ListerItemExtenderUi</class> +<widget class="adept::ItemExtender"> + <property name="name"> + <cstring>ListerItemExtenderrUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>587</width> + <height>230</height> + </rect> + </property> + <property name="caption"> + <string>ListerItemExtenderrUi</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <spacer row="4" column="2"> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>4</width> + <height>4</height> + </size> + </property> + </spacer> + <spacer row="2" column="3"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>4</width> + <height>4</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget" row="0" column="1"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_name</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="text"> + <string>name</string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_indicator</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_status</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="text"> + <string>status</string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_change</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="text"> + <string>change</string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + </hbox> + </widget> + <widget class="QTextBrowser" row="0" column="2" rowspan="4" colspan="1"> + <property name="name"> + <cstring>m_description</cstring> + </property> + <property name="focusPolicy"> + <enum>NoFocus</enum> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <property name="resizePolicy"> + <enum>AutoOneFit</enum> + </property> + <property name="vScrollBarMode"> + <enum>AlwaysOff</enum> + </property> + <property name="hScrollBarMode"> + <enum>AlwaysOff</enum> + </property> + <property name="text"> + <string>description...</string> + </property> + </widget> + <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>4</number> + </property> + <spacer> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>10</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_logical</cstring> + </property> + <property name="text"> + <string>logical</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_details</cstring> + </property> + <property name="text"> + <string>Details</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer5_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>10</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="adept::PackageInfo" row="1" column="1"> + <property name="name"> + <cstring>m_packageInfo</cstring> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>80</height> + </size> + </property> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer13</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>1</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> +</widget> +<customwidgets> + <customwidget> + <class>adept::PackageInfo</class> + <header location="global">adept/packageinfo.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</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="PNG" length="1003">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082</data> + </image> +</images> +<includes> + <include location="global" impldecl="in declaration">adept/extendablelist.h</include> +</includes> +<layoutdefaults spacing="0" margin="4"/> +<includehints> + <includehint>adept/packageinfo.h</includehint> +</includehints> +</UI> diff --git a/adept/adept/listerpredicate.h b/adept/adept/listerpredicate.h new file mode 100644 index 0000000..98f1b41 --- /dev/null +++ b/adept/adept/listerpredicate.h @@ -0,0 +1,14 @@ +// -*- C++ -*- +#include <apt-front/cache/entity/entity.h> +#include <apt-front/predicate/predicate.h> + +#ifndef EPT_LISTERPREDICATE_H +#define EPT_LISTERPREDICATE_H + +namespace adept { +using namespace aptFront; +using namespace cache; +typedef predicate::Predicate< entity::Entity > ListerPredicate; +} + +#endif diff --git a/adept/adept/packagedetails.cpp b/adept/adept/packagedetails.cpp new file mode 100644 index 0000000..56dd80b --- /dev/null +++ b/adept/adept/packagedetails.cpp @@ -0,0 +1,273 @@ +#include <qtoolbutton.h> +#include <qtextbrowser.h> +#include <qlabel.h> +#include <klocale.h> +#include <kiconloader.h> +#include <qpushbutton.h> +#include <ktoolbar.h> +#include <ktoolbarbutton.h> + +#include <kfileitem.h> +#include <kfiledetailview.h> +#include <kapplication.h> + +#include <adept/lister.h> +#include <adept/tagchooser.h> +#include <adept/packageinfo.h> +#include <adept/packagedetails.h> +#include <adept/utils.h> +#include <adept/changelog.h> + +#include <fstream> + +using namespace adept; + +ItemChangelog* global_changelog = new ItemChangelog(); + +PackageDetails::PackageDetails( QWidget *w, const char *n ) + : PackageDetailsUi( w, n ), + m_thread( 0 ), + m_qtMutex( true ), + m_logicalAct( 0 ), m_removeAct( 0 ), + m_fileListRunning( false ) +{ + m_toolbar->setIconSize( 22 ); + m_toolbar->setIconText( KToolBar::IconTextRight ); + + m_toolbar->insertButton( u8( "back" ), BBack, false, i18n( "Back" ) ); + m_toolbar->insertButton( u8( "forward" ), BForward, false, i18n( "Forward" ) ); + m_toolbar->insertLineSeparator(); + m_toolbar->insertButton( u8( "" ), BShow, true, i18n( "Show List" ) ); + + m_tags->setTitle( i18n( "Assigned Tags" ) ); + + m_lister->setRangeProvider( this ); // wee + // m_lister->setOpenToplevel( true ); + + m_description->setPaper( QBrush( colorGroup().background() ) ); + + connect( m_toolbar->getButton( BShow ), SIGNAL( clicked() ), + this, SIGNAL( showList() ) ); + connect( m_toolbar->getButton( BBack ), SIGNAL( clicked() ), + this, SIGNAL( back() ) ); + connect( m_toolbar->getButton( BForward ), SIGNAL( clicked() ), + this, SIGNAL( forward() ) ); + connect( m_lister, SIGNAL( detailsRequested( Lister::Entity ) ), + this, SIGNAL( detailsRequested( Lister::Entity ) ) ); + + observeComponent< component::State >(); + + adjustFontSize( m_name, 1 ); + + Cache &c = cache::Global::get( m_cache ); + component::Packages::iterator i = c.packages().packagesBegin(); + while ( !i->hasVersion() ) ++i; // ha hum... + setPackage( *i ); +} + +Lister::Range PackageDetails::listerRange() { + utils::Range< entity::Relation > r = m_package.depends(); + utils::VectorRange< entity::Entity > vr; + while ( r != r.end() ) { + if ( !r->targetPackages().empty() ) + std::cerr << r->targetPackages()->name() << std::endl; + vr.consume( *r ); + r = r.next(); + } + return vr.sorted(); +} + +void PackageDetails::loadFileListWorker() +{ + entity::Package p = m_package; + + std::string fl, flfile = "/var/lib/dpkg/info/" + p.name() + ".list"; + std::ifstream ifl( flfile.c_str() ); + + int i = 0; + kdDebug() << "PackageDetails::loadFileListWorker() entering loop" << endl; + + while ( ifl.is_open() && !ifl.eof() ) { + std::string line; + getline( ifl, line ); + if ( line == "/." || line == "" ) + continue; // nasty evil thing go away + m_qtMutex.lock(); + KURL url( "file:///" ); + url.addPath( u8( line ) ); + KFileItem *it = new KFileItem( url, u8( "" ), 0 ); + it->setName( u8( line ) ); + m_fileList->insertItem( it ); + ++i; + m_qtMutex.unlock(); + } + kdDebug() << "PackageDetails::loadFileListWorker() leaving loop" << endl; + ifl.close(); +} + +void PackageDetails::notifyPreRebuild( component::Base * ) { + kdDebug() << "PackageDetails::notifyPreRebuild()" << endl; + Threads::wait(); + m_logical->setEnabled( false ); + m_remove->setEnabled( false ); + m_logical->disconnect( SIGNAL( clicked() ) ); + m_remove->disconnect( SIGNAL( clicked() ) ); + delete m_logicalAct; + delete m_removeAct; + kdDebug() << "PackageDetails::notifyPreRebuild() done" << endl; +} + +void PackageDetails::loadFileList() { + Cache &c = cache::Global::get( m_cache ); + if ( m_fileListRunning || !c.isOpen() ) { + QTimer::singleShot( 100, this, SLOT( loadFileList() ) ); + return; + } + + kdDebug() << "PackageDetails::loadFileList()" << endl; + m_fileListRunning = true; + + // the following call is neccessary to invoke buildDefaultType of KMimeType + // the first time the method is called it will check for + // existence of application/octet-stream and *popup a dialog* if + // not found -- we don't want that to happen in a non-gui thread + KMimeType::defaultMimeTypePtr(); + m_thread = asyncCall( std::mem_fun( &PackageDetails::loadFileListWorker ), this ); + + m_qtMutex.lock(); + m_fileList->KFileView::clear(); + c.progress().OverallProgress( 0, 0, 0, i18n( "Loading filelist..." ) ); + + m_qtMutex.unlock(); + Threads::enqueue( m_thread, &m_qtMutex ); + Threads::wait(); + c.progress().Done(); + m_fileListRunning = false; + kdDebug() << "PackageDetails::loadFileList() finished" << endl; +} + +void PackageDetails::setPackage( cache::entity::Package p ) +{ + kdDebug() << "PackageDetails::setPackage()" << endl; + m_package = p.stable(); + m_name->setText( QString( "<b>" ) + + p.name( std::string( "No package" ) ) + "</b>" ); + m_info->setPackage( p ); + QString l = u8( p.longDescription( + std::string( i18n( "No long description available" ).local8Bit() ) ) ); + m_description->setText( QString( "<qt>" ) + + formatLongDescription( l ) + "</qt>" ); + + std::string na = u8( i18n( "not available" ) ); + m_tags->setTags( p.tags( entity::Package::TagSet() ) ); + m_tags->openToplevel(); + m_architecture->setText( labelFormat( i18n( "Architecture: " ), + p.architecture( na ) ) ); + m_filename->setText( labelFormat( i18n( "Filename: " ), p.fileName( na ) ) ); + m_md5->setText( labelFormat( i18n( "MD5: " ), p.md5sum( na ) ) ); + m_source->setText( labelFormat( i18n( "Source Package: " ), p.source( na ) ) ); + + /* IF IT ISN'T KUBUNTU, DON'T SUPPORT CHANGELOGS! */ +#ifdef KUBUNTU + // Lets go ahead and stick the changelog in there.... + try { + global_changelog->setParent(p); + m_changelog->setText(i18n("Loading...")); + connect(dynamic_cast<QObject*>(global_changelog), SIGNAL( changelogReady(QString) ), + dynamic_cast<QObject*>(this), SLOT( changelogDisplay(QString) )); + connect(dynamic_cast<QObject*>(this), SIGNAL( requestTheChangelog() ), + dynamic_cast<QObject*>(global_changelog), SIGNAL( changelogNeeded() )); + emit requestTheChangelog(); + } catch (...) {}; +#endif /* KUBUNTU */ + + notifyPostChange( 0 ); + m_lister->cleanRebuild(); + loadFileList(); +} + +void PackageDetails::changelogDisplay( QString content ) { + m_changelog->setText(content); +} + +void PackageDetails::notifyPostChange( cache::component::Base * ) +{ + kdDebug() << "PackageDetails::notifyPostChange()" << endl; + // without the timer to break it, there could be a loop where + // we connect the clicked() signal to a slot which would be + // invoked right away when we return -> evil + QTimer::singleShot( 0, this, SLOT( updateLogical() ) ); +} + +void PackageDetails::notifyPostRebuild( cache::component::Base *b ) +{ + kdDebug() << "PackageDetails::notifyPostRebuild( " << b << " )" << endl; + // can't call directly because stable entities are not guaranteed + // to be stabilised at this point yet + QTimer::singleShot( 0, this, SLOT( updateLogical() ) ); + QTimer::singleShot( 0, this, SLOT( loadFileList() ) ); + m_lister->cleanRebuild(); +} + +void PackageDetails::updateLogical() +{ + Cache &c = cache::Global::get( m_cache ); + if ( !c.isOpen() ) { + QTimer::singleShot( 100, this, SLOT( updateLogical() ) ); + return; + } + kdDebug() << "PackageDetails::updateLogical()" << endl; + entity::Package p = m_package; + kdDebug() << "PackageDetails::updateLogical: p = " << p.name() + << " p.component() = " << &p.component() << endl; + if ( !p.valid() ) return; // nothing to update + EntityActor *a = 0, *b = 0; + + if ( p.canUpgrade() ) { + a = new EntityActor( p.upgrade() ); + } else if ( p.canInstall() ) { + a = new EntityActor( p.install() ); + } else if ( p.canKeep() ) { + a = new EntityActor( p.keep() ); + } + + if ( p.canRemove() ) { + b = new EntityActor( p.remove() ); + } + + if ( a ) { + m_logical->setEnabled( true ); + m_logical->setText( u8( a->actor().prettyName() ) ); + connect( m_logical, SIGNAL( clicked() ), + a, SLOT( destructiveAct() ) ); + } else { + m_logical->setText( i18n( "Install" ) ); + m_logical->setEnabled( false ); + } + + if ( b ) { + m_remove->setEnabled( true ); + m_remove->setText( u8( b->actor().prettyName() ) ); + connect( m_remove, SIGNAL( clicked() ), + b, SLOT( destructiveAct() ) ); + } else { + m_remove->setText( i18n( "Remove" ) ); + m_remove->setEnabled( false ); + } + + m_logicalAct = a; + m_removeAct = b; + // std::copy( r, r.last(), vr ); + + // r.consume( utils::upcastRange< entity::Entity >( p.depends() ) ); +} + +void PackageDetails::setHasForward( bool e ) { + m_toolbar->setItemEnabled( BForward, e ); + // m_forward->setEnabled( e ); +} + +void PackageDetails::setHasBack( bool e ) { + m_toolbar->setItemEnabled( BBack, e ); + // m_back->setEnabled( e ); +} diff --git a/adept/adept/packagedetails.h b/adept/adept/packagedetails.h new file mode 100644 index 0000000..6d15185 --- /dev/null +++ b/adept/adept/packagedetails.h @@ -0,0 +1,58 @@ +/* -*- C++ -*- adept/packagedetails.h + written by Peter Rockai <me@mornfall.net> */ + +#include <apt-front/cache/entity/package.h> +#include <adept/packagedetailsui.h> +#include <adept/lister.h> +#include <adept/changelog.h> + +#include <qmutex.h> +#include <qguardedptr.h> + +#ifndef EPT_PACKGEDETAILS_H +#define EPT_PACKGEDETAILS_H + +class KToolBarButton; +class QThread; + +namespace adept { + +using namespace aptFront; + +class PackageDetails : public PackageDetailsUi, public Lister::RangeProvider, + public cache::Observer +{ + Q_OBJECT +public: + enum ButtonID { BForward, BBack, BShow }; + PackageDetails( QWidget *p = 0, const char *n = 0 ); + void setPackage( cache::entity::Package ); + void setHasForward( bool ); + void setHasBack( bool ); + virtual Lister::Range listerRange(); + void notifyPostChange( cache::component::Base * ); + void notifyPreRebuild( cache::component::Base * ); + void notifyPostRebuild( cache::component::Base * ); +signals: + void showList(); + void back(); + void forward(); + void detailsRequested( Lister::Entity ); + void requestTheChangelog(); +protected slots: + void loadFileList(); + void updateLogical(); + void changelogDisplay(QString content); +protected: + void loadFileListWorker(); + cache::entity::StablePackage m_package; + QMutex m_qtMutex; + QThread *m_thread; + QGuardedPtr< EntityActor > m_logicalAct, m_removeAct; + int m_fileListRunning; + +}; + +} + +#endif diff --git a/adept/adept/packagedetailsui.ui b/adept/adept/packagedetailsui.ui new file mode 100644 index 0000000..06e436a --- /dev/null +++ b/adept/adept/packagedetailsui.ui @@ -0,0 +1,506 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>PackageDetailsUi</class> +<widget class="QWidget"> + <property name="name"> + <cstring>PackageDetailsUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>705</width> + <height>529</height> + </rect> + </property> + <property name="caption"> + <string>Form1</string> + </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="KToolBar"> + <property name="name"> + <cstring>m_toolbar</cstring> + </property> + </widget> + <widget class="QFrame"> + <property name="name"> + <cstring>frame3</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>8</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="spacing"> + <number>2</number> + </property> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>m_name</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>(title)</string> + </property> + </widget> + <widget class="adept::PackageInfo" row="1" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>m_info</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>8</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>75</height> + </size> + </property> + </widget> + <spacer row="2" column="1"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="3" column="2"> + <property name="name"> + <cstring>m_remove</cstring> + </property> + <property name="text"> + <string>(remove)</string> + </property> + </widget> + <spacer row="3" column="0"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="3" column="1"> + <property name="name"> + <cstring>m_logical</cstring> + </property> + <property name="text"> + <string>(logical)</string> + </property> + </widget> + <spacer row="3" column="3"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QTextBrowser" row="0" column="4" rowspan="4" colspan="1"> + <property name="name"> + <cstring>m_description</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>28</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>NoFocus</enum> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="resizePolicy"> + <enum>AutoOneFit</enum> + </property> + <property name="vScrollBarMode"> + <enum>Auto</enum> + </property> + <property name="hScrollBarMode"> + <enum>AlwaysOff</enum> + </property> + <property name="text"> + <string>description...</string> + </property> + </widget> + </grid> + </widget> + <widget class="QTabWidget"> + <property name="name"> + <cstring>tabWidget2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>16</verstretch> + </sizepolicy> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Package Relationships</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="adept::Lister" row="0" column="0"> + <property name="name"> + <cstring>m_lister</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>120</height> + </size> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Installed Files</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KFileDetailView" row="0" column="0"> + <property name="name"> + <cstring>m_fileList</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage</cstring> + </property> + <attribute name="title"> + <string>Additional Information</string> + </attribute> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="adept::TagChooser"> + <property name="name"> + <cstring>m_tags</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>200</width> + <height>0</height> + </size> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_source</cstring> + </property> + <property name="text"> + <string>source</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_architecture</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>architecture</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_filename</cstring> + </property> + <property name="text"> + <string>file</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_md5</cstring> + </property> + <property name="text"> + <string>md5</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>61</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </hbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>changelog_tab</cstring> + </property> + <attribute name="title"> + <string>Developer Changelog</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QTextBrowser" row="0" column="0"> + <property name="name"> + <cstring>m_changelog</cstring> + </property> + <property name="focusPolicy"> + <enum>NoFocus</enum> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="resizePolicy"> + <enum>AutoOneFit</enum> + </property> + <property name="vScrollBarMode"> + <enum>Auto</enum> + </property> + <property name="hScrollBarMode"> + <enum>AlwaysOff</enum> + </property> + <property name="text"> + <string>description...</string> + </property> + </widget> + </grid> + </widget> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>adept::TagChooser</class> + <header location="global">adept/tagchooser.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> + <customwidget> + <class>adept::PackageInfo</class> + <header location="global">adept/packageinfo.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> + <customwidget> + <class>adept::Lister</class> + <header location="global">adept/lister.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> + <customwidget> + <class>KToolBar</class> + <header location="global">ktoolbar.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> + <customwidget> + <class>KFileDetailView</class> + <header location="global">kfiledetailview.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</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="PNG" length="1003">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082</data> + </image> +</images> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>ktoolbar.h</includehint> + <includehint>adept/packageinfo.h</includehint> + <includehint>adept/lister.h</includehint> + <includehint>kfiledetailview.h</includehint> + <includehint>adept/tagchooser.h</includehint> +</includehints> +</UI> diff --git a/adept/adept/packageinfo.cpp b/adept/adept/packageinfo.cpp new file mode 100644 index 0000000..dac788b --- /dev/null +++ b/adept/adept/packageinfo.cpp @@ -0,0 +1,181 @@ +/** -*- C++ -*- + @file adept/packageinfo.cpp + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qcolor.h> +#include <qlabel.h> +#include <qregexp.h> +#include <kdebug.h> +#include <klocale.h> + +#include <adept/packageinfo.h> +#include <adept/utils.h> + +using namespace adept; +using namespace cache; + +PackageInfo::PackageInfo( QWidget *p, const char *n ) + : PackageInfoUi( p, n ), m_specificVersion( false ) +{ + observeComponent< component::State >(); +} + +void PackageInfo::adjustFontSize( int s ) { + adept::adjustFontSize( m_status, s ); + adept::adjustFontSize( m_change, s ); + adept::adjustFontSize( m_section, s ); + adept::adjustFontSize( m_installedSize, s ); + adept::adjustFontSize( m_maintainer, s ); + adept::adjustFontSize( m_candidateVer, s ); + adept::adjustFontSize( m_installedVer, s ); +} + +void PackageInfo::hideStatus() { + m_status->hide(); + m_change->hide(); +} + +namespace adept { + +QColor statusColor( entity::Package p ) +{ + if ( !p.valid() ) + return Qt::black; + + QColor c = Qt::blue; + if (p.isInstalled()) + c = Qt::darkGreen; + if (p.isUpgradable()) + c = Qt::darkYellow; + if (p.isBroken()) + c = Qt::red; + return c; +} + +QColor actionColor( entity::Package p ) +{ + if ( !p.valid() ) + return Qt::black; + + QColor c = Qt::blue; + if (p.markedNewInstall()) + c = Qt::darkGreen; + if (p.markedUpgrade()) + c = Qt::darkYellow; + if (p.markedReInstall()) + c = Qt::darkYellow; + if (p.markedRemove()) + c = Qt::darkRed; + if (p.markedPurge()) + c = Qt::red; + if (p.willBreak()) + c = Qt::red; + return c; +} + +/* QString hexColor( QColor c ) +{ + QString r( "#%1%2%3" ); + return r.arg( c.red(), -2, 16 ).arg( c.green(), -2, 16 ).arg( c.blue(), -2, 16 ); + } */ + +QString colorify( QColor c, QString s ) +{ + return QString( "<font color=\"" ) + c.name() + + "\">" + s + "</font>"; +} + +QString formatLongDescription( QString l ) +{ + QRegExp rx( u8( "^(.*)\n" ) ); + rx.setMinimal( true ); + l.replace( rx, u8( "\\1</p><p>" ) ); + rx = QRegExp( u8( "\\n[ ]*\\.\\n" ) ); + l.replace( rx, u8( "</p><p>" ) ); + rx = QRegExp( u8( "\n " ) ); + l.replace( rx, u8( " " ) ); + rx = QRegExp( u8( "\n - (.*)(\n|$)" ) ); + rx.setMinimal( true ); + l.replace( rx, u8( "\n<li>\\1</li>\n" ) ); + l.replace( rx, u8( "\n<li>\\1</li>\n" ) ); + return QString( "<p>" ) + l + u8( "</p>" ); +} + +void PackageInfo::setPackage( entity::Package p ) +{ + kdDebug() << "PackageInfo::setPackage()" << endl; + // ho hum, probably XXX fix libapt-front? + setVersion( p.valid() ? p.anyVersion() : entity::Version(), false ); +} + +void PackageInfo::setVersion( entity::Version v, bool specific ) +{ + m_specificVersion = specific; + m_version = v.stable(); + if ( !m_version.valid() ) return; + kdDebug() << "PackageInfo::setVersion() (valid)" << endl; + m_section->setText( + labelFormat( i18n( "Section:" ), u8( v.section( u8( i18n( "Unknown" ) ) ) ) ) ); + m_maintainer->setText( + labelFormat( i18n( "Maintainer:" ), u8( v.maintainer( u8( i18n( "Unknown" ) ) ) ), + false ) ); + + notifyPostChange( 0 ); +} + +void PackageInfo::notifyPostRebuild( component::Base *b ) { + return notifyPostChange( b ); +} + +void PackageInfo::notifyPostChange( component::Base * ) +{ + if ( !m_version.valid() ) return; + entity::Version v = m_version; + entity::Package p = v.package(); + QString cv = i18n( "n/a" ), iv = i18n( "n/a" ), is = i18n( "n/a" ), status, action; + + if (p.valid()) { + entity::Version _cv = p.candidateVersion(); + entity::Version _iv = p.installedVersion(); + + if (_cv.valid()) { + cv = u8( _cv.versionString() ); + is = u8( _cv.installedSizeString() ); + } + + if (_iv.valid()) { + iv = _iv.versionString(); + } + } + + std::string unk = u8( i18n( "unknown" ) ); + /* m_status->setText( i18n( "<nobr>Currently " ) + colorify( + statusColor( p ), + u8( p.statusString( unk ) ) ) + + i18n( ", " ) + colorify( + actionColor( p ), + u8( p.actionString( unk ) ) ) + i18n( " + requested</nobr>" ) ); */ + m_status->setText( + labelFormat( i18n( "Status:" ), colorify( + statusColor( p ), + u8( p.statusString( u8( i18n( "Unknown" ) ) ) ) ) ) ); + m_change->setText( + labelFormat( i18n( "Requested change:" ), colorify( + actionColor( p ), + u8( p.actionString( u8( i18n( "Unknown" ) ) ) + ) ) ) ); + + m_candidateVer->setText( + m_specificVersion ? + labelFormat( i18n( "Version:" ), + v.versionString() + "(" + i18n( "candidate" ) + " " + cv + ")" ) + : labelFormat( i18n( "Candidate Version:" ), cv ) ); + m_installedVer->setText( + labelFormat( i18n( "Installed Version:" ), iv ) ); + m_installedSize->setText( + labelFormat( i18n( "Installed Size:" ), is ) ); +} + +} diff --git a/adept/adept/packageinfo.h b/adept/adept/packageinfo.h new file mode 100644 index 0000000..1a83c0d --- /dev/null +++ b/adept/adept/packageinfo.h @@ -0,0 +1,49 @@ +/* -*- C++ -*- adept/packageinfo.h + written by Peter Rockai <me@mornfall.net> */ + +#include <apt-front/cache/entity/package.h> +#include <apt-front/cache/cache.h> +#include <adept/packageinfoui.h> + +#ifndef EPT_PACKAGEINFO_H +#define EPT_PACKAGEINFO_H + +namespace adept { + +using namespace aptFront; + +class PackageInfo : public PackageInfoUi, public cache::Observer +{ + Q_OBJECT +public: + PackageInfo( QWidget *p, const char *n = 0 ); +public slots: + void setVersion( cache::entity::Version v, bool = true ); + void setPackage( cache::entity::Package v ); + void adjustFontSize( int ); +public: + void notifyPostChange( cache::component::Base * ); + void notifyPostRebuild( cache::component::Base * ); + void hideStatus(); +protected: + cache::entity::StableVersion m_version; + bool m_specificVersion; +}; + +inline QString labelFormat( const QString &what, + const QString &txt, bool nobr = true ) +{ + QString ret = "<b><nobr>" + what + "</nobr></b> " + (nobr ? "<nobr>" : "") + + txt + (nobr ? "</nobr>" : ""); + return ret; +} + +QColor actionColor( cache::entity::Package p ); +QColor statusColor( cache::entity::Package p ); + +QString formatLongDescription( QString in ); +QString colorify( QColor c, QString s ); + +} + +#endif diff --git a/adept/adept/packageinfoui.ui b/adept/adept/packageinfoui.ui new file mode 100644 index 0000000..d7d5dc5 --- /dev/null +++ b/adept/adept/packageinfoui.ui @@ -0,0 +1,180 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>PackageInfoUi</class> +<widget class="QWidget"> + <property name="name"> + <cstring>details</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>253</width> + <height>128</height> + </rect> + </property> + <property name="caption"> + <string>Form2</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>1</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>m_indent</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>16</width> + <height>5</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16</width> + <height>5</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="4" column="1"> + <property name="name"> + <cstring>m_maintainer</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>maintainer</string> + </property> + <property name="alignment"> + <set>AlignBottom</set> + </property> + </widget> + <widget class="QLabel" row="5" column="1"> + <property name="name"> + <cstring>m_candidateVer</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>candidate version</string> + </property> + </widget> + <widget class="QLabel" row="6" column="1"> + <property name="name"> + <cstring>m_installedVer</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>installed version</string> + </property> + </widget> + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>m_section</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>section</string> + </property> + </widget> + <widget class="QLabel" row="3" column="1"> + <property name="name"> + <cstring>m_installedSize</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>installed size</string> + </property> + </widget> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>m_status</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>status</string> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>m_change</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>change</string> + </property> + </widget> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/adept/adept/progress.cpp b/adept/adept/progress.cpp new file mode 100644 index 0000000..60a3bd3 --- /dev/null +++ b/adept/adept/progress.cpp @@ -0,0 +1,58 @@ +#include <kapplication.h> +#include <qcursor.h> +#include <kdebug.h> +#include <adept/progress.h> +#include <adept/utils.h> + +using namespace adept; + +Progress::Progress() + : m_pbar( 0 ), m_sbar( 0 ), m_busy( false ) +{ +} + +void Progress::Update () +{ + if (!m_sbar) + return; + if (!m_pbar) { + if (Percent) { + m_pbar = new KProgress( m_sbar ); + m_pbar->setMinimumWidth( 80 ); + m_pbar->setMaximumWidth( 120 ); + m_pbar->setTextEnabled( false ); + m_pbar->show(); + m_sbar->addWidget( m_pbar, 0, true ); + m_pbar->setTotalSteps( 100 ); + } + MajorChange = true; + } + if (MajorChange) { + if ( !m_busy ) { + QApplication::setOverrideCursor( QCursor( Qt::BusyCursor ) ); + m_busy = true; + } + m_sbar->message( u8( Op + "..." ) ); + } + if (CheckChange (0.05) == false) + return; + // kdDebug() << "Progress::Update()" << endl; + if (m_pbar) + m_pbar->setProgress( Percent ); + kapp->processEvents(); +} + +void Progress::Done () +{ + kdDebug() << "Progress::Done()" << endl; + + QApplication::restoreOverrideCursor(); + m_busy = false; + + if (m_sbar) + m_sbar->clear(); + delete m_pbar; + m_pbar = 0; +} + +Progress::~Progress() {} diff --git a/adept/adept/progress.h b/adept/adept/progress.h new file mode 100644 index 0000000..aef3d92 --- /dev/null +++ b/adept/adept/progress.h @@ -0,0 +1,30 @@ +/** -*- C++ -*- + @file adept/progress.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <kprogress.h> +#include <kstatusbar.h> +#include <apt-pkg/progress.h> + +#ifndef EPT_PROGRESS_H +#define EPT_PROGRESS_H + +namespace adept { + +class Progress : public OpProgress { +public: + Progress(); + virtual ~Progress(); + virtual void Update(); + virtual void Done(); + void setStatusBar( KStatusBar *b ) { m_sbar = b; } +protected: + KProgress *m_pbar; + KStatusBar *m_sbar; + bool m_busy; +}; + +} + +#endif diff --git a/adept/adept/quickfilter.cpp b/adept/adept/quickfilter.cpp new file mode 100644 index 0000000..2cb0577 --- /dev/null +++ b/adept/adept/quickfilter.cpp @@ -0,0 +1,79 @@ +#include <apt-front/predicate/combinators.h> +#include <apt-front/predicate/factory.h> +#include <qobjectlist.h> +#include <klocale.h> +#include <kdebug.h> +#include <klineedit.h> +#include <qcheckbox.h> + +#include "quickfilter.h" + +using namespace aptFront; +using namespace adept; + +QuickFilterWidget::QuickFilterWidget( QWidget *parent, const char *name ) + : QuickFilterUi( parent, name ) +{ + setFocusProxy( m_match ); + connect( m_match, SIGNAL( textChanged( const QString & ) ), + this, SLOT( textChanged( const QString & ) ) ); + /* connect( m_reset, SIGNAL( clicked() ), + this, SLOT( reset() ) ); */ + connect( m_match, SIGNAL( returnPressed() ), + this, SLOT( widgetsChanged() ) ); + connect( &timer, SIGNAL( timeout() ), + this, SLOT( widgetsChanged() ) ); + + QObjectList *chld = queryList( "QCheckBox" ); + QObjectListIt it( *chld ); + while( it.current() != 0 ) { + connect( it.current(), SIGNAL( toggled( bool ) ), + this, SLOT( widgetsChanged() ) ); + ++it; + } +} + +void QuickFilterWidget::mouseReleaseEvent( QMouseEvent *e ) { + m_match->setFocus(); + QuickFilterUi::mouseReleaseEvent( e ); +} + +void QuickFilterWidget::textChanged( const QString & ) +{ + kdDebug() << "QuickFilterWidget::textChanged" << endl; + timer.start( 1000, true ); +} + +QuickFilterWidget::Predicate QuickFilterWidget::predicate() +{ + typedef QuickFilter< entity::Package > F; + F f; int w = 0; + if ( m_name->isChecked() ) w |= F::Name; + if ( m_description->isChecked() ) w |= F::Description; + if ( m_maintainer->isChecked() ) w |= F::Maintainer; + + f.setMatch( u8( m_match->text() ) ); + f.setWhat( w ); + + return predicate::adapt< entity::Entity >( f ); +} + +static void blockedSet( QCheckBox *b, bool v ) { + b->blockSignals( true ); + b->setChecked( v ); + b->blockSignals( false ); +} + +void QuickFilterWidget::predicateChanged() { + typedef QuickFilter< entity::Package > F; + F f = downcast< F >( m_pred ); + m_match->blockSignals( true ); + m_match->setText( f.match() ); + m_match->blockSignals( false ); + int w = f.what(); + + blockedSet( m_name, w & F::Name ); + blockedSet( m_description, w & F::Description ); + blockedSet( m_maintainer, w & F::Maintainer ); +} + diff --git a/adept/adept/quickfilter.h b/adept/adept/quickfilter.h new file mode 100644 index 0000000..788c9da --- /dev/null +++ b/adept/adept/quickfilter.h @@ -0,0 +1,119 @@ +/** -*- C++ -*- + @file adept/quickfilter.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <klocale.h> +#include <qlayout.h> +#include <qtimer.h> + +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/entity/package.h> +#include <apt-front/predicate/factory.h> +#include <adept/quickfilterui.h> +#include <adept/filterlist.h> +#include <adept/lister.h> +#include <adept/utils.h> + +#ifndef EPT_QUICKFILTER_H +#define EPT_QUICKFILTER_H + +class KLineEdit; + +namespace adept { + +template< typename T > +struct QuickFilter : predicate::Implementation< T, QuickFilter< T > >, + InterfacingPredicate +{ + enum Type { Regex, Substring, Exact }; + enum What { Name = 0x1, Description = 0x2, Maintainer = 0x4 }; + + QuickFilter() + : m_type( Substring ), m_match( "" ), m_what( Name | Description ) { + setupPredicate(); + } + + void setupPredicate() { + predicate::ArgumentList l; + l.push_back( m_match ); + predicate::Predicate< T > a = not predicate::True< T >(); + if ( m_what & Name ) a = a or predicate::Factory< T >::name( m_match ); + if ( m_what & Description ) + a = a or predicate::Factory< T >::description( m_match ); + if ( m_what & Maintainer ) + a = a or predicate::Factory< T >::maintainer( m_match ); + m_op = a; + /* m_op = predicate::map( + predicate::predicate( predicate::Factory< T >::description( "" ) + or predicate::Factory< T >::name( "" ) + or predicate::Factory< T + >::maintainer( "" ) ), l ); */ + } + + std::string summary() const { + return u8( i18n( "Search: " ) ) + "\"" + m_match + "\""; + } + + void parseArguments( const predicate::ArgumentList & ) {} + + bool operator==( const QuickFilter &o ) const { + return o.m_type == m_type && o.m_match == m_match; + } + + std::string typeString() const { + if (m_type == Regex) return "Regular Expression"; + if (m_type == Substring) return "Substring"; + if (m_type == Exact) return "Exact Match"; + } + + bool operator()( const T &p ) { + return m_op( p ); + } + + std::string match() const { + return m_match; + } + + void setMatch( const std::string &s ) { + m_match = s; + setupPredicate(); + } + + void setWhat( int w ) { + m_what = w; + setupPredicate(); + } + + int what() { return m_what; } + + virtual void reset() { + m_match = ""; + setupPredicate(); + } + +protected: + Type m_type; + std::string m_match; + int m_what; + predicate::Predicate< T > m_op; +}; + +class QuickFilterWidget : public QuickFilterUi +{ + Q_OBJECT +public: + QuickFilterWidget( QWidget *parent, const char *name = 0 ); + virtual Predicate predicate(); +public slots: + void predicateChanged(); +protected slots: + void textChanged( const QString & ); +protected: + void mouseReleaseEvent( QMouseEvent *e ); + QTimer timer; +}; + +} + +#endif diff --git a/adept/adept/quickfilterui.ui b/adept/adept/quickfilterui.ui new file mode 100644 index 0000000..d45c154 --- /dev/null +++ b/adept/adept/quickfilterui.ui @@ -0,0 +1,130 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::QuickFilterUi</class> +<widget class="adept::PredicateInterface"> + <property name="name"> + <cstring>QuickFilterUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>805</width> + <height>31</height> + </rect> + </property> + <property name="caption"> + <string>QuickFilterUi</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>2</number> + </property> + <property name="spacing"> + <number>1</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_title</cstring> + </property> + <property name="text"> + <string><b>Search:&nbsp;</b></string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_match</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>200</width> + <height>0</height> + </size> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Match: </string> + </property> + <property name="textFormat"> + <enum>AutoText</enum> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_name</cstring> + </property> + <property name="text"> + <string>package name,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_description</cstring> + </property> + <property name="text"> + <string>description,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_maintainer</cstring> + </property> + <property name="text"> + <string>maintainer.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>41</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> +</widget> +<includes> + <include location="global" impldecl="in declaration">adept/filterlist.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/adept/adept/sourceseditor.cpp b/adept/adept/sourceseditor.cpp new file mode 100644 index 0000000..3b04cf6 --- /dev/null +++ b/adept/adept/sourceseditor.cpp @@ -0,0 +1,165 @@ +#include <fstream> +#include <iostream> + +#include <qpushbutton.h> +#include <qlineedit.h> +#include <qpainter.h> + +#include <kdebug.h> +#include <kpopupmenu.h> +#include <klocale.h> + +#include "sourceseditor.h" +#include <adept/utils.h> + +using namespace aptFront; +using namespace adept; + +SourcesEditor::SourcesEditor( std::string f, QWidget *p, const char *n ) + : SourcesEditorUi( p, n ), m_filename( f ) +{ + m_list->setSorting( -1 ); + m_list->setAcceptDrops( true ); + connect( m_close, SIGNAL( clicked() ), + this, SIGNAL( close() ) ); + connect( m_apply, SIGNAL( clicked() ), + this, SLOT( save() ) ); + connect( m_reset, SIGNAL( clicked() ), + this, SLOT( reset() ) ); + + connect( m_list, SIGNAL( contextMenuRequested( + QListViewItem *, const QPoint &, int) ), + this, SLOT( contextMenu( QListViewItem *, const QPoint & ) ) ); + + connect( m_newAdd, SIGNAL( clicked() ), + this, SLOT( newAdd() ) ); + + reset(); +} + +void SourcesEditor::newAdd() +{ + Sources::Entry e( true, Sources::Entry::Binary ); + std::string s = m_newLine->text(); + std::istringstream i( s ); + i >> e; + new EntryItem( e, m_list ); + m_newLine->setText( u8( "" ) ); +} + +void SourcesEditor::contextMenu( QListViewItem *, const QPoint &pt ) { + EntryItem *s = dynamic_cast< EntryItem * >( m_list->selectedItem() ); + if (!s) return; + KPopupMenu *m = new KPopupMenu (this); + m->insertItem( s->entry().enabled() ? i18n( "Disable" ) : i18n( "Enable" ), 0 ); + m->insertItem( i18n( "Clone" ), 1 ); + m->insertItem( i18n( "Remove" ), 2 ); + connect( m, SIGNAL( activated( int ) ), + this, SLOT( contextMenuActivated( int ) ) ); + m->exec( pt ); + delete m; +} + +void SourcesEditor::contextMenuActivated( int i ) { + EntryItem *s = dynamic_cast< EntryItem * >( m_list->selectedItem() ); + Sources::Entry e = s->entry(); + if (i == 0) { + e.setEnabled( !e.enabled() ); + s->setEntry( e ); + } + if (i == 2) + delete s; + if (i == 1) + new EntryItem( e, m_list, s ); +} + +void SourcesEditor::reset() { + std::ifstream in( m_filename.c_str() ); + m_sources.clear(); + in >> m_sources; + utils::Range< Sources::Entry > r = m_sources.entries(); + EntryItem *last = 0; + m_list->clear(); + while( r != r.end() ) { + last = last ? new EntryItem( *r, m_list, last ) : + new EntryItem( *r, m_list ); + ++ r; + } +} + +void SourcesEditor::save() { + m_sources.clear(); + EntryItem *i = dynamic_cast< EntryItem * >( m_list->firstChild() ); + while (i) { + m_sources.add( i->entry() ); + i = dynamic_cast< EntryItem * >( i->nextSibling() ); + } + std::ofstream out( m_filename.c_str() ); + out << m_sources; + std::cerr << "--" << m_sources << "--" << std::endl; + out.close(); + reset(); // re-parse +} + +/* void SourcesEditor::toggleSelectionEnabled() +{ + EntryItem *s = dynamic_cast< EntryItem * >( m_list->selectedItem() ); + if (s) { + Sources::Entry e = s->entry(); + e.setEnabled( !e.enabled() ); + s->setEntry( e ); + updateActions(); + } + } */ + +QString EntryItem::text( int c ) const { + if (entry().type() == Sources::Entry::Comment) { + if (c == 0) + if (entry().comment() == "") + return u8( "" ); + else + return entry().typeString(); + if (c == 1) + return entry().comment(); + return u8( "" ); + } + + if (c == 0) return entry().typeString(); + if (c == 1) return entry().url(); + if (c == 2) return entry().distribution(); + if (c == 3) return entry().components(); + return u8( "" ); +} + +void EntryItem::setText( int c, const QString &_s ) +{ + kdDebug() << "setText on column " << c << endl; + Sources::Entry e = entry(); + std::string s; + s = _s.local8Bit(); + if (c == 0) e.setTypeString( s ); + if (c == 1) + if (entry().type() == Sources::Entry::Comment) + e.setComment( s ); + else + e.setUrl( s ); + if (c == 2) e.setDistribution( s ); + if (c == 3) e.setComponents( s ); + setEntry( e ); + KListViewItem::setText( c, _s ); // stop qlistview from looping infinitely +} + +void EntryItem::paintCell (QPainter *p, const QColorGroup &cg, + int column, int width, int alignment ) +{ + QColorGroup _cg( cg ); + QColor c = _cg.text(); + QPixmap pm( width, height() ); + QPainter _p( &pm ); + if (!entry().enabled()) + c = Qt::gray; + _cg.setColor( QColorGroup::Text, c ); + KListViewItem::paintCell( &_p, _cg, column, width, AlignTop ); + p->drawPixmap( 0, 0, pm ); +} + diff --git a/adept/adept/sourceseditor.h b/adept/adept/sourceseditor.h new file mode 100644 index 0000000..32b474f --- /dev/null +++ b/adept/adept/sourceseditor.h @@ -0,0 +1,63 @@ +/** -*- C++ -*- + @file adept/sourceseditor.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <apt-front/sources.h> +#include <adept/sourceseditorui.h> +#include <klistview.h> + +namespace adept { + +using namespace aptFront; + +class SourcesEditor : public SourcesEditorUi +{ + Q_OBJECT +public: + SourcesEditor( std::string f, QWidget *p = 0, const char *n = 0 ); +public slots: + void save(); + void reset(); +protected slots: + void contextMenu( QListViewItem *, const QPoint & ); + void contextMenuActivated( int ); + void newAdd(); +signals: + void close(); +protected: + aptFront::Sources m_sources; + std::string m_filename; +}; + +class EntryItem : public KListViewItem { +public: + Sources::Entry entry() const { + return m_entry; + } + void setEntry( const Sources::Entry &e ) { + m_entry = e; + } + EntryItem( Sources::Entry e, KListView *v, EntryItem *prev ) + : KListViewItem( v, prev ), m_entry( e ) { + init(); + } + EntryItem( Sources::Entry e, KListView *v ) + : KListViewItem( v ), m_entry( e ) { + init(); + } + void init() { + setRenameEnabled( 0, false ); + setRenameEnabled( 1, true ); + setRenameEnabled( 2, true ); + setRenameEnabled( 3, true ); + } + QString text( int c ) const; + void setText( int c, const QString &s ); + virtual void paintCell (QPainter *p, const QColorGroup &cg, + int column, int width, int alignment); +protected: + Sources::Entry m_entry; +}; + +} diff --git a/adept/adept/sourceseditorui.ui b/adept/adept/sourceseditorui.ui new file mode 100644 index 0000000..43397d3 --- /dev/null +++ b/adept/adept/sourceseditorui.ui @@ -0,0 +1,173 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::SourcesEditorUi</class> +<widget class="QWidget"> + <property name="name"> + <cstring>adept::SourcesEditorUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>683</width> + <height>442</height> + </rect> + </property> + <property name="caption"> + <string>adept::SourcesEditorUi</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KListView"> + <column> + <property name="text"> + <string>Type</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>false</bool> + </property> + </column> + <column> + <property name="text"> + <string>URL</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Distribution</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Components</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>m_list</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="resizeMode"> + <enum>AllColumns</enum> + </property> + <property name="fullWidth"> + <bool>true</bool> + </property> + <property name="itemsMovable"> + <bool>true</bool> + </property> + <property name="itemsRenameable"> + <bool>true</bool> + </property> + <property name="dragEnabled"> + <bool>true</bool> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>New Repository:</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_newLine</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Write or paste a normal sources.list line here to add it to your sources</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_newAdd</cstring> + </property> + <property name="text"> + <string>Add</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout13</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_reset</cstring> + </property> + <property name="text"> + <string>Reset</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_apply</cstring> + </property> + <property name="text"> + <string>Apply</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_close</cstring> + </property> + <property name="text"> + <string>Close</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<tabstops> + <tabstop>m_newLine</tabstop> + <tabstop>m_newAdd</tabstop> + <tabstop>m_reset</tabstop> + <tabstop>m_apply</tabstop> + <tabstop>m_close</tabstop> + <tabstop>m_list</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klistview.h</includehint> +</includehints> +</UI> diff --git a/adept/adept/statefilter.cpp b/adept/adept/statefilter.cpp new file mode 100644 index 0000000..45ee470 --- /dev/null +++ b/adept/adept/statefilter.cpp @@ -0,0 +1,60 @@ +#include <apt-front/predicate/combinators.h> +#include <apt-front/predicate/factory.h> +#include <klocale.h> +#include <kdebug.h> +#include <qcheckbox.h> +#include <qobjectlist.h> +#include "statefilter.h" + +using namespace aptFront; +using namespace adept; + +StateFilterWidget::StateFilterWidget( QWidget *parent, const char *name ) + : StateFilterUi( parent, name ) +{ + QObjectList *chld = queryList( "QCheckBox" ); + QObjectListIt it( *chld ); + while( it.current() != 0 ) { + connect( it.current(), SIGNAL( toggled( bool ) ), + this, SLOT( widgetsChanged() ) ); + ++it; + } +} + +StateFilterWidget::Predicate StateFilterWidget::predicate() +{ + typedef StateFilter< entity::Package > F; + unsigned mask = 0; + if (m_installed->isChecked()) mask |= F::Installed; + if (m_notInstalled->isChecked()) mask |= F::NotInstalled; + if (m_upgradable->isChecked()) mask |= F::Upgradable; + if (m_keep->isChecked()) mask |= F::Keep; + if (m_install->isChecked()) mask |= F::Install; + if (m_remove->isChecked()) mask |= F::Remove; + if (m_upgrade->isChecked()) mask |= F::Upgrade; + + StateFilter< entity::Package > f; + f.setMask( mask ); + return predicate::adapt< entity::Entity >( f ); +} + +static void blockedSet( QCheckBox *b, bool v ) { + b->blockSignals( true ); + b->setChecked( v ); + b->blockSignals( false ); +} + +void StateFilterWidget::predicateChanged() +{ + typedef StateFilter< entity::Package > F; + F f = downcast< F >( m_pred ); + unsigned mask = f.mask(); + blockedSet( m_installed, mask & F::Installed ); + blockedSet( m_notInstalled, mask & F::NotInstalled ); + blockedSet( m_upgradable, mask & F::Upgradable ); + blockedSet( m_keep, mask & F::Keep ); + blockedSet( m_install, mask & F::Install ); + blockedSet( m_upgrade, mask & F::Upgrade ); + blockedSet( m_remove, mask & F::Remove ); +} + diff --git a/adept/adept/statefilter.h b/adept/adept/statefilter.h new file mode 100644 index 0000000..570edb1 --- /dev/null +++ b/adept/adept/statefilter.h @@ -0,0 +1,144 @@ +/** -*- C++ -*- + @file adept/filterwidgets.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/entity/package.h> +#include <apt-front/predicate/factory.h> + +#include <adept/statefilterui.h> +#include <adept/filterlist.h> +#include <adept/lister.h> + +#include <klocale.h> +#include <qlayout.h> +#include <iostream> +#include <sstream> + +#ifndef EPT_STATEFILTER_H +#define EPT_STATEFILTER_H + +class KLineEdit; + +namespace adept { + +template< typename T > +struct StateFilter : predicate::Implementation< T, StateFilter< T > >, + InterfacingPredicate +{ + enum Mask { Installed = 1 << 0, + NotInstalled = 1 << 1, + Upgradable = 1 << 2, + Install = 1 << 3, + Remove = 1 << 4, + Keep = 1 << 5, + Upgrade = 1 << 6 }; + + StateFilter() + : m_mask( 0xff ) { + setupPredicate(); + } + + void setupPredicate() { + predicate::Predicate< T > + p0 = not predicate::True< T >(), + p1 = not predicate::True< T >(); + if (m_mask & Installed) + p0 = p0 or (predicate::Factory< T >::member( &T::isInstalled ) + and not predicate::Factory< T >::member( &T::isUpgradable ) ); + if (m_mask & NotInstalled) + p0 = p0 or not predicate::Factory< T >::member( &T::isInstalled ); + if (m_mask & Upgradable) + p0 = p0 or predicate::Factory< T >::member( &T::isUpgradable ); + + if (m_mask & Install) + p1 = p1 or predicate::Factory< T >::member( &T::markedNewInstall ); + if (m_mask & Remove) + p1 = p1 or predicate::Factory< T >::member( &T::markedRemove ); + if (m_mask & Keep) + p1 = p1 or predicate::Factory< T >::member( &T::markedKeep ); + if (m_mask & Upgrade) + p1 = p1 or predicate::Factory< T >::member( &T::markedUpgrade ); + + m_op = p0 and p1; + } + + std::string summary() const { + std::ostringstream s; + std::vector< std::string > r; + s << "State filter: "; + if (m_mask & Installed && m_mask & NotInstalled && m_mask & Upgradable) + r.push_back( "Any State" ); + else { + if (m_mask & Installed) + r.push_back( i18n( "Installed" ) ); + if (m_mask & NotInstalled) + r.push_back( i18n( "Not Installed" ) ); + if (m_mask & Upgradable) + r.push_back( i18n( "Upgradable" ) ); + } + std::copy( r.begin(), r.end(), + std::ostream_iterator< std::string >( s, " " ) ); + s << "; "; + r.clear(); + if (m_mask & Install && m_mask & Remove + && m_mask & Keep && m_mask & Upgrade) + r.push_back( i18n( "Any Action" ) ); + else { + if (m_mask & Install) + r.push_back( i18n( "Install" ) ); + if (m_mask & Remove) + r.push_back( i18n( "Remove" ) ); + if (m_mask & Keep) + r.push_back( i18n( "Keep" ) ); + if (m_mask & Upgrade) + r.push_back( i18n( "Upgrade" ) ); + } + std::copy( r.begin(), r.end(), + std::ostream_iterator< std::string >( s, " " ) ); + return s.str(); + } + + unsigned mask() const { + return m_mask; + } + + void setMask( unsigned m ) { + m_mask = m; + setupPredicate(); + } + + void parseArguments( const predicate::ArgumentList & ) {} + + bool operator==( const StateFilter &o ) const { + return o.m_op == m_op; + } + + bool operator()( const T &p ) { + return m_op( p ); + } + + virtual void reset() { + m_mask = 0xff; + setupPredicate(); + } + +protected: + unsigned m_mask; + predicate::Predicate< T > m_op; +}; + +class StateFilterWidget : public StateFilterUi +{ + Q_OBJECT +public: + StateFilterWidget( QWidget *parent, const char *name = 0 ); + virtual Predicate predicate(); +public slots: + void predicateChanged(); +}; + +} + +#endif diff --git a/adept/adept/statefilterui.ui b/adept/adept/statefilterui.ui new file mode 100644 index 0000000..1ef19e0 --- /dev/null +++ b/adept/adept/statefilterui.ui @@ -0,0 +1,166 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::StateFilterUi</class> +<widget class="adept::PredicateInterface"> + <property name="name"> + <cstring>StateFilterUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>574</width> + <height>55</height> + </rect> + </property> + <property name="caption"> + <string>StateFilterUi</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>2</number> + </property> + <property name="spacing"> + <number>1</number> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>m_title</cstring> + </property> + <property name="text"> + <string>Show: </string> + </property> + <property name="alignment"> + <set>AlignVCenter</set> + </property> + </widget> + <widget class="QLayoutWidget" row="0" column="1"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_notInstalled</cstring> + </property> + <property name="text"> + <string>not installed,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_installed</cstring> + </property> + <property name="text"> + <string>installed,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_upgradable</cstring> + </property> + <property name="text"> + <string>upgradable packages,</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>195</width> + <height>16</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QLayoutWidget" row="1" column="1"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_keep</cstring> + </property> + <property name="text"> + <string>no changes,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_install</cstring> + </property> + <property name="text"> + <string>install,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_remove</cstring> + </property> + <property name="text"> + <string>removal,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_upgrade</cstring> + </property> + <property name="text"> + <string>upgrade requested.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>195</width> + <height>16</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>with: </string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + </grid> +</widget> +<includes> + <include location="global" impldecl="in declaration">adept/filterlist.h</include> +</includes> +<layoutdefaults spacing="3" margin="11"/> +</UI> diff --git a/adept/adept/tagchooser.cpp b/adept/adept/tagchooser.cpp new file mode 100644 index 0000000..d596133 --- /dev/null +++ b/adept/adept/tagchooser.cpp @@ -0,0 +1,147 @@ +#include <klocale.h> +#include <qdragobject.h> + +#include <ept/debtags/vocabulary.h> +#include <apt-front/cache/component/packagetags.h> +#include <adept/tagchooser.h> +#include <adept/taglist.h> +#include <adept/utils.h> +#include <wibble/operators.h> + +using namespace adept; + +FacetItem::FacetItem( TagChooser *t ) + : KListViewItem( t ) +{ +} + +void FacetItem::removeTag( TagItem::Tag t ) { + // kdDebug() << "removing tag " << t.fullname() << endl; + for ( QListViewItem *n, *i = firstChild(); i != 0; i = n ) { + n = i->nextSibling(); + if ( dynamic_cast< TagItem * >( i )->tag() == t ) + delete i; + } +} + +TagItem::TagItem( FacetItem *p ) + : KListViewItem( p ), m_toplevel( false ) +{ +} + +TagItem::TagItem( TagChooser *l ) + : KListViewItem( l ), m_toplevel( true ) +{ +} + +QString TagItem::text( int c ) const +{ + if (c != 0) return u8( "" ); + return QString( "[" ) + m_tag.name() + "] " + m_tag.shortDescription(""); +} + +TagChooser::TagChooser( QWidget *p, const char *n ) + : KListView( p, n ) +{ + observeComponent< cache::component::PackageTags >(); + // addColumn( " ", 20 ); + setRootIsDecorated( true ); + addColumn( i18n( "Available Tags" ) ); + setResizeMode( LastColumn ); + setDragEnabled( true ); + setAcceptDrops( true ); + viewport()->setAcceptDrops( false ); + // kdDebug() << "TagChooser: tags set" << endl; +} + +void TagChooser::openToplevel() { + QListViewItem *i; + for ( i = firstChild(); i != 0; i = i->nextSibling() ) { + i->setOpen( true ); + } +} + +QDragObject *TagChooser::dragObject() +{ + TagItem *sel = dynamic_cast< TagItem * >( selectedItem() ); + if (sel) + return new QTextDrag( sel->tag().fullname(), this ); + return 0; +} + +void TagChooser::dragEnterEvent( QDragEnterEvent *e ) +{ + // hmmmmm :-) + kdDebug() << "TagChooser::dragEnterEvent" << endl; + e->accept( dynamic_cast< TagList * >( e->source() ) + && QTextDrag::canDecode( e ) ); + kdDebug() << dynamic_cast< TagList * >( e->source() ) + << "; can decode " << QTextDrag::canDecode( e ) << endl; +} + +void TagChooser::dropEvent( QDropEvent* e ) +{ + using namespace wibble::operators; + TagList *tl = dynamic_cast< TagList * >( e->source() ); + QString tag; + QTextDrag::decode( e, tag ); + tl->setTags( tl->tags() - cache::Global::get().tags().tagByName( + static_cast< const char * >( tag.local8Bit() ) ) ); +} + +QString FacetItem::text( int column ) const +{ + if ( column == 0 ) + return QString( "[" ) + m_facet.name() + "] " + m_facet.shortDescription( "" ); + return u8( "" ); +} + +static bool drop( TagChooser::Tag t ) { + if ( t.facet().name() == "special" ) + return true; + if ( t.name() == "TODO" ) + return true; + return false; +} + +void TagChooser::setTags( Tag::Set s ) +{ + using namespace wibble::operators; + std::set<Tag> remove = m_tags - s; + std::set<Tag> add = s - m_tags; + m_tags = s; + Tag::Set::iterator i; + + for ( i = add.begin(); i != add.end(); ++i ) { + + if ( drop( *i ) ) + continue; + + FacetItem *fi = m_facets[ i->facet() ]; + if ( fi == 0 ) { + fi = m_facets[ i->facet() ] = new FacetItem( this ); + fi->setFacet( i->facet() ); + } + + TagItem *ti = new TagItem( fi ); + ti->setTag( *i ); + } + + for ( i = remove.begin(); i != remove.end(); ++i ) { + + if ( drop( *i ) ) + continue; + + FacetItem *fi = m_facets[ i->facet() ]; + fi->removeTag( *i ); + if ( fi->childCount() == 0 ) { + m_facets[ i->facet() ] = 0; + delete fi; + } + } + +} + +void TagChooser::notifyPreRebuild( cache::component::Base *b ) { + setTags( Tag::Set() ); +} diff --git a/adept/adept/tagchooser.h b/adept/adept/tagchooser.h new file mode 100644 index 0000000..f6c6e2e --- /dev/null +++ b/adept/adept/tagchooser.h @@ -0,0 +1,83 @@ +/* -*- C++ -*- file adept/tagchooser.h + written by Peter Rockai <me@mornfall.net> */ + +#include <kdebug.h> +#include <qlayout.h> + +#include <apt-front/utils/range.h> +#include <apt-front/cache/cache.h> + +#include <ept/debtags/tag.h> + +#include <adept/extendablelist.h> + +#ifndef EPT_TAGCHOOSER_H +#define EPT_TAGCHOOSER_H + +namespace adept { + +using namespace aptFront; + +class FacetItem; +class FacetExtender; +class TagChooser; + +class TagItem : public KListViewItem { +public: + typedef ept::debtags::Tag Tag; + virtual QString text( int ) const; + TagItem( TagChooser *t ); + TagItem( FacetItem *t ); + void setTag( Tag t ) { m_tag = t; } + Tag tag() { return m_tag; } +protected: + bool m_toplevel; + Tag m_tag; +}; + +class FacetItem : public KListViewItem +{ +public: + typedef ept::debtags::Facet Facet; + virtual QString text( int ) const; + FacetItem( TagChooser *t ); + void setFacet( Facet f ) { m_facet = f; } + void removeTag( TagItem::Tag ); +protected: + Facet m_facet; +}; + +class TagChooser : public KListView, public cache::Observer // ExtendableList +{ + Q_OBJECT +public: + typedef ept::debtags::Tag Tag; + typedef ept::debtags::Facet Facet; + TagChooser( QWidget *p = 0, const char *n = 0 ); + virtual void notifyPreRebuild( cache::component::Base * ); +public slots: + virtual void setTags( TagChooser::Tag::Set ); + void setTitle( QString s ) { + setColumnText( 0, s ); + } + void openToplevel(); + +protected: + virtual void dragEnterEvent( QDragEnterEvent *e ); + virtual void dropEvent( QDropEvent* e ); + virtual void contentsDragEnterEvent( QDragEnterEvent *e ) { + kdDebug() << "TagChooser::contentsDragEnterEvent" << endl; + dragEnterEvent( e ); + } + virtual void contentsDropEvent( QDropEvent *e ) { + kdDebug() << "TagChooser::contentsDropEvent" << endl; + dropEvent( e ); + } + virtual QDragObject *dragObject(); + Tag::Set m_tags; + std::map< Facet, FacetItem * > m_facets; +}; + +} + +#endif diff --git a/adept/adept/tagfilter.cpp b/adept/adept/tagfilter.cpp new file mode 100644 index 0000000..fb17f8c --- /dev/null +++ b/adept/adept/tagfilter.cpp @@ -0,0 +1,67 @@ +/* -*- C++ -*- libapt/tagfilter.h + written by Peter Rockai <me@mornfall.net> */ + +#include <qpopupmenu.h> +#include <qpushbutton.h> +#include <qtoolbutton.h> + +#include <adept/tagfilter.h> +#include <adept/taglist.h> + +using namespace adept; + +TagFilterWidget::TagFilterWidget( QWidget *w, const char *n ) + : TagFilterUi( w, n ) +{ + m_wanted->setName( i18n( "Tags I Want (drop tags here)" ) ); + m_unwanted->setName( i18n( "Tags I Do Not Want (drop tags here)" ) ); + + connect( m_wanted, SIGNAL( tagsChanged( TagList::Tag::Set ) ), + this, SLOT( wantedChanged() ) ); + connect( m_unwanted, SIGNAL( tagsChanged( TagList::Tag::Set ) ), + this, SLOT( unwantedChanged() ) ); +} + +TagFilterWidget::Predicate TagFilterWidget::predicate() +{ + TagFilter< entity::Package > f; + f.setWanted( m_wanted->tags() ); + f.setUnwanted( m_unwanted->tags() ); + return predicate::adapt< entity::Entity >( f ); +} + +static void setTagsBlocking( TagList *l, TagList::Tag::Set s ) { + l->blockSignals( true ); + l->setTags( s ); + l->blockSignals( false ); +} + +void TagFilterWidget::predicateChanged() +{ + typedef TagFilter< entity::Package > F; + F f = downcast< F >( m_pred ); + setTagsBlocking( m_wanted, f.wanted() ); + setTagsBlocking( m_unwanted, f.unwanted() ); + if ( item() && item()->list() ) { + setupColors(); + item()->list()->delayedUpdateExtenders(); + } +} + +void TagFilterWidget::wantedChanged() +{ + using namespace wibble::operators; + setTagsBlocking( m_unwanted, m_unwanted->tags() - m_wanted->tags() ); + setupColors(); + widgetsChanged(); + item()->list()->delayedUpdateExtenders(); +} + +void TagFilterWidget::unwantedChanged() +{ + using namespace wibble::operators; + setTagsBlocking( m_wanted, m_wanted->tags() - m_unwanted->tags() ); + setupColors(); + widgetsChanged(); + item()->list()->delayedUpdateExtenders(); +} diff --git a/adept/adept/tagfilter.h b/adept/adept/tagfilter.h new file mode 100644 index 0000000..5ff8e47 --- /dev/null +++ b/adept/adept/tagfilter.h @@ -0,0 +1,110 @@ +/* -*- C++ -*- adept/tagfilter.h + written by Peter Rockai <me@mornfall.net> */ + +#include <klocale.h> +#include <qlayout.h> +#include <qtimer.h> +#include <qpoint.h> + +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/entity/package.h> +#include <apt-front/predicate/factory.h> + +#include <adept/quickfilterui.h> +#include <adept/filterlist.h> +#include <adept/lister.h> +#include <adept/taglist.h> +#include <adept/tagfilterui.h> +#include <adept/utils.h> + +#ifndef EPT_TAGFILTER_H +#define EPT_TAGFILTER_H + +namespace adept { + +template< typename T > +struct TagFilter : predicate::Implementation< T, TagFilter< T > >, + InterfacingPredicate, cache::Observer +{ + typedef ept::debtags::Tag Tag; + + TagFilter() { + setupPredicate(); + observeComponent< cache::component::PackageTags >(); + } + + void setupPredicate() { + Cache &cache = cache::Global::get(); // FIXME? + m_op = predicate::Factory< T >::tagSet( m_wanted ); + for (Tag::Set::iterator i = m_unwanted.begin(); i != m_unwanted.end(); ++i ) { + m_op = m_op and not predicate::Factory< T >::tag( *i ); + } + } + + std::string summary() const { + return u8( i18n( "Tag Filter" ) ); + } + + void parseArguments( const predicate::ArgumentList & ) {} + + bool operator==( const TagFilter &o ) const { + return o.m_wanted == m_wanted && o.m_unwanted == m_unwanted; + } + + bool operator()( const T &p ) { + return m_op( p ); + } + + void setWanted( Tag::Set t ) { + m_wanted = t; + setupPredicate(); + } + + void setUnwanted( Tag::Set t ) { + m_unwanted = t; + setupPredicate(); + } + + Tag::Set wanted() const { return m_wanted; } + Tag::Set unwanted() const { return m_unwanted; } + + void notifyPreRebuild( cache::component::Base * ) { + kdDebug() << "TagFilter pre-rebuild" << endl; + m_unwanted.clear(); m_wanted.clear(); + } + + void notifyPostRebuild( cache::component::Base * ) { + Cache &c = cache::Global::get( m_cache ); + setupPredicate(); + } + + virtual void reset() { + m_wanted.clear(); + m_unwanted.clear(); + setupPredicate(); + } + +protected: + predicate::Predicate< T > m_op; + Tag::Set m_wanted; + Tag::Set m_unwanted; +}; + +class TagFilterWidget : public TagFilterUi +{ + Q_OBJECT +public: + TagFilterWidget( QWidget *p, const char *n ); + virtual Predicate predicate(); +public slots: + void predicateChanged(); + void wantedChanged(); + void unwantedChanged(); +protected: + TagList *m_addingTo; + std::vector< ept::debtags::Tag > m_tagMenuMap; +}; + +} + +#endif diff --git a/adept/adept/tagfilterui.ui b/adept/adept/tagfilterui.ui new file mode 100644 index 0000000..1f78b8a --- /dev/null +++ b/adept/adept/tagfilterui.ui @@ -0,0 +1,95 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::TagFilterUi</class> +<widget class="adept::PredicateInterface"> + <property name="name"> + <cstring>TagFilterUi</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>627</width> + <height>130</height> + </rect> + </property> + <property name="caption"> + <string>Form1</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>2</number> + </property> + <property name="spacing"> + <number>2</number> + </property> + <widget class="adept::TagList"> + <property name="name"> + <cstring>m_wanted</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>90</height> + </size> + </property> + </widget> + <widget class="adept::TagList"> + <property name="name"> + <cstring>m_unwanted</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </hbox> +</widget> +<customwidgets> + <customwidget> + <class>adept::TagList</class> + <header location="global">adept/taglist.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</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="PNG" length="1003">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082</data> + </image> +</images> +<includes> + <include location="global" impldecl="in declaration">adept/filterlist.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>adept/taglist.h</includehint> +</includehints> +</UI> diff --git a/adept/adept/taglist.cpp b/adept/adept/taglist.cpp new file mode 100644 index 0000000..c27d74f --- /dev/null +++ b/adept/adept/taglist.cpp @@ -0,0 +1,138 @@ +/* -*- C++ -*- adept/taglist.cpp + written by Peter Rockai <me@mornfall.net> */ + +#include <qlabel.h> +#include <qtimer.h> +#include <kdebug.h> +#include <qdragobject.h> +#include <qevent.h> +#include <klocale.h> + +#include <apt-front/cache/cache.h> +#include <ept/debtags/vocabulary.h> +#include <adept/taglist.h> +#include <adept/utils.h> +#include <wibble/operators.h> + +using namespace adept; + +TagLabel::TagLabel( Tag t, TagList *l, QWidget *p, const char *n ) + : QHBox( p, n ), m_tag( t ), m_list( l ) +{ + if ( t == Tag() ) { + m_description = new QLabel( QString( " " ) + i18n( "[none]" ), this ); + } else { + m_remove = new QLabel( this ); + m_remove->setPixmap( SmallIcon( u8( "cancel" ) ) ); + m_remove->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + m_description = new QLabel( QString( " [" ) + t.fullname( "n/a" ) + "] " + + t.shortDescription( "n/a" ), this ); + } +} + +void TagLabel::mouseReleaseEvent( QMouseEvent *e ) { + using namespace wibble::operators; + if ( e->button() == Qt::LeftButton && + dynamic_cast< QLabel * >( childAt( e->pos() ) ) == m_remove ) + m_list->setTags( m_list->tags() - m_tag ); +} + +TagList::TagList( QWidget *p, const char *n ) + : QVBox( p, n ) +{ + m_name = new QLabel( this ); + m_tagBox = new QVBox( this ); + m_tagBox->setFrameShape( QFrame::Panel ); + m_tagBox->setFrameShadow( QFrame::Sunken ); + m_updateScheduled = false; + setAcceptDrops( true ); + scheduleUpdateList(); + m_tagSpacer = new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding ); +} + +void TagList::setTags( Tag::Set t ) +{ + m_tags = t; + scheduleUpdateList(); + emit tagsChanged( m_tags ); +} + +void TagList::addTag( Tag t ) +{ + using namespace wibble::operators; + if ( t == Tag() ) + return; + m_tags |= t; + scheduleUpdateList(); + emit tagsChanged( m_tags ); +} + +void TagList::setName( QString n ) +{ + m_name->setText( n ); +} + +void TagList::scheduleUpdateList() +{ + if (! m_updateScheduled) { + kdDebug() << "TagList: scheduling update" << endl; + QTimer::singleShot( 0, this, SLOT( updateList() ) ); + m_updateScheduled = true; + } +} + +void TagList::updateList() +{ + kdDebug() << "TagList (" + m_name->text() + "): updating list" << endl; + clearList(); + if ( m_tags.empty() ) { + appendLabel( new TagLabel( Tag(), this, m_tagBox ) ); + } else { + for ( Tag::Set::iterator i = m_tags.begin(); i != m_tags.end(); ++i ) { + appendLabel( new TagLabel( *i, this, m_tagBox ) ); + } + } + m_tagBox->layout()->addItem( m_tagSpacer ); + update(); + parentWidget()->adjustSize(); + m_updateScheduled = false; +} + +void TagList::appendLabel( TagLabel *l ) +{ + m_list.push_back( l ); + l->show(); +} + +void TagList::mouseMoveEvent( QMouseEvent *e ) { + TagLabel *child = dynamic_cast< TagLabel * >( childAt( e->pos() )->parentWidget() ); + if ( !child ) + return; + QDragObject *d = new QTextDrag( child->tag().fullname( "" ), this ); + d->dragCopy(); +} + +void TagList::dragEnterEvent( QDragEnterEvent *e ) { + kdDebug() << "TagList::dragEnterEvent" << endl; + e->accept( QTextDrag::canDecode( e ) ); +} + +void TagList::dropEvent( QDropEvent* e ) { + QString tag; + kdDebug() << "TagList: drop event" << endl; + QTextDrag::decode( e, tag ); + try { + addTag( aptFront::cache::Global::get().tags().tagByName( + static_cast< const char * >( tag.local8Bit() ) ) ); + } catch (...) {} // not a tag, ignore + scheduleUpdateList(); +} + +void TagList::clearList() +{ + for (List::iterator i = m_list.begin(); i != m_list.end(); ++i ) { + delete *i; + } + m_list.clear(); + m_tagBox->layout()->removeItem( m_tagSpacer ); +} diff --git a/adept/adept/taglist.h b/adept/adept/taglist.h new file mode 100644 index 0000000..3f652a9 --- /dev/null +++ b/adept/adept/taglist.h @@ -0,0 +1,72 @@ +/** -*- C++ -*- + @file adept/taglist.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qvbox.h> +#include <qhbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <kiconloader.h> +#include <vector> +#include <ept/debtags/tag.h> + +#ifndef EPT_TAGLIST_H +#define EPT_TAGLIST_H + +class QLabel; + +namespace adept { + +class TagList; + +class TagLabel : public QHBox +{ + Q_OBJECT +public: + typedef ept::debtags::Tag Tag; + TagLabel( Tag t, TagList *l, QWidget *p = 0, const char *n = 0 ); + Tag tag() { return m_tag; } +protected: + void mouseReleaseEvent( QMouseEvent *e ); + Tag m_tag; + QLabel *m_remove; + QLabel *m_description; + TagList *m_list; +}; + +class TagList : public QVBox +{ + Q_OBJECT +public: + typedef ept::debtags::Tag Tag; + TagList( QWidget *p = 0, const char *n = 0 ); + void setTags( Tag::Set t ); + void addTag( Tag t ); + Tag::Set tags() { return m_tags; } + void setName( QString n ); +public slots: + void scheduleUpdateList(); + void updateList(); +signals: + void tagsChanged( TagList::Tag::Set ); +protected: + void mouseMoveEvent( QMouseEvent *e ); + void dropEvent( QDropEvent * ); + void dragEnterEvent( QDragEnterEvent * ); + void appendLabel( TagLabel * ); + void clearList(); + + bool m_updateScheduled; + Tag::Set m_tags; + QLabel *m_name; + QVBox *m_tagBox; + QSpacerItem *m_tagSpacer; + typedef std::vector< TagLabel * > List; + List m_list; +}; + +} + +#endif diff --git a/adept/adept/threadutils.cpp b/adept/adept/threadutils.cpp new file mode 100644 index 0000000..722f75d --- /dev/null +++ b/adept/adept/threadutils.cpp @@ -0,0 +1,44 @@ +/** -*- C++ -*- + @file adept/utils.cpp + @author Peter Rockai <me@mornfall.net> +*/ + +#include <map> +#include <adept/utils.h> + +namespace adept { + +QMutex Threads::serialize; +Threads::Queue Threads::threads; + +void Threads::wait() { + static std::map< QMutex *, int > locked; + while ( !threads.empty() ) { + QThread *current = threads.front().first; + if ( current->finished() ) { + delete current; + threads.pop_front(); + continue; + } + for ( Queue::iterator thr = threads.begin(); thr != threads.end(); ++thr ) { + ++locked[ thr->second ]; + thr->second->lock(); + } + kapp->processEvents(); + for ( Queue::iterator thr = threads.begin(); thr != threads.end(); ++thr ) { + while ( locked[ thr->second ] > 0 ) { + thr->second->unlock(); + --locked[ thr->second ]; + } + } + usleep( 50000 ); + } +} + +void Threads::enqueue( QThread *t, QMutex *m ) +{ + threads.push_back( std::make_pair( t, m ) ); + t->start(); +} + +} diff --git a/adept/adept/utils.h b/adept/adept/utils.h new file mode 100644 index 0000000..6c3a3d3 --- /dev/null +++ b/adept/adept/utils.h @@ -0,0 +1,71 @@ +/** -*- C++ -*- + @file adept/utils.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qthread.h> +#include <qstring.h> +#include <kapplication.h> +#include <string> +#include <queue> +#include <kdebug.h> + +#ifndef EPT_UTILS_H +#define EPT_UTILS_H + +namespace adept { + +inline QString u8( std::string s ) { + return QString::fromUtf8( s.c_str() ); +} + +inline std::string u8( QString s ) { + return std::string( s.utf8() ); +} + +inline QString u8( const char *s ) { + return QString::fromUtf8( s ); +} + +struct Threads { + static QMutex serialize; + typedef std::deque< std::pair< QThread *, QMutex * > > Queue; + static Queue threads; + static void enqueue( QThread *t, QMutex *m ); + static void wait(); +}; + +template< typename F, typename P > +struct AsyncCall : public QThread +{ + AsyncCall( F f, P p ) : func( f ), param( p ) {} + virtual void run() + { + // kdDebug() << "Thread waiting for mutex..." << endl; + Threads::serialize.lock(); + // kdDebug() << "starting thread (mutex acquired)" << endl; + func( param ); + // kdDebug() << "finishing thread (releasing mutex)" << endl; + Threads::serialize.unlock(); + } + virtual ~AsyncCall() {} +protected: + F func; + P param; +}; + + +template< typename F, typename P > AsyncCall< F, P > *asyncCall( F f, P p ) { + return new AsyncCall< F, P >( f, p ); +} + +inline static void adjustFontSize( QWidget *w, int off ) { + QFont f = w->font(); + f.setPointSize( f.pointSize() + off ); // a bit smaller font... + w->setFont( f ); + w->updateGeometry(); +} + +} + +#endif diff --git a/adept/adept/view.cpp b/adept/adept/view.cpp new file mode 100644 index 0000000..207277c --- /dev/null +++ b/adept/adept/view.cpp @@ -0,0 +1,153 @@ +#include <apt-front/predicate/combinators.h> +#include <apt-front/predicate/factory.h> + +#include <adept/quickfilter.h> +#include <adept/statefilter.h> +#include <adept/tagfilter.h> + +#include <adept/packagedetails.h> +#include <adept/view.h> +#include <adept/filtersidebar.h> + +using namespace adept; + +View::View( QWidget *p, const char *n ) + : QSplitter( p, n ) +{ + setOrientation( Qt::Vertical ); + m_flist = new FilterList( this ); + m_bottom = new QSplitter( this ); + m_bottom->setOrientation( Qt::Horizontal ); + m_lister = new Lister( m_bottom ); + m_flist->plugLister( m_lister ); + m_sidebar = new FilterSidebar( m_bottom ); + + connect( m_lister, SIGNAL( cardinalityChanged( const Lister::Cardinality & ) ), + m_sidebar, SLOT( setCardinality( const Lister::Cardinality & ) ) ); + + m_flist->setHiddenPredicate( + predicate::adapt< entity::Entity >( + predicate::Package::member( &entity::Package::hasVersion ) ) ); + m_flist->appendPredicate( + predicate::adapt< entity::Entity >( + StateFilter< entity::Package >() ) ); + m_flist->appendPredicate( + predicate::adapt< entity::Entity >( + TagFilter< entity::Package >() ) ); + m_flist->appendPredicate( + predicate::adapt< entity::Entity >( + QuickFilter< entity::Package >() ) ); + + m_lister->setRangeProvider( this ); + + QTimer::singleShot( 0, this, SLOT( delayed() ) ); +} + +Lister::Range View::listerRange() { + component::Packages &cp = cache::Global::get().packages(); + return cp.sorted(); + // return range( cp.packagesBegin(), cp.packagesEnd() ); +} + +void View::hideTags() { + QValueList< int > szl; + szl.append( 0 ); szl.append( 1 ); + setSizes( szl ); +} + +void View::hideFilters() { + QValueList< int > szl; + szl.append( 1 ); szl.append( 0 ); + m_bottom->setSizes( szl ); +} + +predicate::Predicate< entity::Entity > View::previewPredicate() +{ + return predicate::adapt< entity::Entity >( + (not predicate::Package::member( &entity::Package::markedKeep )) + or predicate::Package::member( &entity::Package::isBroken ) + or predicate::Package::member( &entity::Package::willBreak ) ); +} + +void View::setUpgradeMode() +{ + setPreviewMode(); + filterList()->setHiddenPredicate( + previewPredicate() or predicate::adapt< entity::Entity >( + predicate::Package::member( &entity::Package::isUpgradable ) ) ); +} + +void View::setPreviewMode() +{ + filterList()->setHiddenPredicate( previewPredicate() ); + hideFilters(); + hideTags(); +} + +void View::delayed() +{ + // cleanRebuild(); +} + +Browser::Browser( QWidget *p, const char *n ) + : QWidgetStack( p, n ), m_currentValid( false ) +{ + m_current = entity::Entity(); + addWidget( m_view = new View( this ) ); + addWidget( m_details = new PackageDetails( this ) ); + connect( m_view->lister(), SIGNAL( detailsRequested( Lister::Entity ) ), + this, SLOT( show( Lister::Entity ) ) ); + connect( m_details, SIGNAL( showList() ), + this, SLOT( showList() ) ); + connect( m_details, SIGNAL( back() ), + this, SLOT( back() ) ); + connect( m_details, SIGNAL( forward() ), + this, SLOT( forward() ) ); + connect( m_details, SIGNAL( detailsRequested( Lister::Entity ) ), + this, SLOT( show( Lister::Entity ) ) ); +} + +void Browser::showList() +{ + raiseWidget( m_view ); +} + +void Browser::back() +{ + m_forward.push_back( m_current ); + m_current = m_back.back(); + m_back.pop_back(); + doShow( m_current ); +} + +void Browser::forward() +{ + m_back.push_back( m_current ); + m_current = m_forward.back(); + m_forward.pop_back(); + doShow( m_current ); +} + +void Browser::doShow( Lister::Entity e ) +{ + m_details->setHasForward( !m_forward.empty() ); + m_details->setHasBack( !m_back.empty() ); + raiseWidget( m_details ); + m_details->setPackage( downcast< entity::Package >( e ) ); +} + +void Browser::show( Lister::Entity e ) +{ + m_forward.clear(); + if ( m_currentValid ) + m_back.push_back( m_current ); + m_currentValid = true; + m_current = e.stable(); + doShow( e ); +} + +/* Kolik existencialistu je potreba k zasroubovani zarovky? + Dva. Jeden sroubuje zarovku, a druhy premysli jak zarovka + sama o sobe predstavuje jednotlivy zarivy bod v subjektivni + realite v podsveti nekonecne absurdity dosahujici neuprimny + vesmir nicoty. */ diff --git a/adept/adept/view.h b/adept/adept/view.h new file mode 100644 index 0000000..ea6c6f5 --- /dev/null +++ b/adept/adept/view.h @@ -0,0 +1,66 @@ +// -*- C++ -*- + +#include <deque> + +#include <qsplitter.h> +#include <qwidgetstack.h> + +#include <adept/lister.h> +#include <adept/filterlist.h> + +#ifndef EPT_VIEW_H +#define EPT_VIEW_H + +class QSplitter; + +namespace adept { + +class FilterSidebar; +class PackageDetails; + +class View: public QSplitter, public Lister::RangeProvider { + Q_OBJECT +public: + View( QWidget *p = 0, const char *n = 0 ); + FilterList *filterList() { return m_flist; } + Lister *lister() { return m_lister; } + virtual Lister::Range listerRange(); +public slots: + void cleanRebuild() { m_lister->cleanRebuild(); } + void hideFilters(); + void hideTags(); + void setPreviewMode(); + void setUpgradeMode(); +protected slots: + void delayed(); +protected: + predicate::Predicate< entity::Entity > previewPredicate(); + QSplitter *m_bottom; + FilterList *m_flist; + Lister *m_lister; + FilterSidebar *m_sidebar; +}; + +class Browser : public QWidgetStack { + Q_OBJECT +public: + Browser( QWidget *p = 0, const char *n = 0 ); + View *searchView() const { return m_view; } +public slots: + void forward(); + void back(); + void show( Lister::Entity e ); + void showList(); + void doShow( Lister::Entity e ); +protected: + typedef std::deque< Lister::Entity > Deque; + Deque m_forward, m_back; + entity::Entity m_current; + View *m_view; + PackageDetails *m_details; + bool m_currentValid; +}; + +} + +#endif diff --git a/adept/batch/Makefile.am b/adept/batch/Makefile.am new file mode 100644 index 0000000..a14de1f --- /dev/null +++ b/adept/batch/Makefile.am @@ -0,0 +1,20 @@ +bin_PROGRAMS = adept_batch +noinst_HEADERS = app.h +adept_batch_SOURCES = main.cpp app.cpp +adept_batch_LDADD = ../adept/libadept.la $(LIBAPT_FRONT_LIBS) $(LIBEPT_LIBS) $(LIBTAGCOLL2_LIBS) $(LIBWIBBLE_LIBS) $(LIB_KIO) $(LIBKDE_UI) ../kubuntu_upgrader/libkubuntuupgradewizard.la +adept_batch_LDFLAGS = -L/usr/lib/debug +INCLUDES = $(all_includes) $(LIBAPT_FRONT_CFLAGS) $(LIBEPT_CFLAGS) $(LIBTAGCOLL2_CFLAGS) $(LIBWIBBLE_CFLAGS) -I$(srcdir)/.. -I.. +KDE_CXXFLAGS = $(USE_EXCEPTIONS) -DQT_NO_ASCII_CAST -DQT_NO_CAST_ASCII +METASOURCES = AUTO +KDE_ICON = AUTO + +rcdir = $(kde_datadir)/adept_batch +rc_DATA = adept_batchui.rc + +#shelldesktopdir = $(kde_appsdir)/System +#xdg_apps_DATA = adept_batch.desktop + +messages: rc.cpp + $(EXTRACTRC) `find . -name \*.ui -o -name \*.rc` > rc.cpp + $(EXTRACTRC) `find . -name "*.rc"` >> rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/adept_batch.pot diff --git a/adept/batch/adept_batchui.rc b/adept/batch/adept_batchui.rc new file mode 100644 index 0000000..083b9e8 --- /dev/null +++ b/adept/batch/adept_batchui.rc @@ -0,0 +1,16 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="6" name="adept-updater"> + <MenuBar> + <Menu name="file" noMerge="1"> + <text>&Adept</text> + <Action name="file_quit" /> + </Menu> + <Menu name="edit" noMerge="1"> + <text>&Edit</text> + <Action name="edit_undo" /> + <Action name="edit_redo" /> + </Menu> + </MenuBar> + <ToolBar name="mainToolBar" noMerge="1"> + </ToolBar> +</kpartgui> diff --git a/adept/batch/adept_updater.desktop b/adept/batch/adept_updater.desktop new file mode 100644 index 0000000..dedcbab --- /dev/null +++ b/adept/batch/adept_updater.desktop @@ -0,0 +1,70 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Adept Updater +Name[bg]=Обновяване на Adept +Name[ca]=Actualitzador Adept +Name[da]=Adept-opdatering +Name[el]=Ανανεωτής Adept +Name[es]=Actualizador experto +Name[et]=Adepti uuendaja +Name[fr]=Mise à jour Adept +Name[ga]=Nuashonróir Adept +Name[gl]=Actualizador de Adept +Name[it]=Aggiornamento Adept +Name[ka]=Adept განმაახლებელი +Name[lt]=Adept atnaujinimai +Name[pt]=Actualizador do Adept +Name[sk]=Adept aktualizácia +Name[sv]=Adept-uppdaterare +Name[xx]=xxAdept Updaterxx +GenericName=System Update Wizard +GenericName[bg]=Обновяване на Adept +GenericName[ca]=Assistent d'actualització del sistema +GenericName[cs]=Průvodce aktualizací systému +GenericName[da]=Systemopdateringsguide +GenericName[de]=Systemaktualisierungsassistent +GenericName[el]=Μάγος ενημέρωσης συστήματος +GenericName[es]=Asistente de actualización del sistema +GenericName[et]=Süsteemi uuendamine nõustaja +GenericName[fr]=Assistant de mise à jour du système +GenericName[gl]=Asistente de Actualizazón do Sistema +GenericName[it]=Procedura guidata aggiornamento sistema +GenericName[ja]=システムアップデートウィザード +GenericName[ka]=სისტემის განახლების ოსტატი +GenericName[lt]=Sistemos atnaujinimo vediklis +GenericName[nl]=Systeem-update-assistent +GenericName[pt]=Assistente de Actualização do Sistema +GenericName[sk]=Sprievodca systémovou aktualizáciou +GenericName[sv]=Systemuppdateringsguide +GenericName[xx]=xxSystem Update Wizardxx +Exec=adept_updater %i %m -caption "%c" +TryExec=adept_updater +Categories=Qt;KDE;System; +Icon=adept_updater +Type=Application +X-KDE-SubstituteUID=true +Comment=Update installed software +Comment[bg]=Обновяване на инсталиран софтуер +Comment[ca]=Actualitza el programari instal·lat +Comment[cs]=Aktualizace nainstalovaného softwaru +Comment[da]=Opdatér installeret programmel +Comment[de]=Aktualisiert installierte Software +Comment[el]=Ενημέρωση εγκατεστημένου λογισμικού +Comment[es]=Actualizar el software instalado +Comment[et]=Paigaldatud tarkvara uuendamine +Comment[fr]=Mise à jour des logiciels installés +Comment[ga]=Nuashonraigh bogearraí suiteáilte +Comment[gl]=Actualiza o software instalado +Comment[it]=Aggiorna il software installato +Comment[ja]=インストール済みのソフトウェアをアップデート +Comment[ka]=დაყენებული პროგრამების განახლება +Comment[lt]=Įdiegtų programų atnaujinimas +Comment[nl]=Geïnstalleerde software bijwerken +Comment[pt]=Actualiza o 'software' instalado +Comment[sk]=Aktualizácia inštalovaného softwaru +Comment[sr]=Ажурира инсталиране програме +Comment[sr@Latn]=Ažurira instalirane programe +Comment[sv]=Uppdatera installerad programvara +Comment[xx]=xxUpdate installed softwarexx +Terminal=false +NoDisplay=true diff --git a/adept/batch/app.cpp b/adept/batch/app.cpp new file mode 100644 index 0000000..dd99ec1 --- /dev/null +++ b/adept/batch/app.cpp @@ -0,0 +1,142 @@ +#include <qvbox.h> +#include <qlabel.h> +#include <qsplitter.h> +#include <qtimer.h> +#include <qwidgetstack.h> + +#include <kpushbutton.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kaction.h> +#include <kactionclasses.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kparts/part.h> +#include <ktrader.h> +#include <klibloader.h> +#include <kstatusbar.h> + +#include <apt-pkg/packagemanager.h> +#include <apt-front/manager.h> +#include <apt-front/init.h> +#include <apt-front/cache/entity/package.h> +#include <apt-front/cache/component/state.h> +#include <apt-front/cache/component/history.h> +#include <apt-front/predicate/factory.h> + +#include <adept/acqprogresswidget.h> +#include <adept/progress.h> +#include <adept/utils.h> + +#include <iostream> + +#include "app.h" + +using namespace aptFront; +using namespace aptFront::cache; +using namespace adept; + +App::App( KCmdLineArgs *args ) { + setMainWidget( this ); + initialize(); + QString qs_pkgname; + + updating = false; + enum { None, Remove, Install } m = None; + for(int i = 0; i < args->count(); i++) { + QCString a = args->arg( i ); + + if (m == None || + cache().packages().packageByName( std::string( a ) ).valid()) { + if ( m == Install ) { + kdDebug() << "installing " << a << endl; + cache().packages().packageByName( std::string( a ) ).markInstall(); + } else if ( m == Remove ) { + kdDebug() << "removing " << a << endl; + cache().packages().packageByName( std::string( a ) ).markRemove(); + } + + if ( m == None && a == "install" ) { + m = Install; + } if ( m == None && a == "remove" ) { + m = Remove; + } if ( m == None && a == "update" ) { + updating = true; + } + } else { + qs_pkgname = a; + kdDebug() << "The package '"<<a<<"' could not be found." << endl; + KMessageBox::sorry( + this, i18n( "The package '%1' could not be found." ).arg(u8(qs_pkgname)), + i18n( "Could not commit changes" ) ); + exit(1); + } + } + + if (!updating && m == 0) { + exit( 1 ); + } + + observeComponent< component::State >(); + + m_all = new QVBox( this ); + m_stack = new QWidgetStack( m_all ); + + m_stack->addWidget( m_progress = new adept::AcqProgressWidget( m_stack ) ); + m_stack->addWidget( m_commitProgress = new CommitProgress( m_stack ) ); + + connect(this, SIGNAL( imDone() ), + this, SLOT( handleDone() )); + + setStandardToolBarMenuEnabled( false ); + createStandardStatusBarAction(); + setupGUI( Keys|StatusBar|Save|Create ); + delete toolBar(); + + Application::setStatusBar( statusBar() ); + + QTimer::singleShot( + 0, this, + SLOT( delayed() ) ); + + m_stack->raiseWidget( m_progress ); + setCentralWidget( m_all ); +} + +void App::delayed() { + statusBar()->clear(); + + kdDebug() << "App::delayed starting commit" << endl; + + aptFront::Manager m; + m.setProgressCallback( m_progress->callback() ); + m.setUpdateInterval( 100000 ); + try { + if (updating) { + m_stack->raiseWidget( m_progress ); + m.update(); + } else { + m_stack->raiseWidget( m_progress ); + m.download(); + m_stack->raiseWidget( m_commitProgress ); + m.commit(); + } + emit imDone(); + } catch ( exception::OperationCancelled ) { + emit imDone(); + } catch ( ... ) { + KMessageBox::sorry( + this, i18n( "There was an error commiting changes. " + "Possibly there was a problem downloading some " + "packages or the commit would break packages. " ), + i18n( "Could not commit changes" ) ); + emit imDone(); + } +} + +void App::handleDone() { + kdDebug() << "I'm done here" << endl; + close(); +} + +#include "app.moc" diff --git a/adept/batch/app.h b/adept/batch/app.h new file mode 100644 index 0000000..604a5a2 --- /dev/null +++ b/adept/batch/app.h @@ -0,0 +1,54 @@ +/* -*- C++ -*- */ +#ifndef APP_H +#define APP_H + +#include <kmainwindow.h> +#include <kparts/part.h> +#include <kactionclasses.h> +#include <kcmdlineargs.h> +#include <apt-front/cache/observer.h> +#include <apt-front/cache/component/state.h> +#include <apt-front/cache/component/history.h> +#include <adept/view.h> +#include <adept/commitprogress.h> +#include <adept/application.h> + +#include <adept/acqprogresswidget.h> + +class QVBox; +class QWidgetStack; +class QSplitter; +class KAction; +class KPushButton; +namespace adept { +class AcqProgressWidget; +} + +using namespace aptFront; +using namespace adept; + +class App : public KMainWindow, Application { + Q_OBJECT +public: + void setupActions(); + ExtTerminalInterface *terminal(); + App( KCmdLineArgs *a ); +signals: + void imDone(); +protected slots: + void delayed(); + void handleDone(); +protected: + friend class WaitForLister; + + QWidgetStack *m_stack; + QVBox *m_all; + + // stacked widgets + adept::AcqProgressWidget *m_progress; + adept::CommitProgress *m_commitProgress; + + bool updating; +}; + +#endif diff --git a/adept/batch/main.cpp b/adept/batch/main.cpp new file mode 100644 index 0000000..7521f6c --- /dev/null +++ b/adept/batch/main.cpp @@ -0,0 +1,48 @@ +// KDE includes + +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#include <kuniqueapplication.h> + +#include "app.h" + +static KCmdLineOptions options[] = +{ + { "+command", I18N_NOOP("Command"), 0 }, + KCmdLineLastOption +}; + +int main(int argc, char *argv[]) +{ + KLocale::setMainCatalogue("adept"); + + QString description = i18n("Adept Batch"); + + KAboutData aboutData( "adept_batch", + I18N_NOOP("Adept Batch"), + "2.1 Cruiser", + description.latin1(), + KAboutData::License_BSD, + I18N_NOOP("(c) 2006 Peter Rockai"), + 0, + "http://web.mornfall.net/adept.html"); + + aboutData.addAuthor ( "Peter Rockai", + I18N_NOOP("developer"), + "me at mornfall dot net", + "http://web.mornfall.net"); + + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication app; + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + KGlobal::locale()->insertCatalogue(QString::fromUtf8("libept")); + + App *ta = new App( args ); + + app.setMainWidget( ta ); + ta->show(); + + return app.exec(); +} diff --git a/adept/configure.in.in b/adept/configure.in.in new file mode 100644 index 0000000..eac3946 --- /dev/null +++ b/adept/configure.in.in @@ -0,0 +1,5 @@ +AC_ARG_ENABLE(adept, [ --enable-adept compile adept],, [DO_NOT_COMPILE="$DO_NOT_COMPILE adept"]) +LIBTAGCOLL2_DEFS +LIBAPT_FRONT_DEFS +LIBEPT_DEFS +LIBWIBBLE_DEFS diff --git a/adept/deb-build b/adept/deb-build new file mode 100755 index 0000000..dcd2967 --- /dev/null +++ b/adept/deb-build @@ -0,0 +1,21 @@ +#!/bin/sh +version=`head -1 debian/changelog | sed -r 's/.+\(([^)]+)\).+/\1/'` +tgt=_dist/adept-$version +wd="$(pwd)" + +dir=`basename $(pwd)` +cd .. + +rm -rf $tgt +mkdir -p $tgt + +cp -a $dir/debian $tgt/ +cp -a $dir $tgt/adept +cp -a admin $tgt/ +cp configure.in.in Makefile.am.in $tgt/ +(cd $tgt && patch -p1 < $wd/fix-autoconf.patch) +(cd $tgt && libtoolize --force) +cp -f /usr/share/aclocal/libtool.m4 $tgt/admin/libtool.m4.in +export UNSERMAKE=no +(cd $tgt && make -f admin/Makefile.common cvs) +(cd $tgt && debuild $@) diff --git a/adept/icons/Makefile.am b/adept/icons/Makefile.am new file mode 100644 index 0000000..e5515a8 --- /dev/null +++ b/adept/icons/Makefile.am @@ -0,0 +1 @@ +KDE_ICON = AUTO diff --git a/adept/icons/cr128-action-adept_notifier_warning.png b/adept/icons/cr128-action-adept_notifier_warning.png Binary files differnew file mode 100644 index 0000000..49b0960 --- /dev/null +++ b/adept/icons/cr128-action-adept_notifier_warning.png diff --git a/adept/icons/cr16-action-adept_commit.png b/adept/icons/cr16-action-adept_commit.png Binary files differnew file mode 100644 index 0000000..5b0f6a6 --- /dev/null +++ b/adept/icons/cr16-action-adept_commit.png diff --git a/adept/icons/cr16-action-adept_distupgrade.png b/adept/icons/cr16-action-adept_distupgrade.png Binary files differnew file mode 100644 index 0000000..3de9a44 --- /dev/null +++ b/adept/icons/cr16-action-adept_distupgrade.png diff --git a/adept/icons/cr16-action-adept_install.png b/adept/icons/cr16-action-adept_install.png Binary files differnew file mode 100644 index 0000000..e948508 --- /dev/null +++ b/adept/icons/cr16-action-adept_install.png diff --git a/adept/icons/cr16-action-adept_keep.png b/adept/icons/cr16-action-adept_keep.png Binary files differnew file mode 100644 index 0000000..3fe8b17 --- /dev/null +++ b/adept/icons/cr16-action-adept_keep.png diff --git a/adept/icons/cr16-action-adept_main_indicator.png b/adept/icons/cr16-action-adept_main_indicator.png Binary files differnew file mode 100644 index 0000000..cc09bc8 --- /dev/null +++ b/adept/icons/cr16-action-adept_main_indicator.png diff --git a/adept/icons/cr16-action-adept_notifier_ok.png b/adept/icons/cr16-action-adept_notifier_ok.png Binary files differnew file mode 100644 index 0000000..08b9c9d --- /dev/null +++ b/adept/icons/cr16-action-adept_notifier_ok.png diff --git a/adept/icons/cr16-action-adept_notifier_warning.png b/adept/icons/cr16-action-adept_notifier_warning.png Binary files differnew file mode 100644 index 0000000..c3b9428 --- /dev/null +++ b/adept/icons/cr16-action-adept_notifier_warning.png diff --git a/adept/icons/cr16-action-adept_preview.png b/adept/icons/cr16-action-adept_preview.png Binary files differnew file mode 100644 index 0000000..487a3ec --- /dev/null +++ b/adept/icons/cr16-action-adept_preview.png diff --git a/adept/icons/cr16-action-adept_purge.png b/adept/icons/cr16-action-adept_purge.png Binary files differnew file mode 100644 index 0000000..145aca4 --- /dev/null +++ b/adept/icons/cr16-action-adept_purge.png diff --git a/adept/icons/cr16-action-adept_reinstall.png b/adept/icons/cr16-action-adept_reinstall.png Binary files differnew file mode 100644 index 0000000..3f1c7ae --- /dev/null +++ b/adept/icons/cr16-action-adept_reinstall.png diff --git a/adept/icons/cr16-action-adept_remove.png b/adept/icons/cr16-action-adept_remove.png Binary files differnew file mode 100644 index 0000000..d555d92 --- /dev/null +++ b/adept/icons/cr16-action-adept_remove.png diff --git a/adept/icons/cr16-action-adept_sourceseditor.png b/adept/icons/cr16-action-adept_sourceseditor.png Binary files differnew file mode 100644 index 0000000..9d47a67 --- /dev/null +++ b/adept/icons/cr16-action-adept_sourceseditor.png diff --git a/adept/icons/cr16-action-adept_update.png b/adept/icons/cr16-action-adept_update.png Binary files differnew file mode 100644 index 0000000..1c026d3 --- /dev/null +++ b/adept/icons/cr16-action-adept_update.png diff --git a/adept/icons/cr16-action-adept_upgrade.png b/adept/icons/cr16-action-adept_upgrade.png Binary files differnew file mode 100644 index 0000000..184c118 --- /dev/null +++ b/adept/icons/cr16-action-adept_upgrade.png diff --git a/adept/icons/cr16-action-extender_closed.png b/adept/icons/cr16-action-extender_closed.png Binary files differnew file mode 100644 index 0000000..24a89b5 --- /dev/null +++ b/adept/icons/cr16-action-extender_closed.png diff --git a/adept/icons/cr16-action-extender_opened.png b/adept/icons/cr16-action-extender_opened.png Binary files differnew file mode 100644 index 0000000..a4f8e50 --- /dev/null +++ b/adept/icons/cr16-action-extender_opened.png diff --git a/adept/icons/cr22-action-adept_commit.png b/adept/icons/cr22-action-adept_commit.png Binary files differnew file mode 100644 index 0000000..2166fdf --- /dev/null +++ b/adept/icons/cr22-action-adept_commit.png diff --git a/adept/icons/cr22-action-adept_distupgrade.png b/adept/icons/cr22-action-adept_distupgrade.png Binary files differnew file mode 100644 index 0000000..251f3a0 --- /dev/null +++ b/adept/icons/cr22-action-adept_distupgrade.png diff --git a/adept/icons/cr22-action-adept_install.png b/adept/icons/cr22-action-adept_install.png Binary files differnew file mode 100644 index 0000000..e2823ba --- /dev/null +++ b/adept/icons/cr22-action-adept_install.png diff --git a/adept/icons/cr22-action-adept_keep.png b/adept/icons/cr22-action-adept_keep.png Binary files differnew file mode 100644 index 0000000..f392596 --- /dev/null +++ b/adept/icons/cr22-action-adept_keep.png diff --git a/adept/icons/cr22-action-adept_notifier_ok.png b/adept/icons/cr22-action-adept_notifier_ok.png Binary files differnew file mode 100644 index 0000000..5cf1392 --- /dev/null +++ b/adept/icons/cr22-action-adept_notifier_ok.png diff --git a/adept/icons/cr22-action-adept_notifier_warning.png b/adept/icons/cr22-action-adept_notifier_warning.png Binary files differnew file mode 100644 index 0000000..5d8fb4f --- /dev/null +++ b/adept/icons/cr22-action-adept_notifier_warning.png diff --git a/adept/icons/cr22-action-adept_preview.png b/adept/icons/cr22-action-adept_preview.png Binary files differnew file mode 100644 index 0000000..6f5792a --- /dev/null +++ b/adept/icons/cr22-action-adept_preview.png diff --git a/adept/icons/cr22-action-adept_purge.png b/adept/icons/cr22-action-adept_purge.png Binary files differnew file mode 100644 index 0000000..5d1bce8 --- /dev/null +++ b/adept/icons/cr22-action-adept_purge.png diff --git a/adept/icons/cr22-action-adept_reinstall.png b/adept/icons/cr22-action-adept_reinstall.png Binary files differnew file mode 100644 index 0000000..3054f31 --- /dev/null +++ b/adept/icons/cr22-action-adept_reinstall.png diff --git a/adept/icons/cr22-action-adept_remove.png b/adept/icons/cr22-action-adept_remove.png Binary files differnew file mode 100644 index 0000000..bb16f03 --- /dev/null +++ b/adept/icons/cr22-action-adept_remove.png diff --git a/adept/icons/cr22-action-adept_sourceseditor.png b/adept/icons/cr22-action-adept_sourceseditor.png Binary files differnew file mode 100644 index 0000000..ceb2cbf --- /dev/null +++ b/adept/icons/cr22-action-adept_sourceseditor.png diff --git a/adept/icons/cr22-action-adept_update.png b/adept/icons/cr22-action-adept_update.png Binary files differnew file mode 100644 index 0000000..0d1ae45 --- /dev/null +++ b/adept/icons/cr22-action-adept_update.png diff --git a/adept/icons/cr22-action-adept_upgrade.png b/adept/icons/cr22-action-adept_upgrade.png Binary files differnew file mode 100644 index 0000000..7475f6a --- /dev/null +++ b/adept/icons/cr22-action-adept_upgrade.png diff --git a/adept/icons/cr22-action-extender_closed.png b/adept/icons/cr22-action-extender_closed.png Binary files differnew file mode 100644 index 0000000..95fc568 --- /dev/null +++ b/adept/icons/cr22-action-extender_closed.png diff --git a/adept/icons/cr22-action-extender_opened.png b/adept/icons/cr22-action-extender_opened.png Binary files differnew file mode 100644 index 0000000..53c2297 --- /dev/null +++ b/adept/icons/cr22-action-extender_opened.png diff --git a/adept/icons/cr32-action-adept_commit.png b/adept/icons/cr32-action-adept_commit.png Binary files differnew file mode 100644 index 0000000..592ce6f --- /dev/null +++ b/adept/icons/cr32-action-adept_commit.png diff --git a/adept/icons/cr32-action-adept_distupgrade.png b/adept/icons/cr32-action-adept_distupgrade.png Binary files differnew file mode 100644 index 0000000..63e8ebf --- /dev/null +++ b/adept/icons/cr32-action-adept_distupgrade.png diff --git a/adept/icons/cr32-action-adept_install.png b/adept/icons/cr32-action-adept_install.png Binary files differnew file mode 100644 index 0000000..90fec1d --- /dev/null +++ b/adept/icons/cr32-action-adept_install.png diff --git a/adept/icons/cr32-action-adept_keep.png b/adept/icons/cr32-action-adept_keep.png Binary files differnew file mode 100644 index 0000000..2568b59 --- /dev/null +++ b/adept/icons/cr32-action-adept_keep.png diff --git a/adept/icons/cr32-action-adept_notifier_ok.png b/adept/icons/cr32-action-adept_notifier_ok.png Binary files differnew file mode 100644 index 0000000..1914a42 --- /dev/null +++ b/adept/icons/cr32-action-adept_notifier_ok.png diff --git a/adept/icons/cr32-action-adept_notifier_warning.png b/adept/icons/cr32-action-adept_notifier_warning.png Binary files differnew file mode 100644 index 0000000..d2db447 --- /dev/null +++ b/adept/icons/cr32-action-adept_notifier_warning.png diff --git a/adept/icons/cr32-action-adept_preview.png b/adept/icons/cr32-action-adept_preview.png Binary files differnew file mode 100644 index 0000000..e92f3ca --- /dev/null +++ b/adept/icons/cr32-action-adept_preview.png diff --git a/adept/icons/cr32-action-adept_purge.png b/adept/icons/cr32-action-adept_purge.png Binary files differnew file mode 100644 index 0000000..9a6aadb --- /dev/null +++ b/adept/icons/cr32-action-adept_purge.png diff --git a/adept/icons/cr32-action-adept_reinstall.png b/adept/icons/cr32-action-adept_reinstall.png Binary files differnew file mode 100644 index 0000000..cb734f8 --- /dev/null +++ b/adept/icons/cr32-action-adept_reinstall.png diff --git a/adept/icons/cr32-action-adept_remove.png b/adept/icons/cr32-action-adept_remove.png Binary files differnew file mode 100644 index 0000000..5a6b15a --- /dev/null +++ b/adept/icons/cr32-action-adept_remove.png diff --git a/adept/icons/cr32-action-adept_sourceseditor.png b/adept/icons/cr32-action-adept_sourceseditor.png Binary files differnew file mode 100644 index 0000000..ff21ea5 --- /dev/null +++ b/adept/icons/cr32-action-adept_sourceseditor.png diff --git a/adept/icons/cr32-action-adept_update.png b/adept/icons/cr32-action-adept_update.png Binary files differnew file mode 100644 index 0000000..4b0e37a --- /dev/null +++ b/adept/icons/cr32-action-adept_update.png diff --git a/adept/icons/cr32-action-adept_upgrade.png b/adept/icons/cr32-action-adept_upgrade.png Binary files differnew file mode 100644 index 0000000..899ad4f --- /dev/null +++ b/adept/icons/cr32-action-adept_upgrade.png diff --git a/adept/icons/cr32-action-extender_closed.png b/adept/icons/cr32-action-extender_closed.png Binary files differnew file mode 100644 index 0000000..cd1be0c --- /dev/null +++ b/adept/icons/cr32-action-extender_closed.png diff --git a/adept/icons/cr32-action-extender_opened.png b/adept/icons/cr32-action-extender_opened.png Binary files differnew file mode 100644 index 0000000..2c9074d --- /dev/null +++ b/adept/icons/cr32-action-extender_opened.png diff --git a/adept/icons/cr48-action-adept_commit.png b/adept/icons/cr48-action-adept_commit.png Binary files differnew file mode 100644 index 0000000..3b7a690 --- /dev/null +++ b/adept/icons/cr48-action-adept_commit.png diff --git a/adept/icons/cr48-action-adept_distupgrade.png b/adept/icons/cr48-action-adept_distupgrade.png Binary files differnew file mode 100644 index 0000000..fb43a06 --- /dev/null +++ b/adept/icons/cr48-action-adept_distupgrade.png diff --git a/adept/icons/cr48-action-adept_install.png b/adept/icons/cr48-action-adept_install.png Binary files differnew file mode 100644 index 0000000..1b12d6c --- /dev/null +++ b/adept/icons/cr48-action-adept_install.png diff --git a/adept/icons/cr48-action-adept_keep.png b/adept/icons/cr48-action-adept_keep.png Binary files differnew file mode 100644 index 0000000..753b14f --- /dev/null +++ b/adept/icons/cr48-action-adept_keep.png diff --git a/adept/icons/cr48-action-adept_notifier_ok.png b/adept/icons/cr48-action-adept_notifier_ok.png Binary files differnew file mode 100644 index 0000000..5707ba9 --- /dev/null +++ b/adept/icons/cr48-action-adept_notifier_ok.png diff --git a/adept/icons/cr48-action-adept_notifier_warning.png b/adept/icons/cr48-action-adept_notifier_warning.png Binary files differnew file mode 100644 index 0000000..5add449 --- /dev/null +++ b/adept/icons/cr48-action-adept_notifier_warning.png diff --git a/adept/icons/cr48-action-adept_preview.png b/adept/icons/cr48-action-adept_preview.png Binary files differnew file mode 100644 index 0000000..3dc1678 --- /dev/null +++ b/adept/icons/cr48-action-adept_preview.png diff --git a/adept/icons/cr48-action-adept_purge.png b/adept/icons/cr48-action-adept_purge.png Binary files differnew file mode 100644 index 0000000..70e8012 --- /dev/null +++ b/adept/icons/cr48-action-adept_purge.png diff --git a/adept/icons/cr48-action-adept_reinstall.png b/adept/icons/cr48-action-adept_reinstall.png Binary files differnew file mode 100644 index 0000000..00cd6ef --- /dev/null +++ b/adept/icons/cr48-action-adept_reinstall.png diff --git a/adept/icons/cr48-action-adept_remove.png b/adept/icons/cr48-action-adept_remove.png Binary files differnew file mode 100644 index 0000000..984bf23 --- /dev/null +++ b/adept/icons/cr48-action-adept_remove.png diff --git a/adept/icons/cr48-action-adept_sourceseditor.png b/adept/icons/cr48-action-adept_sourceseditor.png Binary files differnew file mode 100644 index 0000000..cab2a62 --- /dev/null +++ b/adept/icons/cr48-action-adept_sourceseditor.png diff --git a/adept/icons/cr48-action-adept_update.png b/adept/icons/cr48-action-adept_update.png Binary files differnew file mode 100644 index 0000000..248f614 --- /dev/null +++ b/adept/icons/cr48-action-adept_update.png diff --git a/adept/icons/cr48-action-adept_upgrade.png b/adept/icons/cr48-action-adept_upgrade.png Binary files differnew file mode 100644 index 0000000..6af2494 --- /dev/null +++ b/adept/icons/cr48-action-adept_upgrade.png diff --git a/adept/icons/cr48-action-extender_closed.png b/adept/icons/cr48-action-extender_closed.png Binary files differnew file mode 100644 index 0000000..fbce893 --- /dev/null +++ b/adept/icons/cr48-action-extender_closed.png diff --git a/adept/icons/cr48-action-extender_opened.png b/adept/icons/cr48-action-extender_opened.png Binary files differnew file mode 100644 index 0000000..ee52113 --- /dev/null +++ b/adept/icons/cr48-action-extender_opened.png diff --git a/adept/icons/cr64-action-adept_notifier_warning.png b/adept/icons/cr64-action-adept_notifier_warning.png Binary files differnew file mode 100644 index 0000000..d868276 --- /dev/null +++ b/adept/icons/cr64-action-adept_notifier_warning.png diff --git a/adept/icons/crsc-action-adept_notifier_warning.svgz b/adept/icons/crsc-action-adept_notifier_warning.svgz Binary files differnew file mode 100644 index 0000000..208a4f6 --- /dev/null +++ b/adept/icons/crsc-action-adept_notifier_warning.svgz diff --git a/adept/installer/Makefile.am b/adept/installer/Makefile.am new file mode 100644 index 0000000..7275f75 --- /dev/null +++ b/adept/installer/Makefile.am @@ -0,0 +1,22 @@ + +bin_PROGRAMS = adept_installer +noinst_HEADERS = app.h +adept_installer_SOURCES = main.cpp app.cpp +adept_installer_LDADD = ../adept/libadept.la -lapt-front $(LIBTAGCOLL2_LIBS) $(LIB_KIO) $(LIBKDE_UI) +adept_installer_LDFLAGS = -L/usr/lib/debug +INCLUDES = $(all_includes) $(LIBEPT_CFLAGS) $(LIBTAGCOLL2_CFLAGS) $(LIBAPT_FRONT_CFLAGS) $(LIBWIBBLE_CFLAGS) -I$(srcdir)/.. -I.. +KDE_CXXFLAGS = $(USE_EXCEPTIONS) -DQT_NO_ASCII_CAST -DQT_NO_CAST_ASCII \ + -DINSTALLER_DATA=\"/usr/share/app-install\" +METASOURCES = AUTO +KDE_ICON = AUTO + +rcdir = $(kde_datadir)/adept_installer +rc_DATA = adept_installerui.rc + +#shelldesktopdir = $(kde_appsdir)/System +xdg_apps_DATA = adept_installer.desktop + +messages: rc.cpp + $(EXTRACTRC) `find . -name \*.ui -o -name \*.rc` > rc.cpp + $(EXTRACTRC) `find . -name "*.rc"` >> rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/adept_installer.pot diff --git a/adept/installer/adept_installer.desktop b/adept/installer/adept_installer.desktop new file mode 100644 index 0000000..4bba24c --- /dev/null +++ b/adept/installer/adept_installer.desktop @@ -0,0 +1,45 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Add/Remove Programs +Name[bg]=Добавяне/Премахване на програми +Name[br]=Ouzhpennañ/Lemel programmoù +Name[ca]=Afegeix/Elimina programes +Name[cs]=Přidat/odstranit programy +Name[da]=Tilføj/Fjern programmer +Name[de]=Programme hinzufügen/entfernen +Name[el]=Προσθήκη/Αφαίρεση εφαρμογών +Name[es]=Añadir/eliminar programas +Name[gl]=Engade/Quita Programas +Name[it]=Aggiungi/Rimuovi Programmi +Name[ja]=プログラムの追加と削除 +Name[ka]=პროგრამების დაყენება/წაშლა +Name[lt]=Pridėti/šalinti programas +Name[nl]=Programma's toevoegen/verwijderen +Name[pt]=Adicionar/Remover Programas +Name[sk]=Pridať/Odstrániť programy +Name[sv]=Lägg till/Ta bort program +Exec=/opt/kde3/bin/adept_installer +Categories=Qt;KDE;Core; +Icon=adept_installer +Type=Application +X-KDE-SubstituteUID=true +Comment=Adept Installer: install and remove software packages +Comment[bg]=Инсталатор Adept: инсталиране на нови софтуерни пакети +Comment[ca]=Instal·lador Adept: instal·la i elimina paquets de programari +Comment[cs]=Adept Installer: instalace a smazání softwarových balíčků +Comment[da]=Adept installationsprogram: installér og fjern programmer +Comment[de]=Adept Installationsprogramm: Softwarepakete installieren und deinstallieren +Comment[el]=Εφαρμογή ενημέρωσης λογισμικού Adept: Εγκατάσταση και αφαίρεση πακέτων λογισμικού +Comment[es]=Instalador Adept: instala y elimina paquetes de software +Comment[fr]=Installeur Adept : Installation et mise à jour de paquetages logiciels +Comment[ga]=Suiteálaí Adept: suiteáil agus bain bogearraí +Comment[gl]=Instalador de Adept; instala e borra pacotes de software +Comment[it]=Installatore Adept: installa e rimuove pacchetti di programmi +Comment[ja]=Adept Installer: ソフトウェアパッケージのインストールと削除 +Comment[ka]=Adept დამყენებელი: პაკეტების დაყენება და წაშლა +Comment[lt]=Adept tvarkytuvė: programų paketų diegimas ir šalinimas +Comment[nl]=Adept Installer: installeer en verwijder softwarepakketten +Comment[pt]=Instalador Adept: Instalar e remover pacotes de 'software' +Comment[sk]=Adept Installer: inštaluje a odstraňuje softwarové balíky +Comment[sv]=Adept installationsprogram: installera och ta bort programvarupaket +Terminal=false diff --git a/adept/installer/adept_installerui.rc b/adept/installer/adept_installerui.rc new file mode 100644 index 0000000..a4eca27 --- /dev/null +++ b/adept/installer/adept_installerui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="6" name="adept-updater"> + <MenuBar> + <Menu name="file" noMerge="1"> + <text>&Adept</text> + <Action name="file_quit" /> + </Menu> + <Menu name="edit" noMerge="1"> + <text>&Edit</text> + <Action name="edit_undo" /> + <Action name="edit_redo" /> + </Menu> + <Menu name="view" noMerge="1"> + <text>&View</text> + <Action name="review"/> + </Menu> + </MenuBar> + <ToolBar name="mainToolBar" noMerge="1"> + </ToolBar> +</kpartgui> diff --git a/adept/installer/app.cpp b/adept/installer/app.cpp new file mode 100644 index 0000000..7c82421 --- /dev/null +++ b/adept/installer/app.cpp @@ -0,0 +1,416 @@ +#include <qvbox.h> +#include <qlabel.h> +#include <qpopupmenu.h> +#include <qsplitter.h> +#include <qtimer.h> +#include <qwidgetstack.h> + +#include <kpushbutton.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kaction.h> +#include <kactionclasses.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kparts/part.h> +#include <ktrader.h> +#include <klibloader.h> +#include <kstatusbar.h> +#include <kstandarddirs.h> +#include <kprocess.h> +#include <kmenubar.h> + +#include <apt-pkg/packagemanager.h> +#include <apt-front/manager.h> +#include <apt-front/init.h> +#include <apt-front/cache/entity/package.h> +#include <apt-front/cache/component/state.h> +#include <apt-front/cache/component/desktop.h> +#include <apt-front/cache/component/history.h> +#include <apt-front/predicate/factory.h> + +#include <adept/acqprogresswidget.h> +#include <adept/desktoplist.h> +#include <adept/utils.h> + +#include "app.h" + +#include <adept/dpkgpm-gui.h> // EVIL + +using namespace aptFront; +using namespace cache; +using namespace utils; +using namespace adept; + +std::string GroupPolicy::groupForCategories( Range< std::string > r ) { + /* std::cerr << "groupForCategories: "; + for ( Range< std::string > i = r; i != i.end(); ++i ) { + std::cerr << *i << " "; + } + std::cerr << std::endl; */ + for ( Range< std::string > i = r; i != i.end(); ++i ) { + if ( i->find( "X-KDE-settings" ) != std::string::npos ) + return "Settings"; + if ( i->find( "X-KDE-information" ) != std::string::npos ) + return "Settings"; + } + if ( r.contains( "Development" ) ) return "Development"; + if ( !r.contains( "Education" ) ) { + if ( r.contains( "Astronomy" ) || r.contains( "Biology" ) + || r.contains( "Chemistry" ) || r.contains( "Geology" ) + || r.contains( "MedicalSoftware" ) || r.contains( "Physics" ) + || r.contains( "Math" ) || r.contains( "Science" ) ) + return "Science"; + } else { + return "Edutainment"; + } + if ( r.contains( "Game" ) ) return "Games"; + if ( r.contains( "Graphics" ) ) return "Graphics"; + if ( r.contains( "Network" ) ) return "Internet"; + if ( r.contains( "AudioVideo" ) ) return "Multimedia"; + if ( r.contains( "Office" ) ) return "Office"; + if ( r.contains( "Settings" ) ) return "Settings"; + if ( r.contains( "System" ) ) return "System"; + if ( r.contains( "Utility" ) ) { + if ( r.contains( "Accessibility" ) ) + return "Accessibility"; + return "Utilities"; + } + return "Others"; +} + +QString IconPolicy::iconForGroup( QString g ) { + if ( g == u8( "Office" ) ) return u8( "package_wordprocessing" ); + if ( g == u8( "Internet" ) ) return u8( "package_network" ); + if ( g == u8( "Science" ) ) return u8( "edu_science" ); + if ( g == u8( "Accessibility" ) ) return u8( "access" ); + if ( g == u8( "Others" ) ) return u8( "package" ); + return QString( "package_" ) + g.lower(); +} + +void WaitForLister::waiting() +{ + kdDebug() << "WaitForLister::waiting()" << endl; + /* if (app->m_list->lister()->busy()) + QTimer::singleShot( 100, this, SLOT( waiting() ) ); + else */ { + QTimer::singleShot( 0, app, slot ); + deleteLater(); + } +} + +App::App() { + + m_all = new QVBox( this ); + m_stack = new QWidgetStack( m_all ); + + m_stack->addWidget( m_loading = new QLabel( i18n( "Loading, please wait..." ), m_stack ) ); + m_loading->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter ); + + m_buttons = new QHBox( m_all ); + m_editSources = new KPushButton( i18n( "Edit Software Sources" ), m_buttons ); + m_reviewChanges = new KPushButton( i18n( "Review Changes" ), m_buttons ); + QLabel *space = new QLabel( m_buttons ); // spacing + m_next = new KPushButton( i18n( "Next" ), m_buttons ); + m_quit = new KPushButton( i18n( "Quit" ), m_buttons ); + m_editSources->setEnabled( false ); + m_reviewChanges->setEnabled( false ); + m_next->setEnabled( false ); + m_quit->setEnabled( false ); + + m_buttons->setSpacing( 2 ); + m_buttons->setMargin( 2 ); + QSizePolicy buttons( QSizePolicy::Preferred, QSizePolicy::Fixed, false ); + m_buttons->setSizePolicy( buttons ); + m_next->setSizePolicy( buttons ); + m_quit->setSizePolicy( buttons ); + space->setSizePolicy( QSizePolicy( + QSizePolicy::Expanding, + QSizePolicy::Fixed, false ) ); + + setStandardToolBarMenuEnabled( false ); + createStandardStatusBarAction(); + setupActions(); + setupGUI( Keys|StatusBar|Save|Create ); + delete toolBar(); + menuBar()->hide(); + + Application::setStatusBar( statusBar() ); + + QTimer::singleShot( + 0, this, + SLOT( delayed() ) ); + + setCentralWidget( m_all ); + setMinimumSize( 400, 300 ); +} + +void App::delayed() { + + initialize(); + cache().addComponent( new component::Desktop() ); + KGlobal::dirs()->addResourceDir( + "desktopicon", + u8( INSTALLER_DATA "/icons/" ) ); + + cache().component< component::Desktop >().setPolicy( new GroupPolicy() ); + cache().component< component::Desktop >().loadDirectory( + INSTALLER_DATA "/desktop/" ); + + QFile file(QString("/usr/bin/software-properties-kde")); + if (file.exists()) { + connect( m_editSources, SIGNAL( clicked() ), this, SLOT( editSources() ) ); + m_editSources->setEnabled( true ); + } + + connect( m_reviewChanges, SIGNAL( clicked() ), this, SLOT( togglePreview() ) ); + m_reviewChanges->setEnabled( true ); + + connect( m_quit, SIGNAL( clicked() ), this, SLOT( close() ) ); + m_quit->setEnabled( true ); + + m_stack->addWidget( m_view = new InstallerView( m_stack ) ); + connect( m_view->selector(), SIGNAL( request( cache::entity::Package, + cache::component::State::Action ) ), + this, SLOT( request( cache::entity::Package, + cache::component::State::Action ) ) ); + m_stack->addWidget( m_preview = new Browser( m_stack ) ); + m_preview->searchView()->setPreviewMode(); + m_view->selector()->setPolicy( new IconPolicy() ); + + m_stack->addWidget( + m_bye = new QLabel( i18n( "Installation Complete!" ), m_stack ) ); + m_bye->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter ); + + m_stack->addWidget( m_progress = new adept::AcqProgressWidget( m_stack ) ); + m_stack->addWidget( m_commitProgress = new CommitProgress( m_stack ) ); + + m_stack->raiseWidget( m_view ); + + statusBar()->clear(); + m_view->rebuild(); + start(); +} + +bool App::confirmRequest( entity::Package p, component::State::Action a ) +{ + component::Desktop &d = cache::Global::get().component< component::Desktop >(); + typedef predicate::AttributeAdaptor< entity::Desktop, + predicate::match::Exact< entity::Package > > Adaptor; + + QString t; + + if ( a == component::State::ARemove ) + t = i18n( "You selected to remove a program. Following applications " + "are part of the same package, and they will be removed." + " Are you sure you want to remove? " ); + else + return true; + // create modal dialog for the question + KDialogBase *db = new KDialogBase( KDialogBase::Plain, i18n( "Confirm action" ), + KDialogBase::Ok | KDialogBase::Cancel, + KDialogBase::Ok, this ); + QVBoxLayout *layout = new QVBoxLayout( db->plainPage() ); + layout->setSpacing( 4 ); + // db->plainPage()->setLayout( layout = new QVBoxLayout( db->plainPage() ) ); + // QVBox *vb = new QVBox( db ); + QLabel *txt = new QLabel( db->plainPage() ); + txt->setAlignment( Qt::AlignLeft | Qt::AlignTop | Qt::WordBreak ); + txt->setMinimumWidth( 500 ); + txt->setText( t ); + txt->setFixedHeight( txt->heightForWidth( 320 ) ); + txt->setSizePolicy( QSizePolicy( + QSizePolicy::Expanding, QSizePolicy::Fixed, false ) ); + DesktopList *l = new DesktopList( db->plainPage() ); + l->setMinimumHeight( 220 ); + l->setMinimumWidth( 320 ); + l->setDisplayCheckboxes( false ); + layout->addWidget( txt ); + layout->addWidget( l ); + l->insertRange( filteredRange( d.entries(), + Adaptor( &entity::Desktop::package, p ) ) ); + db->adjustSize(); + connect( db, SIGNAL( okClicked() ), this, SLOT( requestOk() ) ); + m_currentRequestOk = false; + db->exec(); + return m_currentRequestOk; +} + +void App::request( entity::Package p, component::State::Action a ) { + if ( !confirmRequest( p, a ) ) return; + RequestList::iterator rm = m_requests.end(), i; + for ( i = m_requests.begin(); i != m_requests.end(); ++i ) { + if ( i->first == p ) { + rm = i; + break; + } + } + if ( rm != m_requests.end() ) + m_requests.erase( rm ); + if ( a != component::State::AKeep ) + m_requests.push_back( std::make_pair( p, a ) ); + cache::Global::get().state().revert(); + cache::Global::get().state().replay( range( m_requests.begin(), + m_requests.end() ) ); +} + +bool App::consistent() { + int remove = 0; + RequestList::iterator i; + for ( i = m_requests.begin(); i != m_requests.end(); ++i ) { + if ( i->second == component::State::ARemove ) { + ++remove; + } + } + if ( remove >= cache::Global::get().state().removeCount() ) + return true; + return false; +} + +void App::setupActions() +{ + KStdAction::quit( kapp, SLOT( quit() ), actionCollection() ); + m_undo = KStdAction::undo( this, SLOT( undo() ), actionCollection() ); + m_redo = KStdAction::redo( this, SLOT( redo() ), actionCollection() ); + m_previewAction = new KToggleAction( + i18n( "Review Changes" ), u8( "adept_preview" ), + 0, this, SLOT( togglePreview() ), actionCollection(), + "review" ); + + setHistoryEnabled( false ); + createStandardStatusBarAction(); +} + +void App::togglePreview() +{ + if ( m_state == Preview ) { + m_previewAction->setChecked( false ); + setState( Select ); + m_stack->raiseWidget( m_view ); + notifyPostChange( 0 ); + m_reviewChanges->setEnabled(true); + } else { + setState( Preview ); + m_stack->raiseWidget( m_preview ); + setNext( i18n( "Back to Program Selection" ), SLOT( togglePreview() ) ); + m_previewAction->setChecked( true ); + m_preview->searchView()->lister()->scheduleRebuild(); + m_reviewChanges->setEnabled(false); + } +} + +void App::inspect() +{ + m_state = Inspect; + m_stack->raiseWidget( m_preview ); + setNext( i18n( "Changes are OK, proceed" ), SLOT( commit() ) ); + m_preview->searchView()->lister()->scheduleRebuild(); +} + +void App::setHistoryEnabled( bool e ) { + if ( e && history() ) { + m_undo->setEnabled( history()->canUndo() ); + m_redo->setEnabled( history()->canRedo() ); + } else { + m_undo->setEnabled( false ); + m_redo->setEnabled( false ); + } +} + +void App::notifyPreRebuild( component::Base *b ) +{ + m_requests.clear(); +} + +void App::notifyPreChange( component::Base *b ) +{ + Application::notifyPreChange( b ); + checkpoint(); +} + +void App::notifyPostChange( component::Base *b ) +{ + Application::notifyPostChange( b ); + + if ( m_state == Select ) { + if ( cache().state().changed() ) + if ( consistent() ) + setNext( i18n( "Apply Changes" ), SLOT( commit() ) ); + else + setNext( i18n( "Inspect Changes" ), SLOT( inspect() ) ); + else + disableNext(); + } +} + +void App::setNext( QString s, const char *slot ) { + m_next->setText( s ); + m_next->setEnabled( true ); + m_next->disconnect( this ); + connect( m_next, SIGNAL( clicked() ), + this, slot ); + m_quit->setEnabled( true ); +} + +void App::disableNext() { + m_next->setText( i18n( "Next" ) ); + m_next->setEnabled( false ); + disconnect( m_next, SIGNAL( clicked() ), 0, 0 ); +} + +void App::disableButtons() { + disableNext(); + m_quit->setEnabled( false ); +} + +void App::editSources() { + KProcess* softwarePropertiesProcess = new KProcess(this); + *softwarePropertiesProcess << "/usr/bin/software-properties-kde"; + softwarePropertiesProcess->start(); +} + +void App::start() { + m_stack->raiseWidget( m_view ); + m_quit->setText( i18n( "Forget Changes and Quit" ) ); + disableNext(); + setState( Select ); + notifyPostChange( 0 ); +} + +void App::commit() { + kdDebug() << "App::commit" << endl; + setState( Commit ); + disableButtons(); + setHistoryEnabled( false ); + + aptFront::Manager m; + m.setProgressCallback( m_progress->callback() ); + m.setUpdateInterval( 100000 ); + try { + m_stack->raiseWidget( m_progress ); + m.download(); + m_stack->raiseWidget( m_commitProgress ); + m.commit(); + } catch ( exception::OperationCancelled ) { + return start(); + } catch ( ... ) { + KMessageBox::sorry( + this, i18n( "There was an error commiting changes. " + "Possibly there was a problem downloading some " + "packages or the commit would break packages. " ), + i18n( "Could not commit changes" ) ); + } + + cache().addComponent( new component::Desktop() ); + cache().component< component::Desktop >().setPolicy( new GroupPolicy() ); + cache().component< component::Desktop >().loadDirectory( + INSTALLER_DATA "/desktop/" ); + QTimer::singleShot( 500, m_view, SLOT( rebuild() ) ); + + m_stack->raiseWidget( m_bye ); + m_quit->setText( i18n( "Quit" ) ); + setNext( i18n( "Back to Program Selection" ), SLOT( start() ) ); + // setNext( i18n( "Done: Quit" ), SLOT( close() ) ); +} + +#include "app.moc" diff --git a/adept/installer/app.h b/adept/installer/app.h new file mode 100644 index 0000000..02ce2e0 --- /dev/null +++ b/adept/installer/app.h @@ -0,0 +1,128 @@ +/* -*- C++ -*- */ +#ifndef TESTUI_APP_H +#define TESTUI_APP_H + +#include <kmainwindow.h> +#include <kparts/part.h> +#include <kactionclasses.h> +#include <apt-front/cache/observer.h> +#include <apt-front/cache/component/state.h> +#include <apt-front/cache/component/history.h> +#include <apt-front/cache/component/desktop.h> +#include <adept/view.h> +#include <adept/commitprogress.h> +#include <adept/installerview.h> +#include <adept/application.h> + +class QVBox; +class QWidgetStack; +class QSplitter; +class KAction; +class KPushButton; +class KProcess; +namespace adept { +class AcqProgressWidget; +} + +using namespace aptFront; +using namespace adept; + +struct GroupPolicy : cache::component::Desktop::GroupPolicy { + virtual std::string groupForCategories( utils::Range< std::string > ); +}; + +struct IconPolicy : GroupedDesktopSelector::IconPolicy { + virtual QString iconForGroup( QString ); +}; + +class App : public KMainWindow, Application { + Q_OBJECT +public: + enum State { Select, Preview, Inspect, Commit }; + void setupActions(); + ExtTerminalInterface *terminal(); + App(); + + // check if the changes in cache are consistent with what is + // checked in the tree and we don't have any suspicious removals + // or other artifacts (broken packages) + bool consistent(); + +protected slots: + void start(); + void commit(); + void inspect(); + + void delayed(); + + void undo() { Application::undo(); } + void redo() { Application::redo(); } + void checkpoint() { Application::checkpoint(); } + + void setHistoryEnabled( bool ); + + void disableNext(); + void disableButtons(); + void setNext( QString str, const char *slot ); + void togglePreview(); + void editSources(); + + void request( cache::entity::Package, cache::component::State::Action ); + + bool confirmRequest( entity::Package, component::State::Action ); + void requestOk() { m_currentRequestOk = true; } + +protected: + friend class WaitForLister; + + void setState( State s ) { m_lastState = m_state; m_state = s; } + + virtual void notifyPreRebuild( cache::component::Base * ); + virtual void notifyPostChange( cache::component::Base * ); + virtual void notifyPreChange( cache::component::Base * ); + + QWidgetStack *m_stack; + QVBox *m_all; + QHBox *m_buttons; + QLabel *m_bye, *m_loading; + KPushButton *m_next, *m_quit; + KPushButton *m_editSources, *m_reviewChanges; + + // stacked widgets + adept::AcqProgressWidget *m_progress; + adept::CommitProgress *m_commitProgress; + // adept::GroupedDesktopSelector *m_desktopSelector; + adept::InstallerView *m_view; + adept::Browser *m_preview; + + // other stuff + std::vector<KAction *> m_actions; + QMap< QString, QString > m_icons; + KAction *m_undo, *m_redo; + KToggleAction *m_previewAction; + State m_state, m_lastState; + + typedef std::list< component::State::Request > RequestList; + RequestList m_requests; + + // XXX hack + bool m_currentRequestOk; +}; + +class WaitForLister : public QObject { + Q_OBJECT +public: + WaitForLister( App *a, const char *s ) + : app( a ), slot( s ) + { + waiting(); + } +protected slots: + void waiting(); +protected: + App *app; + const char *slot; + +}; + +#endif diff --git a/adept/installer/hi128-app-adept_installer.png b/adept/installer/hi128-app-adept_installer.png Binary files differnew file mode 100644 index 0000000..98f792b --- /dev/null +++ b/adept/installer/hi128-app-adept_installer.png diff --git a/adept/installer/hi16-app-adept_installer.png b/adept/installer/hi16-app-adept_installer.png Binary files differnew file mode 100644 index 0000000..7426896 --- /dev/null +++ b/adept/installer/hi16-app-adept_installer.png diff --git a/adept/installer/hi22-app-adept_installer.png b/adept/installer/hi22-app-adept_installer.png Binary files differnew file mode 100644 index 0000000..d0f221f --- /dev/null +++ b/adept/installer/hi22-app-adept_installer.png diff --git a/adept/installer/hi32-app-adept_installer.png b/adept/installer/hi32-app-adept_installer.png Binary files differnew file mode 100644 index 0000000..3f79aa4 --- /dev/null +++ b/adept/installer/hi32-app-adept_installer.png diff --git a/adept/installer/hi48-app-adept_installer.png b/adept/installer/hi48-app-adept_installer.png Binary files differnew file mode 100644 index 0000000..33f9459 --- /dev/null +++ b/adept/installer/hi48-app-adept_installer.png diff --git a/adept/installer/hi64-app-adept_installer.png b/adept/installer/hi64-app-adept_installer.png Binary files differnew file mode 100644 index 0000000..e2a2666 --- /dev/null +++ b/adept/installer/hi64-app-adept_installer.png diff --git a/adept/installer/hisc-app-adept_installer.svgz b/adept/installer/hisc-app-adept_installer.svgz Binary files differnew file mode 100644 index 0000000..00cfa1c --- /dev/null +++ b/adept/installer/hisc-app-adept_installer.svgz diff --git a/adept/installer/main.cpp b/adept/installer/main.cpp new file mode 100644 index 0000000..079cb19 --- /dev/null +++ b/adept/installer/main.cpp @@ -0,0 +1,51 @@ +// KDE includes + +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#include <kuniqueapplication.h> + +#include "app.h" + +static KCmdLineOptions options[] = +{ + KCmdLineLastOption +}; + +int main(int argc, char *argv[]) +{ + + KLocale::setMainCatalogue("adept_installer"); + + putenv( "QT_IM_MODULE=xim" ); + QString description = i18n("Adept Installer"); + + KAboutData aboutData( "adept_installer", + I18N_NOOP("Adept Installer"), + "2.1 Cruiser", + description.latin1(), + KAboutData::License_BSD, + I18N_NOOP("(c) 2005, 2006 Peter Rockai"), + 0, + "http://web.mornfall.net/adept.html"); + + aboutData.addAuthor ( "Peter Rockai", + I18N_NOOP("developer"), + "me at mornfall dot net", + "http://web.mornfall.net"); + + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication app; + + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + + KGlobal::locale()->insertCatalogue(QString::fromUtf8("libept")); + + App *ta = new App(); + + app.setMainWidget(ta); + ta->show(); + + return app.exec(); +} diff --git a/adept/kubuntu_upgrader/Makefile.am b/adept/kubuntu_upgrader/Makefile.am new file mode 100644 index 0000000..63e9569 --- /dev/null +++ b/adept/kubuntu_upgrader/Makefile.am @@ -0,0 +1,11 @@ +METASOURCES = AUTO +noinst_LTLIBRARIES = libkubuntuupgradewizard.la +libkubuntuupgradewizard_la_SOURCES = \ + upgradewizardbase.ui errordialogbase.ui \ + errordialog.cpp upgradewizard.cpp +libkubuntuupgradewizard_la_LIBADD = $(LIB_KIO) $(LIBKDE_UI) +libkubuntuupgradewizard_la_LDFLAGS = -L/usr/lib/debug $(all_libraries) + +INCLUDES = $(all_includes) +KDE_CXXFLAGS = $(USE_EXCEPTIONS) -DQT_NO_ASCII_CAST -DQT_NO_CAST_ASCII + diff --git a/adept/kubuntu_upgrader/errordialog.cpp b/adept/kubuntu_upgrader/errordialog.cpp new file mode 100644 index 0000000..0a1feb0 --- /dev/null +++ b/adept/kubuntu_upgrader/errordialog.cpp @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (C) 2006 by Vladimir Stefan * + * vstefan85@gmail.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; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include <qlabel.h> + +#include "errordialog.h" + +ErrorDialog::ErrorDialog(QWidget* parent, QString error_text, const char* name, bool modal, WFlags fl ) + : ErrorDialogDlg(parent,name, modal,fl) +{ + errorLabel->setText( error_text ); +} + +ErrorDialog::~ErrorDialog() +{} + +/*$SPECIALIZATION$*/ +void ErrorDialog::reject() +{ + QDialog::reject(); +} + +void ErrorDialog::accept() +{ + QDialog::accept(); +} + + + +#include "errordialog.moc" + diff --git a/adept/kubuntu_upgrader/errordialog.h b/adept/kubuntu_upgrader/errordialog.h new file mode 100644 index 0000000..cdb7d14 --- /dev/null +++ b/adept/kubuntu_upgrader/errordialog.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2006 by Vladimir Stefan * + * vstefan85@gmail.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; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef ERRORDIALOG_H +#define ERRORDIALOG_H + +#include "errordialogbase.h" + +class QString; + +class ErrorDialog : public ErrorDialogDlg +{ + Q_OBJECT + +public: + ErrorDialog(QWidget* parent = 0, QString error_text = QString::null, const char* name = 0, bool modal = FALSE, WFlags fl = 0 ); + ~ErrorDialog(); + /*$PUBLIC_FUNCTIONS$*/ + +public slots: + /*$PUBLIC_SLOTS$*/ + +protected: + /*$PROTECTED_FUNCTIONS$*/ + +protected slots: + /*$PROTECTED_SLOTS$*/ + virtual void reject(); + virtual void accept(); + +}; + +#endif + diff --git a/adept/kubuntu_upgrader/errordialogbase.ui b/adept/kubuntu_upgrader/errordialogbase.ui new file mode 100644 index 0000000..21af975 --- /dev/null +++ b/adept/kubuntu_upgrader/errordialogbase.ui @@ -0,0 +1,67 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>ErrorDialogDlg</class> +<widget class="QDialog"> + <property name="name"> + <cstring>errorform</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>222</width> + <height>163</height> + </rect> + </property> + <property name="cursor"> + <cursor>0</cursor> + </property> + <property name="caption"> + <string>Error!</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>errorLabel</cstring> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <property name="text"> + <string><p align="center"></p></string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>exitButton</cstring> + </property> + <property name="text"> + <string>E&xit</string> + </property> + <property name="accel"> + <string>Alt+X</string> + </property> + </widget> + <widget class="QPushButton" row="1" column="0"> + <property name="name"> + <cstring>retryButton</cstring> + </property> + <property name="text"> + <string>Retr&y</string> + </property> + <property name="accel"> + <string>Alt+Y</string> + </property> + </widget> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/adept/kubuntu_upgrader/upgradewizard.cpp b/adept/kubuntu_upgrader/upgradewizard.cpp new file mode 100644 index 0000000..9b81c4d --- /dev/null +++ b/adept/kubuntu_upgrader/upgradewizard.cpp @@ -0,0 +1,545 @@ +/*************************************************************************** + * Copyright (C) 2006 by Vladimir Stefan * + * vstefan85@gmail.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; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include <kurl.h> +#include <kio/netaccess.h> +#include <kio/job.h> +#include <kprocess.h> +#include <klocale.h> +#include <kglobal.h> +#include <kconfig.h> +#include <ktar.h> +#include <kdebug.h> + +#include <qwizard.h> +#include <qwidget.h> +#include <qpushbutton.h> +#include <qtextstream.h> +#include <qfile.h> +#include <qtextbrowser.h> +#include <qmime.h> +#include <qstring.h> +#include <qdialog.h> +#include <qlabel.h> +#include <qdatetime.h> +#include <qtextstream.h> +#include <qptrlist.h> +#include <qdir.h> + +#include <iostream> +#include <cstdlib> + +#include "upgradewizard.h" +#include "errordialog.h" + +DistroEntry::DistroEntry(QString *d_field) +{ + dist_field = d_field; + supported_field = false; + name_field = NULL; + version_field = NULL; + date_field = NULL; + desc_field = NULL; + release_file_url = NULL; + release_notes_url = NULL; + upgrade_tool_url = NULL; + upgrade_tool_sig_url = NULL; +} + +DistroEntry::~DistroEntry() { + free( dist_field ); + free( name_field ); + free( version_field ); + free( date_field ); + free( desc_field ); + free( release_file_url ); + free( release_notes_url ); + free( upgrade_tool_url ); + free( upgrade_tool_sig_url ); +} + +UpgradeWizard::UpgradeWizard(QWidget* parent, const char* name, bool modal, WFlags fl) + : UpgradeWizardDlg(parent,name, modal,fl) +{ + err_dlg = NULL; + + for(int i=0; i<pageCount(); i++) { + QWidget* p = page( i ); + setHelpEnabled( p, false ); + } + + QWidget *p = page( pageCount()-1 ); + setBackEnabled( p, false ); + textLabel3->hide(); + + p = page( pageCount()-2 ); + setNextEnabled( p, false ); + + QPushButton *fin = finishButton(); + connect(fin, SIGNAL( clicked() ), this, SLOT( launchDistUpdater() ) ); + +} + +UpgradeWizard::~UpgradeWizard() +{} + +// ** FUNCTIONS ** // + +void UpgradeWizard::removeDirectory(QString directoryName) +{ + // recursively delete a directory structure + // Mar-22-2007 Billy Pollifrone + QDir dir(directoryName); + QStringList files(dir.entryList()); + for (QStringList::Iterator i=files.begin(); i!=files.end(); i++) { + QString fileName(*(i)); + if (fileName == QString(".") || fileName == QString("..")) continue; + QFileInfo fileInfo(directoryName, fileName); + if (fileInfo.isDir()) { + removeDirectory(fileInfo.absFilePath()); + } else { + QFile file(fileInfo.absFilePath()); + file.remove(); + } + } + dir.rmdir(directoryName); +} + +void UpgradeWizard::removeOldUpgradeTool() +{ + // remove old files from dist-upgrade when we check if there is a knew one since + // adept kills us before we have a chance on the same run. + // Mar-22-2007 Billy Pollifrone + QString directoryName("/tmp/kde-root"); + QString directoryFilter("adept_*.tmp*"); + QDir dir(directoryName, directoryFilter); + QStringList files(dir.entryList()); + for (QStringList::Iterator i=files.begin(); i!=files.end(); i++) { + QString fileName(*(i)); + QFileInfo fileInfo(directoryName, fileName); + if (fileInfo.isDir()) { + removeDirectory(fileInfo.absFilePath()); + } else { + QFile file(fileInfo.absFilePath()); + file.remove(); + } + } +} + +bool UpgradeWizard::checkForDistUpgrade(bool skipIntrepid, QString url, bool developmentVersion) { + removeOldUpgradeTool(); + std::cout << "UpgradeWizard::checkForDistUpgrade" << std::endl; + + if (url == QString("")) { + url = QString("http://changelogs.ubuntu.com/meta-release"); + } + + bool upgrade_available = false; + KConfig* config = KGlobal::config(); + config->setGroup("General Settings"); + QString upgradeURL; + upgradeURL = config->readEntry(QString("upgradeURL"), url); + KURL metafile_url( upgradeURL ); + + QString temp_file_location; + + if( KIO::NetAccess::download( metafile_url, temp_file_location, NULL ) ) { + QFile temp_file( temp_file_location ); + temp_file.open( IO_ReadOnly ); + QTextIStream *temp_file_stream = new QTextIStream( temp_file.readAll() ); + + // need to spawn a process to call lsb_release -c -s + // to find out which version of kubuntu we are using + KProcess *proc = new KProcess; + *proc << "lsb_release"; + *proc << "-c" << "-s"; + connect(proc, SIGNAL( receivedStdout( KProcess*, char *, int ) ), + this, SLOT( receiveDistroName( KProcess*, char *, int ) ) ); + proc->start( KProcess::Block, KProcess::Stdout ); + + current_dist = 0; + QPtrList<DistroEntry> *entry_list = parseMetafile( temp_file_stream, distro_name ); + + upgrade_dist = entry_list->last(); + DistroEntry* entry; + + // if current_dist hasn't been set in parseMetafile then we can't upgrade, since we don't know what we are + if (current_dist == 0) { + return false; + } + + // find the distro version one newer than our current one + for( entry = entry_list->first(); entry; entry = entry_list->next() ) { + //std::cout << "current date: " << (*current_dist->date_field).toString().latin1() << std::endl; + //std::cout << "entry date: " << (*entry->date_field).toString().latin1() << std::endl; + if( *entry->date_field > *current_dist->date_field /*&& entry->supported_field == true*/ ) { + if (!skipIntrepid || QString::compare(*entry->dist_field, QString("intrepid")) != 0) { + upgrade_dist = entry; + upgrade_available = true; + //std::cout << "entry date: " << (*entry->name_field).latin1() << std::endl; + break; + } + } + } + // if there isn't one newer, find the current one + if (!upgrade_available) { + for( entry = entry_list->first(); entry; entry = entry_list->next() ) { + //std::cout << "current date: " << (*current_dist->date_field).toString().latin1() << std::endl; + //std::cout << "entry date: " << (*entry->date_field).toString().latin1() << std::endl; + if( *entry->date_field >= *current_dist->date_field && developmentVersion /*&& entry->supported_field == true*/ ) { + upgrade_dist = entry; + upgrade_available = true; + //std::cout << "entry date: " << (*entry->name_field).latin1() << std::endl; + break; + } + } + } + + // DistroEntry *entry = NULL; + /*Debugging + for( entry = entry_list->first(); entry; entry = entry_list->next() ) { + std::cout << "current date: " << (*current_dist->date_field).toString().latin1() << std::endl; + std::cout << "entry date: " << (*entry->date_field).toString().latin1() << std::endl; + + std::cout << "Dist: " << *entry->dist_field->latin1() << std::endl; + std::cout << "Name: " << *entry->name_field->latin1() << std::endl; + std::cout << "Version: " << *entry->version_field->latin1() << std::endl; + std::cout << "Date: " << entry->date_field->toString( QString( "ddd, dd MMM yyyy hh:mm:ss UTC" ) ).latin1() << std::endl; + //std::cout << "Supported: " << entry->supported_field.latin1() << std::endl; + std::cout << "Description: " << *entry->desc_field->latin1() << std::endl; + std::cout << "Release-File: " << entry->release_file_url->prettyURL().latin1() << std::endl; + if( entry->release_notes_url != NULL ) { + std::cout << "ReleaseNotes: " << entry->release_notes_url->prettyURL().latin1() << std::endl; + } + if( entry->upgrade_tool_url != NULL ) { + std::cout << "UpgradeTool: " << entry->upgrade_tool_url->prettyURL().latin1() << std::endl; + } + if( entry->upgrade_tool_sig_url != NULL ) { + std::cout << "UpgradeToolSignature: " << entry->upgrade_tool_sig_url->prettyURL().latin1() << std::endl; + } + + std::cout << std::endl; + } + */ + temp_file.close(); + KIO::NetAccess::removeTempFile( temp_file_location ); + } + + return upgrade_available; +} + +QPtrList<DistroEntry> *UpgradeWizard::parseMetafile( QTextIStream *text_stream, + QString my_distro_name ) +{ + QPtrList<DistroEntry> *metafile_entries = new QPtrList<DistroEntry>(); + DistroEntry *entry = NULL; + + while( !text_stream->atEnd() ) { + + QStringList line = QStringList::split( QChar(':'), text_stream->readLine() ); + + if( !line.isEmpty() ) { + QString first = line.first(); + if( QString::compare( first, QString( "Dist" ) ) == 0 ) { + // we've encountered a new entry: + // first save the old one + if( entry != NULL ) { + // if this entry is for the current version we are running, + // then add it at the start of the list + if( QString::compare( *entry->dist_field, my_distro_name ) == 0) { + current_dist = entry; + metafile_entries->prepend( entry ); + } else { + metafile_entries->append( entry ); + } + } + // now create a new entry + line.pop_front(); + entry = new DistroEntry( new QString( line.first().stripWhiteSpace() ) ); + } + + else if( QString::compare( first, QString( "Name" ) ) == 0 ) { + if( entry != NULL ) { + line.pop_front(); + entry->name_field = new QString( line.first().stripWhiteSpace() ); + } + } + + else if( QString::compare( first, QString( "Version" ) ) == 0 ) { + if( entry != NULL ) { + line.pop_front(); + entry->version_field = new QString( line.first().stripWhiteSpace() ); + } + } + + else if( QString::compare( first, QString( "Date" ) ) == 0 ) { + if( entry != NULL ) { + line.pop_front(); + QString temp = line.join( QChar(' ') ).stripWhiteSpace(); + // get the day(verbal) + line = QStringList::split( QChar(' '), temp ); + QString day_verbal = line.first(); + day_verbal.truncate(3); + // get the date + line.pop_front(); + QString date = line.first(); + // get the month(verbal) + line.pop_front(); + QString month_verbal = line.first(); + // get the year + line.pop_front(); + QString year = line.first(); + // get the time + line.pop_front(); + QString time = line.first() + ":"; + line.pop_front(); + time += line.first() + ":"; + line.pop_front(); + time += line.first(); + + QDate the_date( QDate::fromString( day_verbal + " " + month_verbal + " " + date + " " + year) ); + QTime the_time( QTime::fromString( time ) ); + + entry->date_field = new QDateTime( the_date, the_time ); + } + } + + else if( QString::compare( first, QString( "Supported" ) ) == 0 ) { + if( entry != NULL ) { + line.pop_front(); + entry->supported_field = line.first().stripWhiteSpace().toInt(); + } + } + + else if( QString::compare( first, QString( "Description" ) ) == 0 ) { + if( entry != NULL ) { + line.pop_front(); + entry->desc_field = new QString( line.first().stripWhiteSpace() ); + } + } + + else if( QString::compare( first, QString( "Release-File" ) ) == 0 ) { + if( entry != NULL ) { + line.pop_front(); + QString http_part = line.first().stripWhiteSpace() + ":"; + line.pop_front(); + QString complete_url = http_part + line.first().stripWhiteSpace(); + entry->release_file_url = new KURL( complete_url ); + } + } + + else if( QString::compare( first, QString( "ReleaseNotes" ) ) == 0 ) { + if( entry != NULL ) { + line.pop_front(); + QString http_part = line.first().stripWhiteSpace() + ":"; + line.pop_front(); + QString complete_url = http_part + line.first().stripWhiteSpace(); + entry->release_notes_url = new KURL( complete_url ); + } + } + + else if( QString::compare( first, QString( "UpgradeTool" ) ) == 0 ) { + if( entry != NULL ) { + line.pop_front(); + QString http_part = line.first().stripWhiteSpace() + ":"; + line.pop_front(); + QString complete_url = http_part + line.first().stripWhiteSpace(); + entry->upgrade_tool_url = new KURL( complete_url ); + } + } + + else if( QString::compare( first, QString( "UpgradeToolSignature" ) ) == 0 ) { + if( entry != NULL ) { + line.pop_front(); + QString http_part = line.first().stripWhiteSpace() + ":"; + line.pop_front(); + QString complete_url = http_part + line.first().stripWhiteSpace(); + entry->upgrade_tool_sig_url = new KURL( complete_url ); + } + } + } + + + } + // add the last one + // if this entry is for the current version we are running, + // then add it at the start of the list + if( QString::compare( *entry->dist_field, my_distro_name ) == 0 ) { + current_dist = entry; + metafile_entries->prepend( entry ); + } else { + metafile_entries->append( entry ); + } + + return metafile_entries; +} + +// ** SLOTS ** // + +void UpgradeWizard::receiveDistroName( KProcess*, char *buffer, int buflen ) { + distro_name = QString::fromAscii( buffer, buflen-1 ); +} + +void UpgradeWizard::launchDistUpdater() { + QDir dir; + dir.mkdir(upgrade_tool_location+"-extract"); + + KTar tarFile(upgrade_tool_location, QString("application/x-gzip")); + tarFile.open(IO_ReadOnly); + //KArchiveDirectory* tarDirectory = tarFile.directory(); + //tarDirectory->copyTo(upgrade_tool_location+"-extract"); + tarFile.directory()->copyTo(upgrade_tool_location+"-extract", true); + + KProcess *proc = new KProcess; + proc->setWorkingDirectory(upgrade_tool_location+"-extract"); + *proc << "python" << upgrade_tool_location+"-extract/dist-upgrade.py"; + *proc << "--frontend" << "DistUpgradeViewKDE"; + proc->start( KProcess::DontCare ); + + // don't kill adept, it stops the app from running + // parentWidget()->close(); +} + +void UpgradeWizard::fetchReleaseAnnounce() { + QString temp_file_location; + bool result = false; + + if (upgrade_dist->release_notes_url == NULL) { + kdDebug() << "No release notes URL, so I'm skipping the fetch." << endl; + } else { + KURL my_url(*upgrade_dist->release_notes_url); + result = KIO::NetAccess::download(my_url, temp_file_location, NULL ); + } + + if( result ) { + emit killErrorDialog(); + err_dlg = NULL; + textBrowser1->mimeSourceFactory()->setExtensionType( QString("tmp"), "text/plain" ); + textBrowser1->setSource( temp_file_location ); + QWidget *p = page( pageCount()-2 ); + setNextEnabled( p, true ); + } else { + if(err_dlg == NULL ) { + err_dlg = new ErrorDialog( this, i18n( "Could not download the release announcement. Please check that your Internet connection is active." ), 0, 1 ); + connect( err_dlg->retryButton, SIGNAL( clicked() ), this, SLOT( fetchReleaseAnnounce() ) ); + connect( err_dlg->exitButton, SIGNAL( clicked() ), err_dlg, SLOT( close() ) ); + connect( err_dlg->exitButton, SIGNAL( clicked() ), this, SLOT( close() ) ); + connect( this, SIGNAL( killErrorDialog() ), err_dlg, SLOT( close() ) ); + err_dlg->show(); + } + } +} + +void UpgradeWizard::fetchUpgradeTool() { + // download the upgrade tool + KURL my_url(*upgrade_dist->upgrade_tool_url); + bool result = KIO::NetAccess::download( my_url, upgrade_tool_location, NULL ); + // uncomment this to use for testing if you don't want to d/l the file every time + //bool result = KIO::NetAccess::download( "/home/vladi/edgy.tar.gz", upgrade_tool_location, NULL ); + if( result ) { + emit killErrorDialog(); + err_dlg = NULL; + fetchUpgradeToolSig(); + } else { + if(err_dlg == NULL ) { + err_dlg = new ErrorDialog( this, i18n( "Could not download the upgrade tool. Please check that your Internet connection is active." ), 0, 1 ); + connect( err_dlg->retryButton, SIGNAL( clicked() ), this, SLOT( fetchUpgradeTool() ) ); + connect( err_dlg->exitButton, SIGNAL( clicked() ), err_dlg, SLOT( close() ) ); + connect( err_dlg->exitButton, SIGNAL( clicked() ), this, SLOT( close() ) ); + connect( this, SIGNAL( killErrorDialog() ), err_dlg, SLOT( close() ) ); + err_dlg->show(); + } + } +} + +void UpgradeWizard::fetchUpgradeToolSig() { + bool result = KIO::NetAccess::download( *upgrade_dist->upgrade_tool_sig_url, upgrade_tool_sig_location, NULL ); + if( result) { + emit killErrorDialog(); + err_dlg = NULL; + verifyUpgradeTool(); + } else { + if(err_dlg == NULL ) { + err_dlg = new ErrorDialog( this, i18n( "Could not download the upgrade tool's GPG signature. Please check that your Internet connection is active." ), 0, 1 ); + connect( err_dlg->retryButton, SIGNAL( clicked() ), this, SLOT( fetchUpgradeToolSig() ) ); + connect( err_dlg->exitButton, SIGNAL( clicked() ), err_dlg, SLOT( close() ) ); + connect( err_dlg->exitButton, SIGNAL( clicked() ), this, SLOT( close() ) ); + connect( this, SIGNAL( killErrorDialog() ), err_dlg, SLOT( close() ) ); + err_dlg->show(); + } + } +} + +void UpgradeWizard::verifyUpgradeTool() { + // spawn a process to call gpg and verify the signature + KProcess *proc = new KProcess; + *proc << "gpg"; + *proc << "--keyring" << "/etc/apt/trusted.gpg" << "--verify" << upgrade_tool_sig_location << upgrade_tool_location; + + proc->start( KProcess::Block, KProcess::Stdout ); + // signature verification successful if gpg exist status = 0 + if( proc->exitStatus() == 0 ) { + emit killErrorDialog(); + err_dlg = NULL; + // remove the signature file + KIO::file_delete( KURL( upgrade_tool_sig_location ), false ); + QWidget *p = page( pageCount()-1 ); + setFinishEnabled( p, true ); + textLabel3->show(); + } else { + if(err_dlg == NULL ) { + err_dlg = new ErrorDialog( this, i18n( "Could not verify the integrity of the upgrader application. This program will now exit." ), 0, 1 ); + //connect( err_dlg->retryButton, SIGNAL( clicked() ), this, SLOT( verify_upgrade_tool() ) ); + err_dlg->retryButton->setEnabled( false ); + connect( err_dlg->exitButton, SIGNAL( clicked() ), err_dlg, SLOT( close() ) ); + connect( err_dlg->exitButton, SIGNAL( clicked() ), this, SLOT( close() ) ); + connect( this, SIGNAL( killErrorDialog() ), err_dlg, SLOT( close() ) ); + err_dlg->show(); + } + } +} + +void UpgradeWizard::back() +{ + QWizard::back(); +} + +void UpgradeWizard::next() +{ + QWizard::next(); + + // page 1: d/l release announcement + // and display it on page1 + if( indexOf( currentPage() ) == 1 ) { + fetchReleaseAnnounce(); + } + else if( indexOf( currentPage() ) == 2 ) { + // remove the temp file used to store the release announcement + KIO::file_delete( KURL( textBrowser1->source() ), false ); + + // download the tool, its signature, and verify + fetchUpgradeTool(); + } +} + + + + +#include "upgradewizard.moc" + diff --git a/adept/kubuntu_upgrader/upgradewizard.h b/adept/kubuntu_upgrader/upgradewizard.h new file mode 100644 index 0000000..21b3f3c --- /dev/null +++ b/adept/kubuntu_upgrader/upgradewizard.h @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright (C) 2006 by Vladimir Stefan * + * vstefan85@gmail.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; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef UPGRADEWIZARD_H +#define UPGRADEWIZARD_H + +#include <adept/kubuntu_upgrader/upgradewizardbase.h> + +class QString; +class QTextIStream; +class QDateTime; +class KProcess; +class KURL; +class ErrorDialog; + +// ** Represents an entry in the metafile ** // +class DistroEntry { + public: + DistroEntry(QString *d_field); + ~DistroEntry(); + QString *dist_field; + QString *name_field; + QString *version_field; + QDateTime *date_field; + bool supported_field; + QString *desc_field; + KURL *release_file_url; + KURL *release_notes_url; + KURL *upgrade_tool_url; + KURL *upgrade_tool_sig_url; +}; + +class UpgradeWizard : public UpgradeWizardDlg +{ + Q_OBJECT + +public: + UpgradeWizard(QWidget* parent = 0, const char* name = 0, bool modal = FALSE, WFlags fl = 0 ); + ~UpgradeWizard(); + + /*$PUBLIC_FUNCTIONS$*/ + bool checkForDistUpgrade(bool skipIntrepid=true, QString url=QString(""), bool developmentVersion = false); + QPtrList<DistroEntry> *parseMetafile( QTextIStream *text_stream, + QString my_distro_name ); + +public slots: + /*$PUBLIC_SLOTS$*/ + void receiveDistroName( KProcess* p, char *buffer, int buflen ); + void launchDistUpdater(); + void fetchReleaseAnnounce(); + void fetchUpgradeTool(); + void fetchUpgradeToolSig(); + void verifyUpgradeTool(); + + + signals: + void killErrorDialog(); + +protected: + /*$PROTECTED_FUNCTIONS$*/ + void removeOldUpgradeTool(); + void removeDirectory(QString directoryName); + +protected slots: + /*$PROTECTED_SLOTS$*/ + virtual void back(); + virtual void next(); + +private: + QString upgrade_tool_location; + QString upgrade_tool_sig_location; + QString distro_name; + DistroEntry* upgrade_dist; + DistroEntry* current_dist; + ErrorDialog* err_dlg; +}; + +#endif + diff --git a/adept/kubuntu_upgrader/upgradewizardbase.ui b/adept/kubuntu_upgrader/upgradewizardbase.ui new file mode 100644 index 0000000..c2d1eee --- /dev/null +++ b/adept/kubuntu_upgrader/upgradewizardbase.ui @@ -0,0 +1,143 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>UpgradeWizardDlg</class> +<author>Vladimir Stefan</author> +<widget class="QWizard"> + <property name="name"> + <cstring>upgrade_wizard</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>584</width> + <height>446</height> + </rect> + </property> + <property name="caption"> + <string>Upgrade Wizard</string> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>WizardPage</cstring> + </property> + <attribute name="title"> + <string>Upgrade Wizard</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>A new distribution version is available! Click next if you wish to upgrade now.</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>271</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>WizardPage</cstring> + </property> + <attribute name="title"> + <string>Upgrade Wizard</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Release Announcement:</string> + </property> + </widget> + <widget class="QTextBrowser" row="1" column="0"> + <property name="name"> + <cstring>textBrowser1</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>WizardPage</cstring> + </property> + <attribute name="title"> + <string>Upgrade Wizard</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Downloading and verifying the upgrade tool ...</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Ready to upgrade! Click finish to close the Adept Package Manager and launch the distribution upgrade tool.</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <spacer row="2" column="0"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>231</height> + </size> + </property> + </spacer> + </grid> + </widget> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/adept/libadept/Makefile.am b/adept/libadept/Makefile.am new file mode 100644 index 0000000..810f516 --- /dev/null +++ b/adept/libadept/Makefile.am @@ -0,0 +1,33 @@ +noinst_LTLIBRARIES = libadept.la +libadept_la_SOURCES = \ + acqprogresswidgetui.ui acqprogress.cpp \ + tagchooser.cpp filtersidebarui.ui filtersidebar.cpp \ + application.cpp \ + tagfilterui.ui tagfilter.cpp taglist.cpp \ + packageinfoui.ui packageinfo.cpp \ + commitprogressui.ui commitprogress.cpp \ + progress.cpp \ + sourceseditorui.ui sourceseditor.cpp \ + acqprogresswidget.cpp dpkgpm.cpp \ + dpkgpm-gui.cpp \ + extendablelist.cpp \ + desktopentryui.ui desktoplist.cpp \ + groupeddesktopselector.cpp \ + packagedetailsui.ui packagedetails.cpp view.cpp \ + listerextenderui.ui lister.cpp filterlist.cpp \ + filterwidget.cpp \ + quickfilterui.ui quickfilter.cpp \ + statefilterui.ui statefilter.cpp \ + easytagfilterui.ui easytagfilter.cpp \ + actor.h threadutils.cpp \ + installerviewui.ui installerview.cpp +libadept_la_LDFLAGS = -L/usr/lib/debug $(all_libraries) +libadept_la_LIBADD = -lapt-front -ltagcoll + +INCLUDES = -I$(srcdir)/.. -I.. $(all_includes) $(LIBTAGCOLL2_CFLAGS) $(LIBAPT_FRONT_CFLAGS) +KDE_CXXFLAGS = $(USE_EXCEPTIONS) -DQT_NO_ASCII_CAST -DQT_NO_CAST_ASCII -DDEFAULT_KONSOLE_HIDDEN=true +METASOURCES = AUTO + +messages: rc.cpp + $(EXTRACTRC) `find . -name \*.ui -o -name \*.rc` > rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/libadept.pot diff --git a/adept/libadept/acqprogress.cpp b/adept/libadept/acqprogress.cpp new file mode 100644 index 0000000..4b0643f --- /dev/null +++ b/adept/libadept/acqprogress.cpp @@ -0,0 +1,295 @@ +// -*- C++ -*- + +#include <qprogressbar.h> +#include <klistview.h> +#include <kapplication.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qstyle.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kdebug.h> + +#include "acqprogress.h" +#include <apt-pkg/acquire-item.h> +#include <apt-pkg/acquire-worker.h> +#include <apt-pkg/strutl.h> +#include <apt-pkg/error.h> +#include <apt-pkg/configuration.h> + +#include <adept/utils.h> + +#include <stdio.h> +#include <signal.h> +#include <iostream> + +#define _(a...) (a) // XXX + +using namespace std; + +namespace adept { + +AcqStatus::Item::Item (KListView *parent, pkgAcquire::ItemDesc &item, bool hit) +: KListViewItem( parent ) +{ + m_pbcol = 0; + m_prog = new ItemProgress( 0, 0 ); + m_prog->setStatus( "waiting" ); + m_prog->setTotalSteps( 100 ); + m_item = item; + m_id = m_item.Owner->ID; + /* if (item.Owner->FileSize > 0) + setText( 1, SizeToStr( item.Owner->FileSize ).c_str() + QString( "B" ) ); */ + setText( 1, u8( item.Description ) ); + // cerr << "create: id = " << item . Owner -> ID << ", myId = " << m_item . Owner -> ID << endl; + if (hit) { + m_prog->setStatus( "hit" ); + } else + m_prog->setStatus( "waiting" ); + // QString (SizeToStr (Itm.Owner -> FileSize) . c_str ()) + QString ("B"), + // /* QString (Itm . Owner -> ID) + */ QString (Itm.Description . c_str ())); +} + +AcqStatus::Item::~Item () +{ + delete m_prog; +} + +int AcqStatus::Item::compare (QListViewItem *i, int /*col*/, bool /*ascend*/) const +{ + int id1 = m_id; + int id2 = ((Item *) i) -> m_id; + return (id2 >= id1) - (id2 <= id1); +} + +void AcqStatus::Item::pulse (pkgAcquire::Worker *w) +{ + if (w) { + if (w->TotalSize) + setStatus( "progress", long( double( + w -> CurrentSize * 100.0) + / double( w->TotalSize ) ) ); + else + setStatus( "downloading", 0 ); + } +} + +void AcqStatus::Item::setStatus( const std::string &s, int i ) +{ + m_prog->setStatus( s, i ); +} + +void AcqStatus::Item::paintCell (QPainter *p, const QColorGroup &cg, + int column, int width, int alignment ) +{ + QColorGroup _cg( cg ); + QColor c = _cg.text(); + + if ( column == m_pbcol ) { + const QRect bar = QRect( 0, 0, width, height() ); + m_prog->resize( width, height() ); + QPixmap pm = QPixmap::grabWidget( m_prog ); + // p->fillRect( bar, listView()->paletteBackgroundColor() ); + p->drawPixmap( bar.x(), bar.y(), pm ); + } else { + QPixmap pm( width, height() ); + QPainter _p( &pm ); + _cg.setColor( QColorGroup::Text, c ); + KListViewItem::paintCell( &_p, _cg, column, width, alignment ); + p->drawPixmap( 0, 0, pm ); + } +} + +AcqStatus::Item *AcqStatus::findItem (pkgAcquire::ItemDesc &Itm) +{ + if ( Itm.Owner->ID < m_idOffset ) + return 0; + if ( Itm.Owner->ID - m_idOffset >= m_items.size() ) + return 0; + return m_items[ Itm.Owner->ID - m_idOffset ]; +} + +AcqStatus::AcqStatus(QWidget *parent, const char *name) + : KListView (parent, name), m_idOffset( 0 ), m_continue( true ) +{ + // m_lastItem = 0; + addColumn( i18n( "Progress" ) ); + addColumn( i18n( "Description" ) ); + setSorting (1); + setColumnWidth (0, 220); + setColumnWidth (1, 300); + setResizeMode (LastColumn); + ID = 0; +} + +void AcqStatus::Done (pkgAcquire::ItemDesc &Itm) +{ + Item *i = findItem (Itm); + if (i) { + i->setStatus( "done" ); + } + emit statusChanged( StWaiting ); + triggerUpdate(); + KApplication::kApplication()->processEvents(); +} + +void AcqStatus::clear() +{ + KListView::clear(); + m_idOffset += m_items.size(); + m_items.clear(); // got deleted by klistview already +} + +void AcqStatus::Start() +{ + clear(); + pkgAcquireStatus::Start(); + kdDebug() << "AcqStatus::Start ()" << endl; + _config -> Set ("APT::Fetcher::Select-Timeout-Usec", 100000); + emit statusChanged( StWaiting ); + triggerUpdate(); + KApplication::kApplication()->processEvents(); +} + +void AcqStatus::IMSHit(pkgAcquire::ItemDesc &Itm) +{ + Itm.Owner->ID = ID++; + Item *i = new Item( this, Itm, true ); + // ensureItemVisible( i ); + i->setStatus( "hit" ); + m_items.push_back( i ); + + kdDebug() << "imshit called on ID = " << ID - 1 << " i = " << (void *)i << endl; + triggerUpdate(); + KApplication::kApplication()->processEvents(); +}; + +void AcqStatus::Fetch(pkgAcquire::ItemDesc &Itm) + // an item started to download +{ + Update = true; + if (Itm.Owner->Complete == true) // XXX? + return; + + Itm.Owner->ID = ID++; + + Item *i = new Item( this, Itm ); + // ensureItemVisible( i ); + m_items.push_back( i ); + + kdDebug() << "fetch called on ID = " << ID - 1 << " i = " << (void *)i << endl; + emit statusChanged( StDownloading ); + triggerUpdate(); + KApplication::kApplication()->processEvents(); +}; + +void AcqStatus::Fail(pkgAcquire::ItemDesc &Itm) + // item failed to download +{ + kdDebug() << "fail, status = " << Itm.Owner->Status + << " ID = " << Itm.Owner->ID << endl; + // Ignore certain kinds of transient failures (bad code) + if (Itm.Owner->Status == pkgAcquire::Item::StatIdle) { + kdDebug() << "fail with StatIdle, ignoring" << endl; + return; + } + + Item *i = findItem (Itm); + kdDebug() << "fail, i = " << i << endl; + if (! i) + return; + if (Itm.Owner->Status == pkgAcquire::Item::StatDone) { + i->setStatus( "ignored" ); + } else { + i->setStatus( "error" ); + } + + triggerUpdate(); + KApplication::kApplication()->processEvents(); +}; + +void AcqStatus::Stop() +{ + pkgAcquireStatus::Stop(); + emit statusChanged( StDone ); + triggerUpdate (); + KApplication::kApplication()->processEvents(); +} + +bool AcqStatus::Pulse(pkgAcquire *Owner) +{ + pkgAcquireStatus::Pulse(Owner); + + for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0; + I = Owner->WorkerStep(I)) { + if (I -> CurrentItem) { + Item *i = findItem (* (I -> CurrentItem)); + if (i) + i -> pulse (I); + } + } + + triggerUpdate (); + // repaint (); + + if (TotalBytes > 0) + emit totalProgress( + long( double( + (CurrentBytes + + CurrentItems)*100.0)/double(TotalBytes+TotalItems) ) ); + else + emit totalProgress (-1); + KApplication::kApplication () -> processEvents (); + + if ( m_continue ) + return true; + + m_continue = true; + return false; +} + +bool AcqStatus::MediaChange(string Media,string Drive) +{ + int res = KMessageBox::warningContinueCancel( + this, i18n( "Please insert the disc " + "labeled '%1' in the drive " + "'%2' and press enter" ).arg( + u8( Media ) ).arg( u8( Drive ) ), + i18n( "Media Change" ) ); + if ( res == KMessageBox::Cancel ) + cancel(); + return true; +} + +void AcqStatus::cancel() +{ + m_continue = false; +} + +AcqStatusDialog::AcqStatusDialog (QWidget *parent, const char *name, bool modal) + : KDialogBase( parent, name, modal, + u8( "progress dialog (FIXME: waiting for headers, done)" ), + Ok|Cancel, Cancel, true ) +{ + m_status = new AcqStatus (this, ""); + setMainWidget( m_status.data() ); + enableButton (Ok, false); + connect (m_status.data(), SIGNAL (statusChanged (AcqStatus::Status)), + this, SLOT (statusChange (AcqStatus::Status))); +} + +void AcqStatusDialog::statusChange (AcqStatus::Status st) +{ + if (st == AcqStatus::StDownloading || st == AcqStatus::StWaiting) { + enableButton (Ok, false); + // XXX: cancel should be true; but needs implementation first + enableButton (Cancel, false); + } else if (st == AcqStatus::StDone) { + enableButton (Ok, true); + enableButton (Cancel, false); + } +} + +} + +#include "acqprogress.moc" diff --git a/adept/libadept/acqprogress.h b/adept/libadept/acqprogress.h new file mode 100644 index 0000000..9510825 --- /dev/null +++ b/adept/libadept/acqprogress.h @@ -0,0 +1,127 @@ +/** -*- C++ -*- + @file adept/acqprogress.h + @author Peter Rockai <me@mornfall.net> +*/ + +#ifndef ACQPROGRESS_H +#define ACQPROGRESS_H + +#include <klocale.h> +#include <kdialogbase.h> +#include <klistview.h> +#include <kprogress.h> + +#include <vector> +#include <apt-pkg/acquire.h> +#include <apt-front/progresscallback.h> + +class AcqStatus; +class QLabel; +class QProgressBar; +class QSpacer; +class QGridLayout; + +namespace adept { + +class AcqStatus : public KListView, public aptFront::ProgressCallback +{ + Q_OBJECT +protected: + class ItemProgress: public KProgress { + public: + ItemProgress( QWidget *parent, const char *name = 0 ) + : KProgress( parent, name ), m_spin( 0 ) {} + void setStatus( const std::string &s, + int prog = 0 ) { + m_status = s; + if (m_status == "hit" + || m_status == "ignored" + || m_status == "done") + prog = 100; + if (m_status == "waiting") { + prog = 0; + } + if (m_status == "progress" && prog != 100) + setFormat( i18n( "downloading (%p%)" ) ); + else if (prog == 100) // who cares about hit/ignore anyway? + setFormat( i18n( "done (%p%)" ) ); + else + setFormat( m_status ); + setProgress( prog ); + } + protected: + std::string m_status; + int m_spin; + }; + class Item : public KListViewItem { + protected: + ItemProgress *m_prog; + int m_pbcol; + unsigned long m_id; + pkgAcquire::ItemDesc m_item; + + public: + Item (KListView *parent, pkgAcquire::ItemDesc &item, + bool hit = false); + virtual ~Item (); + + virtual void paintCell (QPainter *p, const QColorGroup &cg, + int column, int width, int alignment); + + void setProgress (int); + virtual int compare (QListViewItem *i, int col, bool ascend) const; + virtual void pulse (pkgAcquire::Worker *); + void setStatus( const std::string &, int = 0 ); + + void setup() { + KListViewItem::setup(); + setHeight( height() + 6 ); + } + }; + unsigned long ID; + unsigned long m_idOffset; + std::vector <Item *> m_items; + bool m_continue; + +public: + + enum Status { StWaiting, StDownloading, StDone }; + + AcqStatus (QWidget *parent, const char *name); + Item *findItem (pkgAcquire::ItemDesc &Itm); + + virtual bool MediaChange (string Media,string Drive); + virtual void IMSHit (pkgAcquire::ItemDesc &Itm); + virtual void Fetch (pkgAcquire::ItemDesc &Itm); + virtual void Done (pkgAcquire::ItemDesc &Itm); + virtual void Fail (pkgAcquire::ItemDesc &Itm); + virtual void Start (); + virtual void Stop (); + void addLine (QWidget *l, QWidget *s, QWidget *prog); + void clear(); + + bool Pulse (pkgAcquire *Owner); + +public slots: + void cancel(); + +signals: + void statusChanged (AcqStatus::Status st); + void totalProgress (int percent); + + //AcqTextStatus(unsigned int &ScreenWidth,unsigned int Quiet); +}; + +class AcqStatusDialog : public KDialogBase +{ + Q_OBJECT +protected: + aptFront::SharedPtr<AcqStatus> m_status; +public: + aptFront::SharedPtr<aptFront::ProgressCallback> callback() { return m_status.data(); }; + AcqStatusDialog (QWidget *parent, const char *name, bool modal); +public slots: + void statusChange (AcqStatus::Status st); +}; +} +#endif diff --git a/adept/libadept/acqprogresswidget.cpp b/adept/libadept/acqprogresswidget.cpp new file mode 100644 index 0000000..dd02f03 --- /dev/null +++ b/adept/libadept/acqprogresswidget.cpp @@ -0,0 +1,53 @@ +#include <kprogress.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <klocale.h> +#include "acqprogresswidget.h" +#include "acqprogress.h" + +using namespace adept; + +AcqProgressWidget::AcqProgressWidget( QWidget *parent, const char *name ) + : AcqProgressWidgetUi( parent, name ) +{ + m_statusRef = m_status; + m_progress->setTotalSteps( 100 ); + m_progress->setProgress( 0 ); + connect(m_status, SIGNAL( totalProgress( int ) ), + this, SLOT( setProgress( int ) ) ); + connect(m_status, SIGNAL( statusChanged( AcqStatus::Status ) ), + this, SLOT( statusChange( AcqStatus::Status ) ) ); + connect( m_cancel, SIGNAL( clicked() ), + m_status, SLOT( cancel() ) ); +} + +void AcqProgressWidget::statusChange( AcqStatus::Status s ) +{ + QString t; + switch (s) { + case AcqStatus::StWaiting: + t = i18n( "Waiting for headers (%p%)" ); + break; + case AcqStatus::StDownloading: + t = i18n( "Downloading (%p%)" ); + break; + case AcqStatus::StDone: + t = i18n( "Done (%p%)" ); + m_progress->setProgress( 100 ); + break; + } + m_progress->setFormat( t ); +} + +void AcqProgressWidget::setProgress( int p ) +{ + if (p < 0) { + m_progress->setTotalSteps( 0 ); + m_progress->setProgress( m_progress->progress() + 1 ); + } else { + m_progress->setTotalSteps( 100 ); + m_progress->setProgress( p ); + } +} + +#include "acqprogresswidget.moc" diff --git a/adept/libadept/acqprogresswidget.h b/adept/libadept/acqprogresswidget.h new file mode 100644 index 0000000..54359c7 --- /dev/null +++ b/adept/libadept/acqprogresswidget.h @@ -0,0 +1,30 @@ +/** -*- C++ -*- + @file adept/acqprogresswidget.h + @author Peter Rockai <me@mornfall.net> + @todo Close button! +*/ + +#ifndef PROGRESSWIDGET_H +# define PROGRESSWIDGET_H + +#include <adept/acqprogresswidgetui.h> +#include <adept/acqprogress.h> + +namespace adept { + +class AcqProgressWidget : public AcqProgressWidgetUi { + Q_OBJECT +public: + AcqProgressWidget (QWidget *parent = 0, const char *name = 0); + aptFront::SharedPtr<aptFront::ProgressCallback> callback() { return m_statusRef.data(); }; +public slots: + void statusChange( AcqStatus::Status ); + void setProgress( int ); +protected: + aptFront::SharedPtr<AcqStatus> m_statusRef; +}; + +} + +#endif /* ifndef PROGRESSWIDGET_H */ + diff --git a/adept/libadept/acqprogresswidgetui.ui b/adept/libadept/acqprogresswidgetui.ui new file mode 100644 index 0000000..26baa21 --- /dev/null +++ b/adept/libadept/acqprogresswidgetui.ui @@ -0,0 +1,79 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::AcqProgressWidgetUi</class> +<widget class="QWidget"> + <property name="name"> + <cstring>adept::AcqProgressWidgetUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>705</width> + <height>289</height> + </rect> + </property> + <property name="caption"> + <string>Download Progress</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="adept::AcqStatus" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_status</cstring> + </property> + <property name="minimumSize"> + <size> + <width>300</width> + <height>150</height> + </size> + </property> + </widget> + <widget class="KProgress" row="1" column="0"> + <property name="name"> + <cstring>m_progress</cstring> + </property> + </widget> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>m_cancel</cstring> + </property> + <property name="text"> + <string>Cancel Download</string> + </property> + </widget> + </grid> +</widget> +<customwidgets> + <customwidget> + <class>adept::AcqStatus</class> + <header location="global">acqprogress.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</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="PNG" length="1002">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082</data> + </image> +</images> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>adept/acqprogress.h</includehint> + <includehint>kprogress.h</includehint> +</includehints> +</UI> diff --git a/adept/libadept/actor.h b/adept/libadept/actor.h new file mode 100644 index 0000000..115b202 --- /dev/null +++ b/adept/libadept/actor.h @@ -0,0 +1,43 @@ +/** -*- C++ -*- + @file adept/actor.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qobject.h> +#include <apt-front/cache/entity/entity.h> +#include <apt-front/actor.h> + +#ifndef EPT_ACTOR_H +#define EPT_ACTOR_H + +namespace adept { + +using namespace aptFront; + +class EntityActor : public QObject +{ + Q_OBJECT +public: + EntityActor( actor::Bound< cache::entity::Entity > a ) + : m_actor( a ), m_dead( false ) + {} + actor::Bound< cache::entity::Entity > actor() const { + return m_actor; + } +public slots: + void act() { m_actor(); } + void destructiveAct() { + // in case we don't get deleted soon enough + if ( m_dead ) return; + m_dead = true; + act(); + deleteLater(); + } +protected: + actor::Bound< cache::entity::Entity > m_actor; + bool m_dead; +}; + +} + +#endif diff --git a/adept/libadept/application.cpp b/adept/libadept/application.cpp new file mode 100644 index 0000000..8388fa2 --- /dev/null +++ b/adept/libadept/application.cpp @@ -0,0 +1,197 @@ +/** -*- C++ -*- + @file adept/application.cpp + @author Peter Rockai <me@mornfall.net> +*/ + +#include <kmessagebox.h> +#include <klocale.h> +#include <kapplication.h> +#include <kstatusbar.h> + +#include <apt-front/init.h> +#include <apt-front/cache/component/packages.h> +#include <apt-front/cache/component/state.h> + +#include <adept/commitprogress.h> +#include <adept/application.h> +#include <adept/packageinfo.h> +#include <adept/progress.h> +#include <adept/utils.h> + +namespace adept { +using namespace cache; + +/* void WaitForLister::waiting() +{ + kdDebug() << "WaitForLister::waiting()" << endl; + bool done = true; + for ( Vector::iterator i = listers.begin(); i != listers.end(); ++i ) { + if ( (*i)->busy() ) { + done = false; + break; + } + } + if ( listers.empty() ) done = false; + if ( done ) { + QTimer::singleShot( 0, app, slot ); + deleteLater(); + } else { + QTimer::singleShot( 100, this, SLOT( waiting() ) ); + } + } */ + +Application::Application() + : m_acceptReadOnly( false ), m_main( 0 ), m_history( 0 ), m_statusBar( 0 ) +{ +} + +void Application::openCache( unsigned flags ) +{ + bool ro = m_acceptReadOnly; + bool root = ::getuid() == 0 || ::geteuid() == 0; + try { + cache::Global::get().open( flags ); + } catch (...) { + try { + cache::Global::get().open( flags | Cache::OpenReadOnly ); + if ( ro && root ) { + KMessageBox::information( + m_main, i18n( + "You will not be able to change your system settings " + "in any way (install, remove or upgrade software), " + "because another process is using the packaging system database " + "(probably some other Adept application or apt-get or " + "aptitude). Please close the other application before " + "using this one." ), + i18n( "Read Only mode: Database Locked" ) ); + } else if ( !root && ro ) { + KMessageBox::information( + m_main, i18n( + "You will not be able to change your system settings " + "in any way (install, remove or upgrade software), " + "because this application needs special administrator " + "(root) privileges. Please run it as root or " + "through kdesu or sudo programs to be able to perform " + "these actions" ), + i18n( "Read Only mode: Need root privileges" ) ); + } else if ( root && !ro ) { + KMessageBox::information( + m_main, i18n( + "Another process is using the packaging system database " + "(probably some other Adept application or apt-get or " + "aptitude). Please close the other application before " + "using this one." ), + i18n( "Database Locked" ) ); + } else if ( !root && !ro ) { + KMessageBox::information( + m_main, i18n( "This application needs special administrator " + "(root) privileges. Please run it as root or " + "through kdesu or sudo programs" ), + i18n( "Need root privileges" ) ); + } + if ( !ro ) { + kdDebug() << "cannot continue, exiting" << endl; + exit( 1 ); + } + } catch (...) { + KMessageBox::sorry( + m_main, i18n( + "The APT Database could not be opened!" + " This may be caused by incorrect APT configuration" + " or some similar problem. Try running apt-setup and" + " apt-get update in terminal and see if it helps" + " to resolve the problem." ), i18n( "Could not open cache" ) ); + exit( 1 ); + } + } +} + +void Application::initHistory() { + cache::Global::get().addComponent( + m_history = new History() ); +} + +void Application::initKDEDebconf() +{ + // xxx unhardcode the package name somehow? + if (cache::Global::get().packages() + .packageByName( "libqt-perl" ).isInstalled()) + putenv( "DEBIAN_FRONTEND=kde" ); +} + +void Application::initialize() +{ + CommitProgress::initSystem(); + aptFront::init(); + openCache(); + initKDEDebconf(); + initHistory(); + observeComponent< component::State >(); +} + +void Application::checkpoint() { + if ( !history() ) return; + setHistoryEnabled( false ); + history()->checkpoint(); + setHistoryEnabled( true ); +} + +void Application::undo() { + if ( !history() ) return; + setHistoryEnabled( false ); + history()->undo(); + setHistoryEnabled( true ); +} + +void Application::redo() { + if ( !history() ) return; + setHistoryEnabled( false ); + history()->redo(); + setHistoryEnabled( true ); +} + +QString Application::changeString() { + component::State &s = cache().state(); + return i18n( " Install %1, upgrade %2, remove %3 " ) + .arg( s.newInstallCount() ).arg( s.upgradeCount() ) + .arg( s.removeCount() ); +} + +QString Application::statusString() { + component::State &s = cache().state(); + return i18n( " %1 installed, %2 upgradable, %3 available " ) + .arg( s.installedCount() ).arg( s.upgradableCount() ) + .arg( s.availableCount() ); +} + +QString Application::sizesString() { + QString dl = cache().state().downloadSizeString(); + QString inst = cache().state().installSizeString(); + return i18n( " download: %1, installation: %2 " ).arg( dl ).arg( inst ); +} + +void Application::setStatusBar( KStatusBar *s ) { + m_statusBar = s; + if ( s ) { + s->message( i18n( "Initializing..." ) ); + s->insertItem( u8( "" ), 0 ); + s->insertItem( u8( "" ), 1 ); + s->insertItem( u8( "" ), 2 ); + adjustFontSize( s, -1 ); + + adept::Progress *pr = new adept::Progress(); + pr->setStatusBar( s ); + cache::Global::get().setProgress( pr ); + } +} + +void Application::notifyPostChange( component::Base * ) +{ + if ( m_statusBar ) { + m_statusBar->changeItem( changeString(), 0 ); + m_statusBar->changeItem( statusString(), 1 ); + m_statusBar->changeItem( sizesString(), 2 ); + } +} + +} diff --git a/adept/libadept/application.h b/adept/libadept/application.h new file mode 100644 index 0000000..74e9506 --- /dev/null +++ b/adept/libadept/application.h @@ -0,0 +1,75 @@ +/** -*- C++ -*- + @file adept/application.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <vector> + +#include <qobject.h> + +#include <apt-front/cache/cache.h> +#include <apt-front/cache/component/state.h> +#include <apt-front/cache/component/history.h> + +#ifndef EPT_APPLICATION_H +#define EPT_APPLICATION_H + +class KStatusBar; + +namespace adept { +using namespace aptFront; +using cache::Cache; + +class Lister; + +struct Application : cache::Observer { + Application(); + void setAcceptReadOnly( bool ro ) { m_acceptReadOnly = ro; } + bool writeable() { return cache::Global::get().writeable(); } + Cache &cache() { return cache::Global::get(); } + void openCache( unsigned flags = Cache::OpenDefault | Cache::OpenDebtags ); + void initialize(); + void initKDEDebconf(); + void initHistory(); + void setMainWidget( QWidget *w ) { m_main = w; } + void setStatusBar( KStatusBar *s ); + virtual void checkpoint(); + virtual void undo(); + virtual void redo(); + + virtual void notifyPostChange( cache::component::Base * ); + + QString changeString(); + QString statusString(); + QString sizesString(); +protected: + virtual void setHistoryEnabled( bool ) {} + typedef cache::component::History< cache::component::State > History; + virtual History *history() { return m_history; } + bool m_acceptReadOnly; + QWidget *m_main; + KStatusBar *m_statusBar; + History *m_history; +}; + +/* class WaitForLister : public QObject { + Q_OBJECT +public: + WaitForLister( QObject *a, const char *s ) + : obj( a ), slot( s ) + { + waiting(); + } + void addLister( Lister *l ) { listers.push_back( l ); } +protected slots: + void waiting(); +protected: + QObject *obj; + const char *slot; + typedef std::vector< Lister * > Vector; + Vector listers; + }; */ + +} + +#endif diff --git a/adept/libadept/commitprogress.cpp b/adept/libadept/commitprogress.cpp new file mode 100644 index 0000000..9100d9b --- /dev/null +++ b/adept/libadept/commitprogress.cpp @@ -0,0 +1,115 @@ +#include <cassert> + +#include <qwidgetstack.h> +#include <qpushbutton.h> +#include <qlabel.h> +#include <kprogress.h> +#include <qlayout.h> +#include <qtimer.h> + +#include <klocale.h> +#include <kdebug.h> +#include <ktrader.h> +#include <klibloader.h> + +#include <apt-front/init.h> +#include <adept/commitprogress.h> +#include <adept/utils.h> + +using namespace adept; +using namespace aptFront; + +PkgSystem *CommitProgress::s_system = 0; + +void CommitProgress::initSystem() { + CommitProgress::s_system = new PkgSystem(); +} + +CommitProgress::CommitProgress( QWidget *p, const char *n ) + : CommitProgressUi( p, n ) +{ + assert( s_system ); + m_konsoleFrame->installEventFilter( this ); + loadKonsole(); + connect( s_system, SIGNAL( statusChanged( int, QString ) ), + this, SLOT( updateProgress( int, QString ) ) ); + connect( m_details, SIGNAL( clicked() ), + this, SLOT( toggleDetails() ) ); + m_progress->setTotalSteps( 100 ); +} + +bool CommitProgress::eventFilter( QObject *o, QEvent *e ) { + // o == m_konsoleFrame + if ( e->type() == QEvent::Resize ) { + QResizeEvent *re = dynamic_cast< QResizeEvent * >( e ); + if ( !re ) return false; + m_konsole->widget()->setGeometry( 0, 0, re->size().width(), re->size().height() ); + m_occlude->setGeometry( 0, 0, re->size().width(), re->size().height() ); + } + return false; +}; + +void CommitProgress::toggleDetails() +{ + if ( !m_occlude->isVisible() ) { + // if ( m_stack->visibleWidget() == m_konsole->widget() ) { // hide + // m_stack->raiseWidget( m_emptyPage ); + m_occlude->show(); + m_bottomSpace->changeSize( 10, 10, QSizePolicy::Fixed, QSizePolicy::Expanding ); + m_details->setText( i18n( "Show Details" ) ); + } else { // show + m_occlude->hide(); + // m_stack->raiseWidget( m_konsole->widget() ); + m_bottomSpace->changeSize( 10, 10, QSizePolicy::Fixed, QSizePolicy::Fixed ); + m_details->setText( i18n( "Hide Details" ) ); + } +} + +void CommitProgress::updateProgress( int p, QString msg ) +{ + m_operation->setText( msg ); + m_progress->setProgress( p ); +} + +void CommitProgress::loadKonsole() +{ + if ( s_system->terminal() ) + kdDebug() << "WARNING: Hijacking PkgSystem terminal" << endl; + + KLibFactory* factory = KLibLoader::self()->factory( "libsanekonsolepart" ); + if (!factory) + factory = KLibLoader::self()->factory( "libkonsolepart" ); + + assert( factory ); + + delete m_occlude; + m_konsole = static_cast<KParts::Part*>( + factory->create( m_konsoleFrame, "konsolepart", "QObject", + u8( "KParts::ReadOnlyPart" ) ) ); + // m_konsole->widget()->setGeometry( QRect( 0, 0, 40, 40 ) ); + + m_occlude = new QFrame( m_konsoleFrame, "m_occlude" ); + // m_occlude->setGeometry( QRect( 0, 0, 10, 10 ) ); + m_occlude->setFrameShape( QFrame::NoFrame ); + + assert( terminal() ); + + terminal()->setAutoDestroy( false ); + terminal()->setAutoStartShell( false ); + // m_stack->addWidget( m_konsole->widget() ); + + QStrList l; l.append( "echo" ); l.append( "-n" ); + terminal()->startProgram( u8( "/bin/echo" ), l ); + + s_system->setTerminal( m_konsole ); + + // m_stack->raiseWidget( m_konsole->widget() ); + // m_konsole->widget()->show(); + // m_stack->raiseWidget( m_emptyPage ); + m_operation->setText( i18n( "Idle" ) ); + QTimer::singleShot( 0, this, SLOT( toggleDetails() ) ); + if ( DEFAULT_KONSOLE_HIDDEN ) + QTimer::singleShot( 0, this, SLOT( toggleDetails() ) ); + QTimer::singleShot( 0, this, SLOT( hide() ) ); +} + diff --git a/adept/libadept/commitprogress.h b/adept/libadept/commitprogress.h new file mode 100644 index 0000000..ed557d7 --- /dev/null +++ b/adept/libadept/commitprogress.h @@ -0,0 +1,41 @@ +/* -*- C++ -*- file adept/commitprogress.h + written by Peter Rockai <me@mornfall.net> */ + +#include <kde_terminal_interface.h> +#include <adept/dpkgpm-gui.h> +#include <adept/commitprogressui.h> +#include <kparts/part.h> + +#ifndef EPT_COMMITPROGRESS_H +#define EPT_COMMITPROGRESS_H + +namespace adept { + +class CommitProgress : public CommitProgressUi +{ + Q_OBJECT +public: + CommitProgress( QWidget *p = 0, const char *n = 0 ); + + ExtTerminalInterface *terminal() { + return static_cast<ExtTerminalInterface*>( + m_konsole->qt_cast( "ExtTerminalInterface" ) ); + } + + // needs to be called before aptFront::init() :'(( + static void initSystem(); + virtual bool eventFilter( QObject *o, QEvent *e ); + +public slots: + void updateProgress( int p, QString msg ); + void toggleDetails(); +protected: + void loadKonsole(); + KParts::Part *m_konsole; + static adept::PkgSystem *s_system; // bla... +}; + +} + + +#endif diff --git a/adept/libadept/commitprogressui.ui b/adept/libadept/commitprogressui.ui new file mode 100644 index 0000000..5ccecbf --- /dev/null +++ b/adept/libadept/commitprogressui.ui @@ -0,0 +1,197 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::CommitProgressUi</class> +<widget class="QWidget"> + <property name="name"> + <cstring>CommitProgressUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>542</width> + <height>303</height> + </rect> + </property> + <property name="caption"> + <string>Form1</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>1</number> + </property> + <widget class="QFrame"> + <property name="name"> + <cstring>m_konsoleFrame</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <widget class="QFrame"> + <property name="name"> + <cstring>m_occlude</cstring> + </property> + <property name="geometry"> + <rect> + <x>40</x> + <y>10</y> + <width>460</width> + <height>60</height> + </rect> + </property> + <property name="frameShape"> + <enum>StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + </widget> + </widget> + <spacer> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>m_details</cstring> + </property> + <property name="text"> + <string>(details)</string> + </property> + </widget> + <widget class="KProgress" row="1" column="0"> + <property name="name"> + <cstring>m_progress</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_operation</cstring> + </property> + <property name="text"> + <string>Preparing...</string> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>m_bottomSpace</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>80</height> + </size> + </property> + </spacer> + <spacer> + <property name="name"> + <cstring>spacer6_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>32</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kprogress.h</includehint> +</includehints> +</UI> diff --git a/adept/libadept/desktopentryui.ui b/adept/libadept/desktopentryui.ui new file mode 100644 index 0000000..a40c766 --- /dev/null +++ b/adept/libadept/desktopentryui.ui @@ -0,0 +1,116 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::DesktopEntryUi</class> +<widget class="adept::ItemExtender"> + <property name="name"> + <cstring>DesktopEntryUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>509</width> + <height>52</height> + </rect> + </property> + <property name="caption"> + <string>Form1</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>6</number> + </property> + <property name="spacing"> + <number>5</number> + </property> + <widget class="QLabel" row="0" column="1" rowspan="2" colspan="1"> + <property name="name"> + <cstring>m_icon</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QCheckBox" row="0" column="0" rowspan="2" colspan="1"> + <property name="name"> + <cstring>m_check</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> + </widget> + <widget class="QLabel" row="0" column="3"> + <property name="name"> + <cstring>m_name</cstring> + </property> + <property name="text"> + <string>(name)</string> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel" row="1" column="3"> + <property name="name"> + <cstring>m_description</cstring> + </property> + <property name="text"> + <string>(description)</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <spacer row="0" column="2" rowspan="2" colspan="1"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>6</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> +</widget> +<includes> + <include location="global" impldecl="in declaration">adept/extendablelist.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/adept/libadept/desktoplist.cpp b/adept/libadept/desktoplist.cpp new file mode 100644 index 0000000..de64f11 --- /dev/null +++ b/adept/libadept/desktoplist.cpp @@ -0,0 +1,194 @@ +/** -*- C++ -*- + @file adept/desktoplist.cpp + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qimage.h> +#include <qlabel.h> +#include <qcursor.h> +#include <qcheckbox.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <kapplication.h> +#include <klocale.h> +#include <kdebug.h> + +#include <adept/desktoplist.h> +#include <adept/utils.h> + +namespace adept { + +DesktopEntry::DesktopEntry( QWidget *p, const char *n ) + : DesktopEntryUi( p, n ) +{ + adjustFontSize( m_description, -1 ); +} + +void DesktopEntry::resize( int w, int h ) +{ + // kdDebug() << "DesktopEntry::resize( " << w << ", " << h << " )" << endl; + int margin = layout()->margin() + layout()->spacing() * 2 + + 6 /* spacer */ + m_icon->width() + m_check->width(); + if ( m_check->isVisible() ) margin += m_check->width() + layout()->spacing(); + int hFW1 = m_name->heightForWidth( w - margin ); + int hFW2 = m_description->heightForWidth( w - margin ); + /* kdDebug() << "margin = " << margin << ", hFW1 = " << hFW1 << ", hFW2 = " + << hFW2 << endl; */ + int height = 2 * layout()->margin() + layout()->spacing() + hFW1 + hFW2; + if ( height < 32 + 2*layout()->margin() /* icon size + margin */ ) + height = 32 + 2*layout()->margin(); + // m_description->resize( w - margin, m_description->heightForWidth( w - margin ) ); + QWidget::resize( w, height ); +} + +void DesktopEntry::setItem( ExtendableItem *i ) { + m_polished = false; + ItemExtender::setItem( i ); + m_name->setText( u8( "<b>" ) + u8( entity().name() ) + u8( "</b>" ) ); + m_description->setText( u8( entity().description() ) ); + if ( !item()->list()->displayCheckboxes() ) { + m_check->hide(); + } + if ( !package().valid() || !package().hasVersion() ) { + setEnabled( false ); + } else { + connect( m_check, SIGNAL( toggled( bool ) ), + this, SLOT( toggled() ) ); + notifyPostChange(); + } +} + +void DesktopEntry::mousePressEvent( QMouseEvent *e ) { + kdDebug() << "DesktopEntry::mousePressEvent" << endl; + e->ignore(); +} + +void DesktopEntry::mouseReleaseEvent( QMouseEvent *e ) { + kdDebug() << "DesktopEntry::mouseReleaseEvent" << endl; + e->ignore(); +} + +void DesktopEntry::showEvent( QShowEvent *e ) { + DesktopEntryUi::showEvent( e ); + // DesktopEntryUi::polish(); + if ( m_polished ) return; + item()->list()->polishing(); + kdDebug() << "polish for " << entity().name() << endl; + QImage icon( KGlobal::iconLoader()->iconPath( entity().icon(), -32, true ) ); + if ( icon.isNull() ) { + icon = QImage( KGlobal::dirs()->findResource( "desktopicon", entity().icon() ) ); + } + m_icon->setPixmap( icon.isNull() ? item()->list()->emptyIcon() : + QPixmap( icon.smoothScale( 32, 32, QImage::ScaleMin ) ) ); + item()->list()->polished(); + m_polished = true; +} + +void DesktopEntry::toggled() { + /* if ( package().isInstalled() ) { + if ( package().markedRemove() ) + package().markKeep(); + else + package().markRemove(); + } else if ( package().markedInstall() ) + package().markKeep(); + else + package().markInstall(); */ + + if ( package().isInstalled() ) { + if ( package().markedRemove() ) + item()->list()->fireRequest( package(), component::State::AKeep ); + else + item()->list()->fireRequest( package(), component::State::ARemove ); + } else if ( package().markedInstall() ) + item()->list()->fireRequest( package(), component::State::AKeep ); + else + item()->list()->fireRequest( package(), component::State::AInstall ); + notifyPostChange(); +} + +void DesktopList::polishing() { + if ( m_polishing == 0 ) + QApplication::setOverrideCursor( QCursor( Qt::BusyCursor ) ); + m_polishing++; + if ( m_polishing % 10 == 0 ) + kapp->processEvents(); +} + +void DesktopList::polished() { + if ( m_polishing == childCount() ) + QApplication::restoreOverrideCursor(); +} + +void DesktopList::notifyPostChange( component::Base * ) { + utils::Range< ExtendableItem * > r = extenders(); + for ( ; r != r.end(); ++r ) { + dynamic_cast< DesktopEntry * >( (*r)->extender() )->notifyPostChange(); + } +} + +void DesktopEntry::notifyPostChange() { + if ( !package().valid() || !package().hasVersion() ) + return; + + m_check->blockSignals( true ); + m_check->setChecked( ( package().isInstalled() + || entity().package().markedInstall() ) + && !entity().package().markedRemove() ); + m_check->blockSignals( false ); +} + +DesktopList::DesktopList( QWidget *parent, const char *name ) + : ExtendableList( parent, name ), m_polishing( 0 ), m_displayCheckboxes( true ) +{ + observeComponent< component::State >(); + addColumn( i18n( "Application" ) ); + setResizeMode( LastColumn ); + setToggleColumn( -1 ); // no toggling, thanks + setExtenderHighlight( true ); + m_emptyIcon = QPixmap( + QImage( + KGlobal::iconLoader()->iconPath( u8( "exec" ), -32, false ) + ).smoothScale( 32, 32, QImage::ScaleMin ) ); + connect( this, SIGNAL( clicked( QListViewItem *, const QPoint &, int ) ), + this, SLOT( processClick( QListViewItem *, const QPoint &, int ) ) ); +} + +void DesktopList::processClick( QListViewItem *it, const QPoint &, int ) { + kdDebug() << "DesktopList::processClick..." << endl; + DesktopItem *i = dynamic_cast< DesktopItem * >( it ); + if ( !i ) return; + emit showDescription( i->entity() ); +} + +void DesktopList::insertRange( Range r ) { + m_range = r; + DesktopItem *last = 0; + int i = 0; + QApplication::setOverrideCursor( QCursor( Qt::BusyCursor ) ); + for( ; r != r.end(); r.advance() ) { + if ( i % 20 == 0 ) + kapp->processEvents(); + if ( !r->package( entity::Package() ).valid() ) + continue; + DesktopItem *i = last ? new DesktopItem( this, last ) : new DesktopItem( this ); + last = i; + i->setEntity( *r ); + ++ i; + } + QApplication::restoreOverrideCursor(); +} + +ItemExtender *DesktopItem::createExtender() { + return new DesktopEntry(); +} + +DesktopItem *DesktopEntry::item() const { + return dynamic_cast< DesktopItem * >( m_item ); +} + +entity::Desktop DesktopEntry::entity() const { + return item()->entity(); +} + +} diff --git a/adept/libadept/desktoplist.h b/adept/libadept/desktoplist.h new file mode 100644 index 0000000..207b9a7 --- /dev/null +++ b/adept/libadept/desktoplist.h @@ -0,0 +1,117 @@ +/** -*- C++ -*- + @file adept/desktoplist.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qimage.h> +#include <klocale.h> + +#include <apt-front/cache/entity/desktop.h> +#include <adept/extendablelist.h> +#include <adept/desktopentryui.h> + +#ifndef EPT_DESKTOPLIST_H +#define EPT_DESKTOPLIST_H + +class QPopupMenu; + +namespace adept { +using namespace aptFront; +using namespace aptFront::cache; + +class DesktopItem; + +class DesktopList : public ExtendableList, public cache::Observer +{ + Q_OBJECT +public: + typedef utils::Range< entity::Desktop > Range; + DesktopList( QWidget *parent = 0, const char *name = 0 ); + void insertRange( Range ); + QPixmap emptyIcon() { return m_emptyIcon; } + void polishing(); + void polished(); + + void setTitle( QString s ) { + setColumnText( 0, i18n( "Application (" ) + s + i18n( ")" ) ); + } + + void setDisplayCheckboxes( bool d ) { m_displayCheckboxes = d; } + bool displayCheckboxes() { return m_displayCheckboxes; } + virtual void notifyPostChange( cache::component::Base * ); + void fireRequest( entity::Package p, component::State::Action a ) { + emit request( p, a ); + } +protected slots: + void processClick( QListViewItem *, const QPoint &, int ); +signals: + void request( cache::entity::Package, cache::component::State::Action ); + void showDescription( cache::entity::Desktop ); +protected: + Range m_range; + QPixmap m_emptyIcon; + int m_polishing; + bool m_displayCheckboxes; +}; + +class DesktopEntry : public DesktopEntryUi +{ + Q_OBJECT +public: + DesktopEntry( QWidget * = 0, const char * = 0 ); + DesktopItem *item() const; + entity::Desktop entity() const; + void setItem( ExtendableItem * ); + entity::Package package() { return entity().package(); } + virtual void notifyPostChange(); + virtual void resize( int, int ); + // virtual void polish(); +public slots: + void toggled(); +protected: + virtual void mousePressEvent( QMouseEvent *e ); + virtual void mouseReleaseEvent( QMouseEvent *e ); + virtual void showEvent( QShowEvent * ); + bool m_polished; +}; + +class DesktopItem : public ExtendableItem +{ +public: + ItemExtender *createExtender(); + DesktopItem( DesktopList *l ) + : ExtendableItem( l ), m_delayedDone( false ) + { + } + DesktopItem( DesktopList *v, DesktopItem *i ) + : ExtendableItem( v, i ), m_delayedDone( false ) + { + } + + void setup() { + ExtendableItem::setup(); + if (m_delayedDone) + return; + m_delayedDone = true; + showExtender(); + } + + DesktopList *list() { return dynamic_cast< DesktopList * >( listView() ); } + + QString text( int ) const { return QString( "you shouldn't see this" ); } + entity::Desktop entity() const { return m_entity; } + void setEntity( entity::Desktop e ) { m_entity = e; } + + virtual bool less( const ExtendableItem *other ) const { + const DesktopItem *o = dynamic_cast< const DesktopItem * >( other ); + return entity() < o->entity(); + } + +protected: + entity::Desktop m_entity; + bool m_delayedDone:1; +}; + +} + +#endif diff --git a/adept/libadept/dpkgpm-gui.cpp b/adept/libadept/dpkgpm-gui.cpp new file mode 100644 index 0000000..828d18f --- /dev/null +++ b/adept/libadept/dpkgpm-gui.cpp @@ -0,0 +1,258 @@ +/** -*- C++ -*- + @file adept/dpkgpm-gui.cpp + @author Peter Rockai <me@mornfall.net> +*/ + +#include <fcntl.h> +#include <iostream> + +#include <qstrlist.h> +#include <kapplication.h> +#include <klistbox.h> +#include <klocale.h> +#include <kparts/part.h> + +#include <apt-pkg/configuration.h> +#include <apt-pkg/error.h> + +#include <apt-front/cache/cache.h> +#include <apt-front/cache/component/packages.h> +#include <apt-front/cache/entity/package.h> + +#include <adept/dpkgpm-gui.h> +#include <adept/utils.h> + +using namespace aptFront; +using namespace cache; + +namespace adept { + +PkgSystem::PkgSystem() + : m_terminalPart( 0 ) +{ + std::cerr << "kapture::PkgSystem::PkgSystem()" << std::endl; + Label = "adeptDPkgSystem"; +} + +void PkgSystem::setTerminal( KParts::Part *t ) +{ + m_terminalPart = t; +} + +pkgPackageManager *PkgSystem::CreatePM( pkgDepCache *c ) const +{ + std::cerr << "kapture::PkgSystem::CreatePM()" << std::endl; + adept::DPkgPM *pm = new adept::DPkgPM( c, m_terminalPart ); + connect( pm, SIGNAL( statusChanged( int, QString ) ), + this, SIGNAL( statusChanged( int, QString ) ) ); + return pm; +} + +DPkgPM::DPkgPM( pkgDepCache *cache, KParts::Part *t ) + : aptFront::DPkgPM (cache), m_terminalPart (t) +{ +} + +bool DPkgPM::forkDpkg( char *const argv[] ) +{ + bool ok = true; + std::cerr << "adept::DPkgPM::forkDpkg ()" << std::endl; + QStrList l; + for (int i = 0; argv[i]; i ++) + l.append( argv[i] ); + + m_processRunning = true; + connect( m_terminalPart, SIGNAL( processExited( KProcess * ) ), + this, SLOT( processExit( KProcess * ) ) ); + connect( m_terminalPart, SIGNAL( processExited( const KProcess * ) ), + this, SLOT( processExitC( const KProcess * ) ) ); + connect( m_terminalPart, SIGNAL( forkedChild() ), + this, SLOT( setupDpkgChild() ) ); + + terminal()->startProgram( u8( argv[0] ), l ); + + ::close( m_dpkgPipe[1] ); + ::fcntl( m_dpkgPipe[0], F_SETFL, O_NONBLOCK ); + + while (m_processRunning) { + dpkgMonitor(); + usleep( 50000 ); + } + + if (m_exitedProcess->normalExit()) { + if (m_exitedProcess->exitStatus() != 0) { + ok = _error->Error( "Child for %s exited with error %d", + argv [0], m_exitedProcess->exitStatus()); + } + } else { + ok = _error->Error( "Child for %s was killed by signal %d", + argv [0], m_exitedProcess->exitSignal()); + } + + if (ok) // do we run scripts in case dpkg died??? + ok = runScripts ("DPkg::Post-Invoke", false); + + return ok; +} + +ExtTerminalInterface *DPkgPM::terminal() { + return static_cast<ExtTerminalInterface *>( + m_terminalPart->qt_cast( "ExtTerminalInterface" ) ); +} + +bool DPkgPM::forkScript (const char *cmd, bool fP) +{ + std::cerr << "adept::DPkgPM::forkScript(\"" << cmd << "\")" << std::endl; + if (fP) { + if (pipe( m_scriptPipe ) != 0) + return _error->Errno( + "pipe","Failed to create IPC pipe to subprocess"); + SetCloseExec (m_scriptPipe[0], true); + SetCloseExec (m_scriptPipe[1], true); + } + QStrList l; + l.append ("/bin/sh"); + l.append ("-c"); + l.append (cmd); + if (fP) { + connect( m_terminalPart, SIGNAL( forkedChild() ), + this, SLOT( setupScriptPipe() ) ); + } + + connect( m_terminalPart, SIGNAL( processExited( KProcess * ) ), + this, SLOT( processExit( KProcess * ) ) ); + connect( m_terminalPart, SIGNAL( processExited( const KProcess * ) ), + this, SLOT( processExitC( const KProcess * ) ) ); + + m_processRunning = true; + terminal()->startProgram( u8( "/bin/sh" ), l); + + if (fP) { + if (!feedPackages()) + return _error->Error("Failed feeding packages to script"); + } + + while (m_processRunning) { + kapp->processEvents(); + usleep(50000); + } + + std::cerr << "END: adept::DPkgPM::forkScript(\"" + << cmd << "\")" << std::endl; + + if (m_exitedProcess->normalExit()) { + if (m_exitedProcess->exitStatus() != 0) { + return _error -> Error("Child for %s exited with error %d", + cmd, m_exitedProcess->exitStatus()); + } else { + return true; + } + } else { + return _error->Error("Child for %s was killed by signal %d", + cmd, m_exitedProcess->exitSignal()); + } +} + +void DPkgPM::processExit(KProcess *p) { + processExitC( p ); +} + +void DPkgPM::processExitC(const KProcess *p) +{ + std::cerr << "a process exited!" << std::endl; + m_processRunning = false; + m_exitedProcess = p; +} + +void DPkgPM::setupScriptPipe() +{ + // setupScript(); + // std::cerr << "setupScriptPipe()" << std::endl; + dup2 (m_scriptPipe[0], STDIN_FILENO); +} + +void DPkgPM::setupDpkgChild() +{ + // setupScript(); + // std::cerr << "setupDpkgChild()" << std::endl; + setupChild(); +} + +bool DPkgPM::Go( int ) +{ + std::cerr << "kapture::DPkgPM::Go ()" << std::endl; + statusChanged( 0, i18n( "Preparing..." ) ); + bool ret = aptFront::DPkgPM::Go(-1); + QStrList l; + l.append("echo"); + l.append("dpkg run finished!"); + terminal()->startProgram( u8( "echo" ), l ); + statusChanged( 100, i18n( "Done" ) ); + return ret; +} + +void DPkgPM::dpkgMonitor () +{ + aptFront::DPkgPM::dpkgMonitor(); + kapp->processEvents(); +} + +void DPkgPM::updateStatus( std::string pkg, std::string ev, std::string r ) +{ + std::string op, msg; + aptFront::DPkgPM::updateStatus( pkg, ev, r ); + entity::Package p = cache::Global::get().packages().packageByName( pkg ); + + if ( m_currentOp == OInstall ) { + if ( p.markedNewInstall() ) { + if ( ev == "half-installed" ) + msg = u8( i18n( "Preparing installation of %1..." ) ); + else if ( ev == "unpacked" ) + msg = u8( i18n( "Unpacking %1..." ) ); + } else if ( p.markedUpgrade() ) { + if ( ev == "half-installed" ) + msg = u8( i18n( "Preparing upgrade of %1..." ) ); + else if ( ev == "unpacked" || ev == "half-configured" ) + msg = u8( i18n( "Replacing %1 with new version..." ) ); + } + } else if ( m_currentOp == OConfigure ) { + if ( p.markedNewInstall() ) { + if ( ev == "unpacked" ) + msg = u8( i18n( "Preparing to configure %1..." ) ); + else if ( ev == "half-configured" ) + msg = u8( i18n( "Configuring %1..." ) ); + else if ( ev == "installed" ) + msg = u8( i18n( "Installed %1" ) ); + } else if ( p.markedUpgrade() ) { + if ( ev == "unpacked" ) + msg = u8( i18n( "Preparing to configure new version of %1..." ) ); + else if ( ev == "half-configured" ) + msg = u8( i18n( "Configuring new version of %1..." ) ); + else if ( ev == "installed" ) + msg = u8( i18n( "Upgraded %1" ) ); + } + } else if ( m_currentOp == ORemove ) { + if ( ev == "installed" ) + msg = u8( i18n( "Preparing to remove %1..." ) ); + else if ( ev == "half-configured" || ev == "half-installed" ) + msg = u8( i18n( "Removing %1..." ) ); + else if ( ev == "config-files" || ev == "not-installed" ) + msg = u8( i18n( "Removed %1" ) ); + } else if ( m_currentOp == OPurge ) { + if ( ev == "config-files" ) + msg = u8( i18n( "Preparing to purge %1..." ) ); + else if ( ev == "not-installed" ) + msg = u8( i18n( "Purged %1" ) ); + } + + std::cerr << "updateStatus( " << pkg << ", " << ev << ", " << r << ")" << std::endl; + std::cerr << "updateStatus: msg = " << msg << std::endl; + std::cerr << "updateStatus: seen = " << m_seenOpCount + << ", total = " << m_totalOpCount << std::endl; + statusChanged( ( m_seenOpCount * 100 ) / m_totalOpCount, + u8( msg ).arg( pkg ) + ( ( r == "") ? "" : (" (" + r + ")") ) ); +} + +} + +#include "dpkgpm-gui.moc" diff --git a/adept/libadept/dpkgpm-gui.h b/adept/libadept/dpkgpm-gui.h new file mode 100644 index 0000000..435ee7f --- /dev/null +++ b/adept/libadept/dpkgpm-gui.h @@ -0,0 +1,68 @@ +/** -*- C++ -*- + @file adept/dpkgpm-gui.h + @author Peter Rockai <me@mornfall.net> +*/ + +#ifndef EPT_DPKGPM_H +# define EPT_DPKGPM_H + +#include <apt-pkg/debsystem.h> +#include <adept/dpkgpm.h> +#include <kde_terminal_interface.h> +#include <kprocess.h> +#include <kdialogbase.h> + +class KListBox; +namespace KParts { +class Part; +} + +namespace adept { + +class PkgSystem : public QObject, public debSystem +{ + Q_OBJECT +public: + PkgSystem (); + virtual pkgPackageManager *CreatePM( pkgDepCache *Cache ) const; + virtual void setTerminal( KParts::Part *t ); + KParts::Part *terminal() { return m_terminalPart; } + virtual int Score( Configuration const &Cnf ) { + return debSystem::Score (Cnf) + 2; }; +protected: + KParts::Part *m_terminalPart; +signals: + void statusChanged( int p, QString m ); +}; + +class DPkgPM : public QObject, public aptFront::DPkgPM +{ + Q_OBJECT +public: + DPkgPM (pkgDepCache *c, KParts::Part *t); + virtual bool forkDpkg (char *const argv[]); + virtual void dpkgMonitor (void); + virtual bool Go (int); + virtual bool forkScript (const char *, bool); + ExtTerminalInterface *terminal(); + virtual void updateStatus( std::string pkg, std::string ev, std::string r ); + +public slots: + void processExitC(const KProcess *p); + void processExit(KProcess *p); + void setupScriptPipe(); + void setupDpkgChild(); + +signals: + void statusChanged( int p, QString m ); + +protected: + KParts::Part *m_terminalPart; + // DPkgProgress *m_prog; + bool m_processRunning:1; + const KProcess *m_exitedProcess; +}; + +} + +#endif diff --git a/adept/libadept/dpkgpm.cpp b/adept/libadept/dpkgpm.cpp new file mode 100644 index 0000000..b38b5fb --- /dev/null +++ b/adept/libadept/dpkgpm.cpp @@ -0,0 +1,451 @@ +/** -*- C++ -*- + @file adept/dpkgpm.cpp + @author Peter Rockai <me@mornfall.net> +*/ + +#include <apt-pkg/configuration.h> +#include <apt-pkg/error.h> +#include "dpkgpm.h" +#include <signal.h> +#include <sys/wait.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include <apt-front/cache/cache.h> +#include <apt-front/cache/component/packages.h> +#include <apt-front/cache/entity/package.h> + +#include <iostream> +#include <sstream> + +using namespace std; +using namespace aptFront; +using namespace cache; + +/* === PkgSystem === */ +DPkgPM::DPkgPM (pkgDepCache *C) + : pkgDPkgPM (C), m_seenOpCount( 0 ), m_totalOpCount( 0 ) +{ +} + +bool DPkgPM::Go( int ) +{ + cerr << "DPkgPM::Go()" << endl; + computeTotals(); + if (runScripts ("DPkg::Pre-Invoke", false) == false) + return false; + if (runScripts ("DPkg::Pre-Install-Pkgs", true) == false) + return false; + + for (vector<Item>::iterator I = List.begin(); I != List.end();) { + char *const *argv; + if (! setupArgs (&argv, I)) + return false; + + cerr << "running '"; + for (unsigned int k = 0; argv [k]; k++) + cerr << argv[k] << ' '; + cerr << "'" << endl; + if (_config->FindB("Debug::pkgDPkgPM",false) == true) + { + for (unsigned int k = 0; argv [k]; k++) + cerr << argv[k] << ' '; + cerr << endl; + continue; + } + + if (! forkDpkg (argv)) + return false; + delete[] argv; + if (! runScripts ("DPkg::Post-Invoke", false)) + return false; + } + return true; +} + +void DPkgPM::computeTotals() +{ + m_totalOpCount = 0; + for (vector<Item>::iterator I = List.begin(); I != List.end();I++) + { + entity::Package p = cache::Global::get().packages().packageByName( + I->Pkg.Name() ); + int x = 0; + switch ( I->Op ) { + case Item::Remove: x = 4; break; + case Item::Install: p.markedUpgrade() ? x = 3 : x = 2; break; + case Item::Purge: x = 2; break; + case Item::Configure: x = 3; break; + } + m_totalOpCount += x; + } +} + +bool DPkgPM::forkDpkg (char *const argv[]) +{ + cerr << "DPkgPM::forkDpkg ()" << endl; + cout << flush; + clog << flush; + cerr << flush; + + /* Mask off sig int/quit. We do this because dpkg also does when + it forks scripts. What happens is that when you hit ctrl-c it sends + it to all processes in the group. Since dpkg ignores the signal + it doesn't die but we do! So we must also ignore it */ + sighandler_t old_SIGQUIT = signal(SIGQUIT,SIG_IGN); + sighandler_t old_SIGINT = signal(SIGINT,SIG_IGN); + + // Fork dpkg + pid_t Child = ExecFork(); + if (Child == 0) { + if (! setupChild ()) { + cerr << "Error in dpkg post-fork setup!" << endl; + _exit (100); + } + execvp (argv [0], argv); + cerr << "Error executing dpkg!" << endl; + _exit (100); + } + + close( m_dpkgPipe[1] ); + fcntl( m_dpkgPipe[0], F_SETFL, O_NONBLOCK ); + + int Status = 0; + int ret = 0; + while ((ret = waitpid (Child, &Status, WNOHANG)) != Child) { + if (errno == EINTR || ret == 0) { + dpkgMonitor (); + usleep (200000); // 0.2 second hang + continue; + } + runScripts ("DPkg::Post-Invoke", false); + + signal(SIGQUIT,old_SIGQUIT); + signal(SIGINT,old_SIGINT); + return _error -> Errno ("waitpid","Couldn't wait for subprocess"); + } + + signal(SIGQUIT,old_SIGQUIT); + signal(SIGINT,old_SIGINT); + + // Check for an error code. + if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0) + { + runScripts ("DPkg::Post-Invoke", false); + if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV) + return _error->Error("Sub-process %s received a segmentation fault.", argv [0]); + + if (WIFEXITED(Status) != 0) + return _error->Error("Sub-process %s returned an error code (%u)", argv[0], WEXITSTATUS(Status)); + + return _error->Error("Sub-process %s exited unexpectedly", argv[0]); + } + + return true; +} + +bool DPkgPM::setupArgs (char *const**a, std::vector<Item>::iterator &I) +{ + cerr << "DPkgPM::setupArgs ()" << endl; + unsigned int MaxArgs = _config->FindI("Dpkg::MaxArgs",350); + unsigned int MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes",8192); + + vector<Item>::iterator J = I; + for (; J != List.end() && J->Op == I->Op; J++); + + // Generate the argument list + const char **Args = new const char *[MaxArgs + 50]; + if (J - I > (signed)MaxArgs) + J = I + MaxArgs; + + unsigned int n = 0; + unsigned long Size = 0; + string Tmp = _config->Find("Dir::Bin::dpkg","dpkg"); + Args[n++] = Tmp.c_str(); + Size += strlen(Args[n-1]); + + // Stick in any custom dpkg options + Configuration::Item const *Opts = _config->Tree("DPkg::Options"); + if (Opts != 0) + { + Opts = Opts->Child; + for (; Opts != 0; Opts = Opts->Next) + { + if (Opts->Value.empty() == true) + continue; + Args[n++] = Opts->Value.c_str(); + Size += Opts->Value.length(); + } + } + + pipe( m_dpkgPipe ); + stringstream fds; + fds << m_dpkgPipe[1]; + std::cerr << "reading end of the pipe: " << m_dpkgPipe[0] << std::endl; + + Args[n++] = "--status-fd"; + Size += strlen(Args[n-1]); + // bah, we leak a string every time we run dpkg... silly eh + Args[n++] = ( new string( fds.str() ) )->c_str(); + Size += strlen(Args[n-1]); + + switch (I->Op) + { + case Item::Remove: + Args[n++] = "--force-depends"; + Size += strlen(Args[n-1]); + Args[n++] = "--force-remove-essential"; + Size += strlen(Args[n-1]); + Args[n++] = "--remove"; + Size += strlen(Args[n-1]); + m_currentOp = ORemove; + break; + + case Item::Purge: + Args[n++] = "--force-depends"; + Size += strlen(Args[n-1]); + Args[n++] = "--force-remove-essential"; + Size += strlen(Args[n-1]); + Args[n++] = "--purge"; + Size += strlen(Args[n-1]); + m_currentOp = OPurge; + break; + + case Item::Configure: + Args[n++] = "--configure"; + Size += strlen(Args[n-1]); + m_currentOp = OConfigure; + break; + + case Item::Install: + Args[n++] = "--unpack"; + Size += strlen(Args[n-1]); + m_currentOp = OInstall; + break; + } + + // Write in the file or package names + if (I->Op == Item::Install) + { + for (;I != J && Size < MaxArgBytes; I++) + { + if (I->File[0] != '/') + return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str()); + Args[n++] = I->File.c_str(); + Size += strlen(Args[n-1]); + } + } + else + { + for (;I != J && Size < MaxArgBytes; I++) + { + Args[n++] = I->Pkg.Name(); + Size += strlen(Args[n-1]); + } + } + Args[n] = 0; + J = I; + *a = (char *const *)Args; + return true; +} + +bool DPkgPM::setupChild () +{ + // cerr << "DPkgPM::setupChild ()" << endl; + if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0) + return false; + + if (_config->FindB("DPkg::FlushSTDIN",true) == true && isatty(STDIN_FILENO)) + { + int Flags,dummy; + if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0) + return false; + + // Discard everything in stdin before forking dpkg + if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0) + return false; + + while (read(STDIN_FILENO,&dummy,1) == 1); + + if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0) + return false; + } + + /* No Job Control Stop Env is a magic dpkg var that prevents it + from using sigstop */ + putenv("DPKG_NO_TSTP=yes"); + close( m_dpkgPipe[0] ); + + return true; +} + +void DPkgPM::dpkgMonitor () +{ + char buf[1024]; + int r = read( m_dpkgPipe[0], buf, 1023 ); + + if ( r > 0 ) { + buf[r] = 0; + std::string b( buf ); + + // parse status updates from dpkg + while ( true ) { + std::string::size_type colon, nl = b.find( '\n' ); + m_statusBuffer.append( string( b, 0, nl ) ); + if ( nl == std::string::npos ) + break; + + // cerr << "dpkg status completed line: " << m_statusBuffer << endl; + colon = m_statusBuffer.find( ": " ); + string l( m_statusBuffer, 0, colon ); + string r( m_statusBuffer, colon + 2, string::npos ); + + if ( l == "status" ) { + colon = r.find( ": " ); + std::string p( r, 0, colon ); + r = string( r, colon + 2, string::npos ); + + colon = r.find( ": " ); + std::string e( r, 0, colon ); + if ( colon == string::npos ) + r = ""; + else + r = string( r, colon + 2, string::npos ); + updateStatus( p, e, r ); + } + + b = string( b, nl + 1, string::npos ); + m_statusBuffer = string(); + nl = b.find( '\n' ); + } + } +} + +void DPkgPM::updateStatus( std::string pkg, std::string ev, std::string r ) +{ + OpAndStatus os = std::make_pair( m_currentOp, ev ); + if ( m_seenOps[ std::make_pair( os, pkg ) ] == 0 ) { + m_seenOpCount++; + m_seenOps[ std::make_pair( os, pkg ) ] = 1; + } +} + +bool DPkgPM::runScripts (const char *Cnf, bool sP) +{ + cerr << "DPkgPM::runScripts ('" << Cnf << "', " << sP << ")" << endl; + Configuration::Item const *Opts = _config->Tree(Cnf); + if (Opts == 0 || Opts->Child == 0) + return true; + Opts = Opts->Child; + + unsigned int Count = 1; + for (; Opts != 0; Opts = Opts->Next, Count++) + { + if (Opts->Value.empty() == true) + continue; + + // Determine the protocol version + string OptSec = Opts->Value; + string::size_type Pos; + if ((Pos = OptSec.find(' ')) == string::npos || Pos == 0) + Pos = OptSec.length(); + OptSec = "DPkg::Tools::Options::" + string(Opts->Value.c_str(),Pos); + + m_version = _config->FindI (OptSec + "::Version", 1); + + // Purified Fork for running the script + // pid_t Process = ExecFork(); + forkScript (Opts->Value.c_str(), sP); + } + + return true; +} + +bool DPkgPM::SendV1Pkgs (FILE *F) +{ + bool Die = false; + for (vector<Item>::iterator I = List.begin(); I != List.end(); ++I) + { + // Only deal with packages to be installed from .deb + if (I->Op != Item::Install) + continue; + + // No errors here.. + if (I->File[0] != '/') + continue; + + /* Feed the filename of each package that is pending install + into the pipe. */ + fprintf(F,"%s\n",I->File.c_str()); + if (ferror(F) != 0) + { + Die = true; + break; + } + } + return ! Die; +} + +bool DPkgPM::forkScript (const char *cmd, bool fP) +{ + cerr << "DPkgPM::forkScript ()" << endl; + if (fP) { + if (pipe( m_scriptPipe ) != 0) + return _error -> Errno("pipe", "Failed to create IPC pipe to subprocess"); + SetCloseExec( m_scriptPipe[ 0 ], true ); + SetCloseExec( m_scriptPipe[ 1 ], true ); + } + pid_t Process = ExecFork (); + if (Process == 0) + { + setupScript (cmd, fP); + + const char *Args[4]; + Args[0] = "/bin/sh"; + Args[1] = "-c"; + Args[2] = cmd; + Args[3] = 0; + execv(Args[0],(char **)Args); + _exit(100); + } + + if (fP) { + if (! feedPackages ()) + return _error -> Error ("Failed feeding packages to script"); + } + + // Clean up the sub process + if (ExecWait (Process, cmd) == false) + return _error -> Error("Failure running script %s", cmd); +} + +void DPkgPM::setupScript (const char * /*cmd*/, bool fP) +{ + cerr << "DPkgPM::setupScript ()" << endl; + if (fP) { + dup2 (m_scriptPipe [0], STDIN_FILENO); + SetCloseExec(STDOUT_FILENO, false); + SetCloseExec(STDIN_FILENO, false); + SetCloseExec(STDERR_FILENO, false); + } +} + +bool DPkgPM::feedPackages () +{ + close(m_scriptPipe[ 0 ]); + + FILE *F = fdopen(m_scriptPipe[ 1 ], "w"); + if (F == 0) + return _error->Errno("fdopen","Faild to open new FD"); + + // Feed it the filenames. + bool Die = false; + if (m_version <= 1) + Die = !SendV1Pkgs (F); + else + Die = !SendV2Pkgs(F); + + fclose(F); + return ! Die; +} diff --git a/adept/libadept/dpkgpm.h b/adept/libadept/dpkgpm.h new file mode 100644 index 0000000..b899693 --- /dev/null +++ b/adept/libadept/dpkgpm.h @@ -0,0 +1,49 @@ +/** -*- C++ -*- + @file adept/dpkgpm.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <apt-pkg/dpkgpm.h> +#include <string> +#include <vector> +#include <map> + +#ifndef DPKGPM_H +# define DPKGPM_H + +namespace aptFront { + +class DPkgPM : public pkgDPkgPM { +protected: + enum Op { ORemove, OPurge, OConfigure, OInstall }; + Op m_currentOp; + int m_dpkgPipe[2]; + int m_scriptPipe[2]; + unsigned m_version; + std::string m_statusBuffer; + typedef std::pair< Op, std::string > OpAndStatus; + typedef std::map< std::pair< OpAndStatus, std::string >, int > SeenOps; + SeenOps m_seenOps; + int m_totalOpCount; + int m_seenOpCount; +public: + DPkgPM (pkgDepCache *C); + virtual bool Go ( int ); + virtual void computeTotals(); + virtual bool setupArgs (char *const **a, std::vector<Item>::iterator &I); + virtual bool forkDpkg (char *const argv[]); + virtual bool forkScript (const char *, bool); + virtual bool runScripts (const char *, bool); + virtual bool setupChild (); + virtual void setupScript (const char *, bool); + virtual void dpkgMonitor (void); + virtual bool SendV1Pkgs (FILE *); + virtual bool feedPackages (void); + virtual void updateStatus( std::string pkg, std::string ev, std::string r ); +}; + +} + + +#endif /* ifndef DPKGPM_H */ + diff --git a/adept/libadept/easytagfilter.cpp b/adept/libadept/easytagfilter.cpp new file mode 100644 index 0000000..4fa593b --- /dev/null +++ b/adept/libadept/easytagfilter.cpp @@ -0,0 +1,82 @@ +#include <apt-front/predicate/combinators.h> +#include <apt-front/predicate/factory.h> +#include <klocale.h> +#include <kdebug.h> +#include <qcombobox.h> +#include <qpushbutton.h> +#include "easytagfilter.h" + +using namespace aptFront; +using namespace adept; +using namespace Tagcoll; + +static void fillCombo( QComboBox *c, const std::string f ) { + Cache &cache = cache::Global::get(); // FIXME? + OpSet< entity::Tag > t; + t = cache.tags().tags( f ); + for (OpSet< entity::Tag >::iterator i = t.begin(); i != t.end(); ++ i) { + c->insertItem( i->name() ); + } +} + +EasyTagFilterWidget::EasyTagFilterWidget( QWidget *parent, const char *name ) + : EasyTagFilterUi( parent, name ) +{ + fillCombo( m_use, "use" ); + fillCombo( m_interface, "interface" ); + fillCombo( m_worksWith, "works-with" ); + fillCombo( m_role, "role" ); + connect( m_use, SIGNAL( activated( int ) ), + this, SLOT( widgetsChanged() ) ); + connect( m_interface, SIGNAL( activated( int ) ), + this, SLOT( widgetsChanged() ) ); + connect( m_worksWith, SIGNAL( activated( int ) ), + this, SLOT( widgetsChanged() ) ); + connect( m_role, SIGNAL( activated( int ) ), + this, SLOT( widgetsChanged() ) ); + connect( m_reset, SIGNAL( clicked() ), + this, SLOT( reset() ) ); +} + +static void setFacet( QComboBox *c, const std::string fac, + EasyTagFilter< entity::Package > &f ) +{ + if (c->currentItem()) + f.set( fac, c->currentText() ); +} + +EasyTagFilterWidget::Predicate EasyTagFilterWidget::predicate() +{ + EasyTagFilter< entity::Package > f; + setFacet( m_use, "use", f ); + setFacet( m_interface, "interface", f ); + setFacet( m_worksWith, "works-with", f ); + setFacet( m_role, "role", f ); + return predicate::adapt< entity::Entity >( f ); +} + +static void setCombo( QComboBox *c, const std::string &t ) { + c->blockSignals( true ); + if (t == "") + c->setCurrentItem( 0 ); + else + c->setCurrentText( t ); + c->blockSignals( false ); +} + +void EasyTagFilterWidget::predicateChanged() { + typedef EasyTagFilter< entity::Package > F; + F f = downcast< F >( m_pred ); + setCombo( m_use, f.get( "use" ) ); + setCombo( m_interface, f.get( "interface" ) ); + setCombo( m_role, f.get( "role" ) ); + setCombo( m_worksWith, f.get( "works-with" ) ); +} + +void EasyTagFilterWidget::reset() { + setCombo( m_use, "" ); + setCombo( m_interface, "" ); + setCombo( m_role, "" ); + setCombo( m_worksWith, "" ); + emit widgetsChanged(); +} diff --git a/adept/libadept/easytagfilter.h b/adept/libadept/easytagfilter.h new file mode 100644 index 0000000..edbe8b5 --- /dev/null +++ b/adept/libadept/easytagfilter.h @@ -0,0 +1,93 @@ +/** -*- C++ -*- + @file adept/quickfilter.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <klocale.h> +#include <qlayout.h> +#include <kdebug.h> + +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/entity/package.h> +#include <apt-front/cache/component/tags.h> +#include <apt-front/predicate/factory.h> + +#include <adept/easytagfilterui.h> +#include <adept/filterlist.h> +#include <adept/lister.h> + +#ifndef EPT_EASYTAGFILTER_H +#define EPT_EASYTAGFILTER_H + +namespace adept { + +template< typename T > +struct EasyTagFilter : predicate::Implementation< T, EasyTagFilter< T > >, + InterfacingPredicate +{ + typedef std::map< std::string, std::string > Tags; + + EasyTagFilter() { + setupPredicate(); + } + + void setupPredicate() { + Cache &cache = cache::Global::get(); // FIXME? + m_op = predicate::True< T >(); + for (Tags::iterator i = m_tags.begin(); i != m_tags.end(); ++i ) { + m_op = m_op and predicate::Factory< T >::tag( + cache.tags().tagByName( i->first + "::" + i->second ) ); + // kdDebug() << t.summary() << endl; + } + } + + std::string summary() const { + std::string r( i18n( "EasyTag filter: " ).local8Bit() ); + for (Tags::const_iterator j, i = m_tags.begin(); + i != m_tags.end(); ++i ) { + j = i; ++j; + r += i->first + ": " + i->second; + if (j != m_tags.end()) + r += ", "; + } + return r; + } + + void parseArguments( const predicate::ArgumentList & ) {} + + bool operator==( const EasyTagFilter &o ) const { + return o.m_tags == m_tags; + } + + bool operator()( const T &p ) { + return m_op( p ); + } + + void set( const std::string &f, const std::string &t ) { + m_tags[f] = t; + setupPredicate(); + } + + std::string get( const std::string &f ) { + return m_tags[ f ]; + } + +protected: + Tags m_tags; + predicate::Predicate< T > m_op; +}; + +class EasyTagFilterWidget : public EasyTagFilterUi +{ + Q_OBJECT +public: + EasyTagFilterWidget( QWidget *parent, const char *name = 0 ); + virtual Predicate predicate(); +public slots: + void predicateChanged(); + void reset(); +}; + +} + +#endif diff --git a/adept/libadept/easytagfilterui.ui b/adept/libadept/easytagfilterui.ui new file mode 100644 index 0000000..998bf2b --- /dev/null +++ b/adept/libadept/easytagfilterui.ui @@ -0,0 +1,201 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::EasyTagFilterUi</class> +<widget class="adept::PredicateInterface"> + <property name="name"> + <cstring>EasyTagFilterUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>611</width> + <height>116</height> + </rect> + </property> + <property name="caption"> + <string>QuickFilterUi</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>2</number> + </property> + <property name="spacing"> + <number>1</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_title</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><b>Easy Tag Filter</b></string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="1" column="2"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Works With:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Role:</string> + </property> + </widget> + <widget class="QComboBox" row="1" column="3"> + <item> + <property name="text"> + <string>Anything</string> + </property> + </item> + <property name="name"> + <cstring>m_worksWith</cstring> + </property> + </widget> + <widget class="QPushButton" row="1" column="4"> + <property name="name"> + <cstring>m_reset</cstring> + </property> + <property name="text"> + <string>Reset Filter</string> + </property> + </widget> + <widget class="QComboBox" row="0" column="3"> + <item> + <property name="text"> + <string>Any</string> + </property> + </item> + <property name="name"> + <cstring>m_interface</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Use:</string> + </property> + </widget> + <widget class="QComboBox" row="0" column="1"> + <item> + <property name="text"> + <string>Any</string> + </property> + </item> + <property name="name"> + <cstring>m_use</cstring> + </property> + </widget> + <widget class="QComboBox" row="1" column="1"> + <item> + <property name="text"> + <string>Any</string> + </property> + </item> + <property name="name"> + <cstring>m_role</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Interface:</string> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>130</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<includes> + <include location="global" impldecl="in declaration">adept/filterlist.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/adept/libadept/extendablelist.cpp b/adept/libadept/extendablelist.cpp new file mode 100644 index 0000000..55d1013 --- /dev/null +++ b/adept/libadept/extendablelist.cpp @@ -0,0 +1,332 @@ +#include <kdebug.h> +#include <qtimer.h> +#include <qobjectlist.h> +#include <qpainter.h> +#include <qimage.h> +#include <kiconeffect.h> +#include <kiconloader.h> + +#include <adept/extendablelist.h> +#include <adept/utils.h> + +using namespace adept; + +ExtendableList::ExtendableList( QWidget *p, const char *n ) + : KListView( p, n ), + m_toggleColumn( 0 ), m_inDtor( false ), + m_extenderUpdateScheduled( false ), + m_needSort( false ), + m_extenderHighlight( false ) +{ + // kdDebug() << "connecting processClick har har" << endl; + connect( this, SIGNAL( clicked( QListViewItem *, + const QPoint &, int ) ), + this, SLOT( processClick( QListViewItem *, + const QPoint &, int ) ) ); + connect( this, SIGNAL( moved() ), + this, SLOT( delayedUpdateExtenders() ) ); + connect( this, SIGNAL( collapsed( QListViewItem * ) ), + this, SLOT( delayedUpdateExtenders() ) ); + connect( this, SIGNAL( expanded( QListViewItem * ) ), + this, SLOT( delayedUpdateExtenders() ) ); + setTreeStepSize( 15 ); + + m_baseIcon = SmallIcon( u8( "extender_closed" ) ); + m_extendedIcon = SmallIcon( u8( "extender_opened" ) ); + QImage img; + img = m_baseIcon; + KIconEffect::toGray( img, 1.0 ); + m_unextendableIcon = QPixmap( img ); +} + +void ExtendableList::keyPressEvent( QKeyEvent *e ) { + ExtendableItem *item = dynamic_cast< ExtendableItem* >( currentItem() ); + if ( item && item->extendable() ) { + if ( item->extender() && e->key() == Qt::Key_Left ) { + return item->hideExtender(); + } else if ( !item->extender() && e->key() == Qt::Key_Right ) { + return item->showExtender(); + } + } + return KListView::keyPressEvent( e ); +} + +void ExtendableList::openToplevel() { + QListViewItem *i; + for ( i = firstChild(); i != 0; i = i->nextSibling() ) { + i->setOpen( true ); + } +} + +int ExtendableList::extenderOffset( ExtendableItem *i ) +{ + int c = 0, x = 0; + + while( c < m_toggleColumn ) { + x += columnWidth( c ); + c ++; + } + + if ( m_toggleColumn >= 0 ) { + // *sigh* + if ( i->pixmap( m_toggleColumn ) ) + x += i->pixmap( m_toggleColumn )->width(); + if ( rootIsDecorated() ) + x += treeStepSize(); + if ( i->parent() ) + x += treeStepSize(); + } + + return x; +} + +void ExtendableList::updateExtender( ExtendableItem *i ) +{ + // setUpdatesEnabled( false ); + + // since updateGeometries is private, we use this dirty trick to + // get at it (since setContentsPos in QListView calls it + setContentsPos( contentsX(), contentsY() ); + + if ( !i->isVisible() || ( i->parent() && !i->parent()->isOpen() ) ) { + kdDebug() << "hiding invisible item's extender" << endl; + i->hideExtender(); + return; + } + + // QRect rect = itemRect( i ); + addChild( i->extender(), extenderOffset( i ), itemPos( i ) ); + // addChild( i->extender(), x, rect.y() ); + i->extender()->show(); + i->extender()->resize( visibleWidth() - extenderOffset( i ), + i->extender()->height() ); + if ( i->height() != i->extender()->frameSize().height() ) { + i->setHeight( i->extender()->frameSize().height() ); + delayedUpdateExtenders(); // re-update since we broke layout + } + + i->extender()->setupColors(); + + // setUpdatesEnabled( true ); + // addChild( i->extender(), x, itemPos( i ) ); + // QTimer::singleShot( 0, this, SLOT( triggerUpdate() ) ); + // QTimer::singleShot( 0, i->extender(), SLOT( setupColors() ) ); +} + +void ExtendableList::delayedUpdateExtenders() +{ + if ( m_extenderUpdateScheduled ) + return; + m_extenderUpdateScheduled = true; + // kdDebug() << "ExtendableList::delayedUpdateExtenders()" << endl; + QTimer::singleShot( 0, this, SLOT( updateExtenders() ) ); +} + +void ExtendableList::clear() +{ + kdDebug() << "ExtendableList::clear()" << endl; + KListView::clear(); + kdDebug() << "end of ExtendableList::clear()" << endl; +} + +void ExtendableList::show() +{ + KListView::show(); + updateExtenders(); +} + +void ExtendableList::showEvent( QShowEvent *e ) +{ + KListView::showEvent( e ); + updateExtenders(); +} + +void ExtendableList::resizeEvent( QResizeEvent *e ) +{ + KListView::resizeEvent( e ); + updateExtenders(); + // delayedUpdateExtenders(); +} + +void ExtendableList::updateExtenders() +{ + m_extenderUpdateScheduled = false; + setUpdatesEnabled( false ); + // updateGeometries(); + // since updateGeometries is private, we use this dirty trick to + // get at it (since setContentsPos in QListView calls it + setContentsPos( contentsX(), contentsY() ); + extendersChanged(); + kdDebug() << "ExtendableList::updateExtenders(); count = " + << m_extenders.size() << endl; + if ( m_needSort ) { + std::sort( m_extenders.begin(), m_extenders.end(), ExtendableItem::s_less ); + m_needSort = false; + } + + std::for_each( m_extenders.begin(), m_extenders.end(), + std::bind1st( std::mem_fun( &ExtendableList::updateExtender ), + this ) ); + + setUpdatesEnabled( true ); + // triggerUpdate(); + if ( !m_extenderUpdateScheduled ) + QTimer::singleShot( 0, this, SLOT( triggerUpdate() ) ); + /* if ( m_extenders.empty() ) + QTimer::singleShot( 0, this, SLOT( triggerUpdate() ) ); */ + // QTimer::singleShot( 0, this, SIGNAL( extendersChanged() ) ); +} + +void ExtendableList::addExtender( ExtendableItem *item ) +{ + m_extenders.push_back( item ); + m_needSort = true; + // std::sort( m_extenders.begin(), m_extenders.end(), ExtendableItem::s_less ); + // updateExtender( item ); + delayedUpdateExtenders(); +} + +void ExtendableList::removeExtender( ExtendableItem *i ) +{ + kdDebug() << "ExtendableList::removeExtender( " << i << " )" << endl; + m_extenders.erase( std::remove( m_extenders.begin(), + m_extenders.end(), i ), + m_extenders.end() ); + // the above retains ordering so no need to re-sort + if (!m_inDtor) + delayedUpdateExtenders(); +} + +void ExtendableList::processClick( QListViewItem *it, + const QPoint &pt, int c ) +{ + // if (! it) return; + ExtendableItem *item = dynamic_cast< ExtendableItem* >( it ); + if (!item) return; + kdDebug() << "ExtendableList::processClick (a real item)" << endl; + + if (c == m_toggleColumn) + item->toggleExtender(); + if ( item->extender() ) + item->extender()->setupColors(); + delayedUpdateExtenders(); + /* if (item->extender()) { + if (c == m_toggleColumn) + item->toggleExtender(); + } else + item->toggleExtender(); */ +} + +ExtendableList::~ExtendableList() { +} + +ExtendableList *ExtendableItem::list() +{ + return dynamic_cast< ExtendableList * >( listView() ); +} + +bool ExtendableItem::s_less( + const ExtendableItem *a, const ExtendableItem *b ) +{ + return a->less( b ); +} + +int ExtendableItem::compare( QListViewItem *i, int c, bool asc ) const +{ + ExtendableItem *o = dynamic_cast< ExtendableItem * >( i ); + return int( o->less( this ) ) - int( less( o ) ); +} + +void ExtendableItem::updateIcon() { + QPixmap p; + if ( !extender() ) { + p = list()->baseIcon(); + if ( !extendable() && !firstChild() ) { + p = list()->unextendableIcon(); + } + } else { + p = list()->extendedIcon(); + } + setPixmap( list()->toggleColumn(), p ); + + // umm hack + if ( dynamic_cast< ExtendableItem * >( parent() ) ) + dynamic_cast< ExtendableItem * >( parent() )->updateIcon(); +} + + +void ExtendableItem::toggleExtender() +{ + if (m_extender) { + setup(); + if( list() ) // this could as well be 0... bah + list()->removeExtender( this ); + delete m_extender; + m_extender = 0; + } else { + m_extender = createExtender(); + if (m_extender) { + m_extender->setItem( this ); + list()->addExtender( this ); + } + if ( !m_extender && firstChild() ) { + setOpen( !isOpen() ); + } + } + updateIcon(); +} + +void ExtendableItem::paintBranches( QPainter *p, + const QColorGroup &cg, int w, int y, int h ) +{ + /* if (!isAlternate()) + p->setBackgroundColor( + KGlobalSettings::alternateBackgroundColor() ); + p->eraseRect( 0, y, w, h ); */ + p->eraseRect( 0, 0, w, h ); +} + +/* void ExtendableItem::paintCell( QPainter *p, const QColorGroup &cg, + int column, int width, int alignment ) +{ + QPixmap pm( width, height() ); + QPainter _p( &pm ); + KListViewItem::paintCell( &_p, cg, column, width, alignment ); + p->drawPixmap( 0, 0, pm ); + } */ + + +static void setcolor( QWidget *w, ExtendableItem *i ) { + if ( i->isSelected() && i->list()->extenderHighlight() ) + w->setPaletteBackgroundColor( w->colorGroup().highlight() ); + else if ( i->isAlternate() ) + w->setPaletteBackgroundColor( + KGlobalSettings::alternateBackgroundColor() ); + else + w->setPaletteBackgroundColor( w->colorGroup().base() ); + // w->setBackgroundMode( QWidget::PaletteBase ); +} +void ItemExtender::setupColors() +{ + if ( !item() ) return; + setcolor( this, item() ); + QObjectList *chld = queryList( "QWidget" ); + QObjectListIt it( *chld ); + QWidget *o; + while ((o = dynamic_cast< QWidget * >( it.current() )) != 0) { + setcolor( o, item() ); + ++it; + } +} + +ExtendableItem::~ExtendableItem() +{ + // kdDebug() << "~ExtendableList; list = " << list() << endl; + // kdDebug() << "extender() = " << extender() << endl; + while ( firstChild() ) + delete firstChild(); // har har + if( extender() && list() ) // list() could be 0... + list()->removeExtender( this ); + if (extender()) + extender()->deleteLater(); +} diff --git a/adept/libadept/extendablelist.h b/adept/libadept/extendablelist.h new file mode 100644 index 0000000..53a901b --- /dev/null +++ b/adept/libadept/extendablelist.h @@ -0,0 +1,165 @@ +// -*- C++ -*- +#include <klistview.h> +#include <qpixmap.h> +#include <qlayout.h> +#include <kglobalsettings.h> +#include <vector> + +#include <apt-front/utils/range.h> + +#ifndef EPT_EXTENDABLELIST_H +#define EPT_EXTENDABLELIST_H +namespace adept { + +using namespace aptFront; + +class ExtendableItem; +class ExtendableList; +class ItemExtender; + +class ExtendableList : public KListView { + Q_OBJECT +public: + typedef bool(*ItemCompare)( const ExtendableItem *, + const ExtendableItem * ); + ExtendableList( QWidget *p = 0, const char *n = 0 ); + virtual ~ExtendableList(); + QPixmap extendedIcon() { return m_extendedIcon; } + QPixmap baseIcon() { return m_baseIcon; } + QPixmap unextendableIcon() { return m_unextendableIcon; } + int extenderOffset( ExtendableItem *i ); + void setExtenderHighlight( bool e ) { m_extenderHighlight = e; } + bool extenderHighlight() { return m_extenderHighlight; } +public slots: + void addExtender( ExtendableItem *i ); + void removeExtender( ExtendableItem *i ); + void updateExtender( ExtendableItem *i ); + void delayedUpdateExtenders(); + void updateExtenders(); + void setToggleColumn( int c ) { + m_toggleColumn = c; + } + unsigned toggleColumn() { return m_toggleColumn; } + virtual void show(); + virtual void clear(); + utils::Range< ExtendableItem * > extenders() { + return utils::range( m_extenders.begin(), m_extenders.end() ); } + void openToplevel(); +protected slots: + void processClick( QListViewItem *, const QPoint &, int ); +signals: + void extendersChanged(); +protected: + virtual void resizeEvent( QResizeEvent * ); + virtual void showEvent( QShowEvent * ); + virtual void keyPressEvent( QKeyEvent * ); + std::vector< ExtendableItem * > m_extenders; + QPixmap m_extendedIcon; + QPixmap m_baseIcon; + QPixmap m_unextendableIcon; + int m_toggleColumn; + bool m_inDtor:1; + bool m_extenderUpdateScheduled:1; + bool m_needSort:1; + bool m_extenderHighlight:1; +}; + +class ExtendableItem : public KListViewItem { +public: + + ExtendableItem( ExtendableList *l ) + : KListViewItem( l ), m_extender( 0 ) { + } + + ExtendableItem( ExtendableList *l, ExtendableItem *prev ) + : KListViewItem( l, prev ), m_extender( 0 ) { + } + + ExtendableItem( ExtendableItem *p, ExtendableItem *prev ) + : KListViewItem( p, prev ), m_extender( 0 ) { + } + + ExtendableItem( ExtendableItem *p ) + : KListViewItem( p ), m_extender( 0 ) { + } + + virtual void setup() { + KListViewItem::setup(); + updateIcon(); + } + void toggleExtender(); + + void hideExtender() { + if (extender()) + toggleExtender(); + } + + void showExtender() { + if (!extender()) + toggleExtender(); + } + + ItemExtender *extender() { return m_extender; } + + static bool s_less( const ExtendableItem *a, const ExtendableItem *b ); + + ExtendableList *list(); + + virtual void updateIcon(); + + virtual void paintBranches( QPainter *, const QColorGroup &, int, int, int ); + + virtual ItemExtender *createExtender() = 0; + virtual bool extendable() const { return false; } + virtual bool less( const ExtendableItem * ) const = 0; + virtual int compare( QListViewItem *other, int col, bool ascending ) const; + + virtual ~ExtendableItem(); + virtual void setHeight( int h ) { KListViewItem::setHeight( h ); } +protected: + ItemExtender *m_extender; +}; + +class ItemExtender : public QWidget { + Q_OBJECT +public: + // ItemExtender( ExtendableItem *item ); + ItemExtender( QWidget *parent, const char *n ) + : QWidget( parent, n ), m_item( 0 ) + {} + + virtual void setItem( ExtendableItem *i ) { + m_item = i; + } + + virtual void polish() { + setupColors(); + } + + ExtendableItem *item() { + return m_item; + } + + void resize( int w, int h ) { + setUpdatesEnabled( false ); + QWidget::resize( w, h ); + setUpdatesEnabled( true ); + QWidget::resize( w, layout()->minimumSize().height() ); + } + + void resize( const QSize &s ) { + resize( s.width(), s.height() ); + } + +public slots: + void setupColors(); +protected: + virtual void mouseReleaseEvent( QMouseEvent *e ) { + e->accept(); + } // throw away mouse clicks :-) + ExtendableItem *m_item; +}; + +} + +#endif diff --git a/adept/libadept/filterlist.cpp b/adept/libadept/filterlist.cpp new file mode 100644 index 0000000..7d4a1b0 --- /dev/null +++ b/adept/libadept/filterlist.cpp @@ -0,0 +1,231 @@ +#include <kdebug.h> +#include <qpopupmenu.h> +#include <qheader.h> +#include <klineedit.h> + +#include <tagcoll/InputMerger.h> + +#include <apt-front/cache/component/tags.h> +#include <apt-front/cache/entity/package.h> + +#include <adept/lister.h> +#include <adept/filterlist.h> +#include <adept/quickfilter.h> +#include <adept/statefilter.h> +#include <adept/easytagfilter.h> +#include <adept/tagfilter.h> + + +using namespace adept; +using namespace Tagcoll; + +// TODO: Beat enrico till this lands in some of our libs... +template< typename PKG, typename TAG > +class TagcollConsumerAdaptor : + public utils::ConsumerImpl< PKG,TagcollConsumerAdaptor<PKG, TAG> > +{ +protected: + Consumer<PKG, TAG>& m_out; + +public: + TagcollConsumerAdaptor( Consumer<PKG, TAG>& out) : m_out( out ) {} + virtual void consume( const PKG& a ) { + if (a != PKG()) + m_out.consume(a, a.tags()); + } +}; + +PredicateInterface::PredicateInterface( QWidget *w, const char *n ) + : ItemExtender( w, n ) +{ +} + +void PredicateInterface::widgetsChanged() { + kdDebug() << "PredicateInterface::widgetsChanged()" << endl; + emit predicateDrop( m_pred ); + m_pred = predicate(); + emit predicateAdd( m_pred ); + downcast< FilterItem >( item() ).setPredicate( m_pred ); +} + +FilterList::FilterList( QWidget *parent, const char *name ) + : ExtendableList( parent, name ), + m_pred( predicate::True< entity::Entity >() ), + m_hidden( predicate::True< entity::Entity >() ) +{ + m_itemsSeen = 0; + // addColumn( " ", 20 ); + addColumn( i18n( "Active filters" ), 240 ); + // setSortColumn( -1 ); + /* setItemsMovable( true ); + setDragEnabled( true ); + setAcceptDrops( true ); */ + setResizeMode( LastColumn ); + setAllColumnsShowFocus (true); + + resize( 240, 180 ); + connect( this, SIGNAL( + contextMenuRequested( QListViewItem *, const QPoint + &, int ) ), + this, SLOT( contextMenu( QListViewItem *, const + QPoint &, int) ) ); + connect( this, SIGNAL( extendersChanged() ), + this, SLOT( updateHeight() ) ); +} + +void FilterList::emitPredicateChanged() { + predicateChanged( m_hidden and m_pred ); +} + +void FilterList::updateHeight() { + int h = header()->height() + 4; + for ( QListViewItem *i = firstChild(); i != 0; i = i->nextSibling() ) { + h += i->totalHeight(); + } + // int h = contentsHeight() + header()->height() + 4; // magic constant + setMinimumHeight( h ); + setMaximumHeight( h ); +} + +void FilterList::drawContents( QPainter *p, int a, int b, int c, int d ) { + if ( m_itemsSeen != childCount() ) { + m_itemsSeen = childCount(); + updateHeight(); + } // hmm, doesn't work... bah :p + KListView::drawContents( p, a, b, c, d ); +} + +void FilterList::plugLister( Lister *l ) { + m_lister = l; + connect( this, SIGNAL( predicateChanged( ListerPredicate ) ), + l, SLOT( baseSet( ListerPredicate ) ) ); +} + +void FilterList::setPredicate( Predicate p ) { + clear(); + m_pred = p; + appendPredicate( p ); + emitPredicateChanged(); +} + +void FilterList::setHiddenPredicate( Predicate p ) { + m_hidden = p; + emitPredicateChanged(); +} + +void FilterList::editorPredicateDrop( Predicate p ) { + m_pred = predicate::remove( m_pred, p ); + emitPredicateChanged(); +} + +void FilterList::editorPredicateAdd( Predicate p ) { + kdDebug() << "FilterList::editorPredicateAdd" << endl; + m_pred = m_pred and p; + emitPredicateChanged(); +} + +void FilterList::appendPredicate( Predicate p ) { + if (p.is< And >()) { + And a = p; + for (utils::Range< Predicate > r = a.parts(); + r != r.end(); ++r ) + appendPredicate( *r ); + } else if (p.is< predicate::True< entity::Entity > >() ) { + // we generally ignore truth + } else { + m_pred = m_pred and p; + // kdDebug() << p.serialize() << endl; + // kdDebug() << p.prettyPrint() << endl; + FilterItem *i; + i = new FilterItem( this ); + i->setPredicate( p ); + } +} + +void FilterList::contextMenu( QListViewItem *it, const QPoint &pt, int /*c*/ ) +{ + std::cerr << "FilterList::contextMenu(p);" << std::endl; + FilterItem *i = dynamic_cast< FilterItem * >( it ); + if (! i) + return; + QPopupMenu *m = new QPopupMenu( this ); + m->insertItem( i18n( "Reset Filter" ), 1 ); + m->insertItem( i18n( "Remove Filter" ), 0 ); + m->insertSeparator(); + m->insertItem( i18n( "Add Quick Filter" ), 8 ); + m->insertItem( i18n( "Add State Filter" ), 9 ); + m->insertItem( i18n( "Add Tag Filter" ), 10 ); + m->insertItem( i18n( "Add Easy Tag Filter" ), 11 ); + // m->insertItem( "Add Tag Filter", tagMenu() ); + m_context = i; + connect(m, SIGNAL(activated(int)), this, SLOT(contextActivated(int))); + m->exec(pt); + delete m; +} + + +void FilterList::contextActivated( int i ) +{ + predicate::Predicate< entity::Entity > p; + switch (i) { + case 0: + m_pred = predicate::remove( m_pred, m_context->predicate() ); + delete m_context; + emitPredicateChanged(); + return; + case 1: + m_context->reset(); + return; + case 8: + p = predicate::adapt< entity::Entity >( + QuickFilter< entity::Package >() ); + break; + case 9: + p = predicate::adapt< entity::Entity >( + StateFilter< entity::Package >() ); + break; + case 10: + p = predicate::adapt< entity::Entity >( + TagFilter< entity::Package >() ); + break; + case 11: + p = predicate::adapt< entity::Entity >( + EasyTagFilter< entity::Package >() ); + break; + } + if (p.impl()) { + kdDebug() << "summary: " << + downcast< InterfacingPredicate >( p ).summary() << endl; + appendPredicate( p ); + emitPredicateChanged(); + } +} + +ItemExtender *FilterItem::createExtender() +{ + PredicateInterface *o = 0; + if (m_pred.is< QuickFilter< entity::Package > >()) { + o = new QuickFilterWidget( list(), 0 ); + } else if (m_pred.is< StateFilter< entity::Package > >()) { + o = new StateFilterWidget( list(), 0 ); + } else if (m_pred.is< EasyTagFilter< entity::Package > >()) { + o = new EasyTagFilterWidget( list(), 0 ); + } else if (m_pred.is< TagFilter< entity::Package > >()) { + o = new TagFilterWidget( list(), 0 ); + } + if (o) { + o->setPredicate( m_pred ); + QObject::connect( o, SIGNAL( predicateAdd( Predicate ) ), + list(), SLOT( editorPredicateAdd( Predicate ) ) ); + QObject::connect( o, SIGNAL( predicateDrop( Predicate ) ), + list(), SLOT( editorPredicateDrop( Predicate ) ) ); + } + return o; +} + +QString FilterItem::text( int c ) const { + InterfacingPredicate &ip = downcast< InterfacingPredicate >( m_pred.impl() ); + if (c == 0) + return ip.summary(); + return u8( "" ); +} diff --git a/adept/libadept/filterlist.h b/adept/libadept/filterlist.h new file mode 100644 index 0000000..f904bc7 --- /dev/null +++ b/adept/libadept/filterlist.h @@ -0,0 +1,149 @@ +/** -*- C++ -*- + @file adept/filterlist.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qtooltip.h> +#include <kdebug.h> + +#include <apt-front/predicate/matchers.h> +#include <apt-front/predicate/combinators.h> +#include <apt-front/predicate/factory.h> +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/component/packagetags.h> +#include <apt-front/cache/component/tags.h> + +#include <adept/listerpredicate.h> +#include <adept/extendablelist.h> + +#ifndef EPT_FILTERLIST_H +#define EPT_FILTERLIST_H + +class QPopupMenu; + +namespace adept { +using namespace aptFront; +using namespace aptFront::cache; +class Lister; + +struct InterfacingPredicate +{ +public: + virtual std::string summary() const = 0; + virtual void reset() {} +signals: + void changed(); +}; + + +class PredicateInterface: public ItemExtender +{ + Q_OBJECT +public: + typedef predicate::Predicate< entity::Entity > Predicate; + PredicateInterface( QWidget *w = 0, const char *n = 0 ); + virtual Predicate predicate() = 0; +signals: + void predicateAdd( Predicate ); + void predicateDrop( Predicate ); +public slots: + virtual void setPredicate( const Predicate &p ) { + m_pred = p; + predicateChanged(); + } + virtual void widgetsChanged(); + virtual void predicateChanged() = 0; +protected: + predicate::Predicate< entity::Entity > m_pred; +}; + +class FilterItem; + +class FilterList : public ExtendableList +{ + Q_OBJECT +public: + friend class FilterItem; + typedef predicate::Predicate< entity::Entity > Predicate; + // typedef std::map< KListViewItem *, Predicate > Map; + FilterList( QWidget *parent = 0, const char *name = 0 ); + typedef predicate::And< entity::Entity > And; + void appendPredicate( Predicate p ); + void plugLister( Lister *l ); + void emitPredicateChanged(); +signals: + void predicateChanged( ListerPredicate p ); +public slots: + void setPredicate( Predicate p ); + void setHiddenPredicate( Predicate p ); +protected slots: + void editorPredicateDrop( Predicate ); + void editorPredicateAdd( Predicate ); + void contextMenu( QListViewItem *, const QPoint &, int ); + // QPopupMenu *tagMenu(); + void contextActivated( int ); + // void tagMenuActivated( int ); + void updateHeight(); +protected: + void drawContents( QPainter *, int, int, int, int ); + Predicate m_pred; + Predicate m_hidden; + FilterItem *m_context; + bool m_changed; + Lister *m_lister; + int m_itemsSeen; + std::vector< entity::Tag > m_tagMenuMap; +}; + +class FilterItem : public ExtendableItem +{ +public: + ItemExtender *createExtender(); + FilterItem( FilterList *l ) + : ExtendableItem( l ), m_delayedDone( false ) + { + } + void setup() { + ExtendableItem::setup(); + if (m_delayedDone) + return; + m_delayedDone = true; + showExtender(); + } + + QString text( int ) const; + + virtual bool less( const ExtendableItem *other ) const { + const FilterItem *o = dynamic_cast< const FilterItem * >( other ); + return downcast< InterfacingPredicate >( m_pred ).summary() < + downcast< InterfacingPredicate >( o->m_pred ).summary(); + } + + void setPredicate( predicate::Predicate< entity::Entity > p ) { + m_pred = p; + } + + FilterList::Predicate predicate() const { + return m_pred; + } + + FilterList *filterList() { return dynamic_cast< FilterList * >( list() ); } + + void reset() { + filterList()->editorPredicateDrop( m_pred ); + downcast< InterfacingPredicate >( m_pred ).reset(); + if ( extender() ) { + downcast< PredicateInterface >( extender() ).setPredicate( m_pred ); + extender()->setFocus(); + } + filterList()->editorPredicateAdd( m_pred ); + } + +protected: + predicate::Predicate< entity::Entity > m_pred; + bool m_delayedDone:1; +}; + +} + +#endif diff --git a/adept/libadept/filtersidebar.cpp b/adept/libadept/filtersidebar.cpp new file mode 100644 index 0000000..52d909e --- /dev/null +++ b/adept/libadept/filtersidebar.cpp @@ -0,0 +1,71 @@ +#include <functional> +#include <ext/functional> +#include <algorithm> +#include <cmath> +#include <apt-front/cache/entity/tag.h> +#include <apt-front/cache/component/tags.h> +#include <adept/filtersidebar.h> +#include <adept/tagchooser.h> + +using namespace adept; +using namespace aptFront; +using namespace std; +using namespace __gnu_cxx; + +template< typename H, typename G1, typename G2 > +struct _compose2_binary { + _compose2_binary( H _h, G1 _g1, G2 _g2 ) + : h( _h ), g1( _g1 ), g2( _g2 ) + {} + + typename H::result_type operator()( + typename G1::argument_type a, + typename G2::argument_type b ) + { + return h( g1( a ), g2( b ) ); + } + + H h; + G1 g1; + G2 g2; +}; + +template< typename H, typename G1, typename G2 > +_compose2_binary< H, G1, G2 > compose2_binary( H h, G1 g1, G2 g2 ) { + return _compose2_binary< H, G1, G2 >( h, g1, g2 ); +} + +void FilterSidebar::setCardinality( const Lister::Cardinality &c ) +{ + cache::entity::Tag::Set all, smart; + + kdDebug() << "FilterSidebar::setCardinality" << endl; + Lister::Cardinality cprime; + remove_copy_if( c.begin(), c.end(), inserter( cprime, cprime.begin() ), + compose1( bind1st( equal_to< int >(), 0 ), + select2nd< + Lister::Cardinality::value_type >() ) ); + transform( cprime.begin(), cprime.end(), inserter( all, all.begin() ), + select1st< Lister::Cardinality::value_type >() ); + m_all->setTags( all ); + cache::component::Tags &t = cache::Global().get().tags(); + m_easy->setTags( all ^ ( t.facetByName( "interface" ).tags() + + t.facetByName( "works-with" ).tags() + + t.facetByName( "use" ).tags() + + t.facetByName( "role" ).tags() ) ); + + typedef vector< pair< cache::entity::Tag, int > > Vec; + Vec vec; + copy( cprime.begin(), cprime.end(), back_inserter( vec ) ); + sort( vec.begin(), vec.end(), + compose2_binary( less< int >(), + select2nd< Vec::value_type >(), + select2nd< Vec::value_type >() ) ); + Vec::reverse_iterator end = vec.rbegin(); + advance( end, vec.size() < 10 ? vec.size() : 10 ); + transform( vec.rbegin(), end, inserter( smart, smart.begin() ), + select1st< Vec::value_type >() ); + + m_smart->setTags( smart ); + m_smart->openToplevel(); +} diff --git a/adept/libadept/filtersidebar.h b/adept/libadept/filtersidebar.h new file mode 100644 index 0000000..0fac201 --- /dev/null +++ b/adept/libadept/filtersidebar.h @@ -0,0 +1,26 @@ +/* -*- C++ -*- file adept/filtersidebar.h + written by Peter Rockai <me@mornfall.net> */ + +#include <adept/filtersidebarui.h> +#include <adept/lister.h> + +#ifndef EPT_FILTERSIDEBAR_H +#define EPT_FILTERSIDEBAR_H + +namespace adept { + +// using namespace aptFront; + +class FilterSidebar : public FilterSidebarUi { + Q_OBJECT +public: + FilterSidebar( QWidget *p = 0, const char *n = 0 ) + : FilterSidebarUi( p, n ) + {} +public slots: + void setCardinality( const Lister::Cardinality & ); +}; + +} + +#endif diff --git a/adept/libadept/filtersidebarui.ui b/adept/libadept/filtersidebarui.ui new file mode 100644 index 0000000..0f2efb4 --- /dev/null +++ b/adept/libadept/filtersidebarui.ui @@ -0,0 +1,119 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::FilterSidebarUi</class> +<widget class="QWidget"> + <property name="name"> + <cstring>adept::FilterSidebarUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>227</width> + <height>469</height> + </rect> + </property> + <property name="caption"> + <string>Form2</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QTabWidget" row="0" column="0"> + <property name="name"> + <cstring>m_tabs</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab0</cstring> + </property> + <attribute name="title"> + <string>Smart</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="adept::TagChooser" row="0" column="0"> + <property name="name"> + <cstring>m_smart</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab1</cstring> + </property> + <attribute name="title"> + <string>Simple</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="adept::TagChooser" row="0" column="0"> + <property name="name"> + <cstring>m_easy</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab2</cstring> + </property> + <attribute name="title"> + <string>All</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="adept::TagChooser" row="0" column="0"> + <property name="name"> + <cstring>m_all</cstring> + </property> + </widget> + </grid> + </widget> + </widget> + </grid> +</widget> +<customwidgets> + <customwidget> + <class>adept::TagChooser</class> + <header location="global">adept/tagchooser.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </customwidget> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>adept/tagchooser.h</includehint> +</includehints> +</UI> diff --git a/adept/libadept/filterwidget.cpp b/adept/libadept/filterwidget.cpp new file mode 100644 index 0000000..f294327 --- /dev/null +++ b/adept/libadept/filterwidget.cpp @@ -0,0 +1,36 @@ +#include <apt-front/predicate/combinators.h> +#include <apt-front/predicate/factory.h> +#include <klocale.h> +#include <klineedit.h> +#include "filterwidget.h" + +using namespace aptFront; +using namespace adept; + +void FilterWidget::connectLister( Lister *l ) { + connect( this, SIGNAL( drop( ListerPredicate ) ), + l, SLOT( interactiveDrop( ListerPredicate ) ) ); + connect( this, SIGNAL( changed( ListerPredicate ) ), + l, SLOT( interactiveAnd( ListerPredicate ) ) ); + connect( this, SIGNAL( apply( ListerPredicate ) ), + l, SLOT( baseAnd( ListerPredicate ) ) ); + +} + +void FilterWidget::changedInternal() { + setEnabled( false ); + emit drop( m_old ); + emit changed( m_old = predicate() ); + setEnabled( true ); + setFocus(); +} + +void FilterWidget::applyInternal() { + // check for emptiness? + setEnabled( false ); + emit drop( m_old ); + emit apply( m_old = predicate() ); + reset(); + setEnabled( true ); + setFocus(); +} diff --git a/adept/libadept/filterwidget.h b/adept/libadept/filterwidget.h new file mode 100644 index 0000000..78b0c38 --- /dev/null +++ b/adept/libadept/filterwidget.h @@ -0,0 +1,39 @@ +/** -*- C++ -*- + @file adept/filterwidgets.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/entity/package.h> +#include <adept/lister.h> + +#ifndef EPT_FILTERWIDGET_H +#define EPT_FILTERWIDGET_H + +class KLineEdit; + +namespace adept { + +class FilterWidget : public QWidget +{ + Q_OBJECT +public: + FilterWidget( QWidget *parent = 0, const char *n = 0 ) + : QWidget( parent, n ) {} + virtual ListerPredicate predicate() = 0; + void connectLister( Lister *l ); +protected slots: + void changedInternal(); + void applyInternal(); + virtual void reset() = 0; +signals: + void changed( ListerPredicate op ); + void apply( ListerPredicate op ); + void drop( ListerPredicate op ); +protected: + ListerPredicate m_old; +}; + +} + +#endif diff --git a/adept/libadept/groupeddesktopselector.cpp b/adept/libadept/groupeddesktopselector.cpp new file mode 100644 index 0000000..68afa98 --- /dev/null +++ b/adept/libadept/groupeddesktopselector.cpp @@ -0,0 +1,137 @@ +/** -*- C++ -*- + @file adept/groupeddestkopselector.cpp + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qobjectlist.h> +#include <qvbox.h> +#include <qlabel.h> +#include <qtimer.h> +#include <kiconloader.h> +#include <kglobal.h> +#include <kseparator.h> +#include <kapplication.h> + +#include <apt-front/cache/component/desktop.h> +#include <adept/groupeddesktopselector.h> +#include <adept/desktoplist.h> +#include <adept/utils.h> + +using namespace aptFront; +using namespace cache; + +namespace adept { + +GroupedDesktopSelector::GroupedDesktopSelector( QWidget *p, const char *n ) + : KJanusWidget( p, n, IconList ), m_policy( 0 ) +{ + observeComponent< cache::component::Packages >(); + m_pages.push_back( addPage( QString( "Initializing..." ) ) ); + QObjectList *chld = queryList( "QWidget" ); + QObjectListIt it( *chld ); QWidget *o; + while ((o = dynamic_cast< QWidget * >( it.current() )) != 0) { + if ( dynamic_cast< QLabel * >( o ) != 0 ) + o->hide(); + if ( dynamic_cast< KSeparator * >( o ) != 0 ) + o->hide(); + ++it; + } // *hack* + + // AAAA hack + QLayoutIterator li = layout()->iterator(); + QHBoxLayout *hbox = 0; + while ( li.current() != 0 ) { + hbox = dynamic_cast< QHBoxLayout * >( li.current() ); + if ( hbox ) break; + ++li; + } + kdDebug() << "hacking hbox = " << hbox << endl; + if ( hbox ) { + li = hbox->iterator(); + while ( li.current() != 0 ) { + QSpacerItem *spacer = dynamic_cast< QSpacerItem * >( li.current() ); + if ( spacer ) { + hbox->removeItem( spacer ); + delete spacer; + } + ++li; + } + } +} + +void GroupedDesktopSelector::notifyPreRebuild( component::Base * ) { + clear(); +} + +void GroupedDesktopSelector::notifyPostRebuild( component::Base * ) { + // QTimer::singleShot( 0, this, SLOT( fill() ) ); +} + +void GroupedDesktopSelector::clear() +{ + if ( !m_pages.empty() ) + showPage( m_pages.front() ); + while ( !m_pages.empty() ) { + removePage( m_pages.back() ); + delete m_pages.back(); + m_pages.pop_back(); + } +} + +void GroupedDesktopSelector::fill() +{ + component::Desktop &d = cache::Global::get().component< component::Desktop >(); + fill( d.entries() ); +} + +void GroupedDesktopSelector::fill( component::Desktop::EntityRange r ) +{ + component::Desktop &d = cache::Global::get().component< component::Desktop >(); + utils::Range< std::string > gr; + QString last = pageTitle( activePageIndex() ); + + clear(); + + bool shown = false; + + for ( gr = d.availableGroups( r ); gr != gr.end(); gr.advance() ) { + + component::Desktop::EntityRange cr = d.group( *gr ); + QString name = u8( *gr ); + std::cerr << "group for " << cr->name() << ": " << r->group() << std::endl; + name = ( name != u8( "" ) ? name : u8( "Legacy" ) ); + + QPixmap icon( KGlobal::iconLoader()->iconPath( + policy() ? policy()->iconForGroup( name ) : u8( "" ), -32 ) ); + + QVBox *b = addVBoxPage( name, name, icon ); + m_pages.push_back( b ); + std::cerr << "creating list for " << *gr << std::endl; + + DesktopList *l = new DesktopList( b ); + l->setTitle( name ); + connect( l, SIGNAL( request( cache::entity::Package, + cache::component::State::Action ) ), + this, SIGNAL( request( cache::entity::Package, + cache::component::State::Action ) ) ); + connect( l, SIGNAL( showDescription( cache::entity::Desktop ) ), + this, SIGNAL( showDescription( cache::entity::Desktop ) ) ); + + l->insertRange( intersectionRange( r, cr ) ); + // l->insertRange( cr ); + + std::cerr << "created list for " << *gr << std::endl; + if ( name == last ) { + showPage( b ); + shown = true; + } + kapp->processEvents(); + } + + if ( m_pages.empty() ) + m_pages.push_back( addPage( QString( "No Results" ) ) ); + if ( !shown ) + showPage( pageIndex( m_pages.front() ) ); +} + +} diff --git a/adept/libadept/groupeddesktopselector.h b/adept/libadept/groupeddesktopselector.h new file mode 100644 index 0000000..a54f7aa --- /dev/null +++ b/adept/libadept/groupeddesktopselector.h @@ -0,0 +1,39 @@ +/** -*- C++ -*- + @file adept/groupeddestkopselector.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <kjanuswidget.h> +#include <apt-front/cache/entity/desktop.h> + +namespace adept { +using namespace aptFront; +using namespace aptFront::cache; + +// XXX needs fixing +class GroupedDesktopSelector : public KJanusWidget, cache::Observer +{ + Q_OBJECT +public: + struct IconPolicy { + virtual QString iconForGroup( QString group ) { return group; } + }; + GroupedDesktopSelector( QWidget *p = 0, const char *n = 0 ); + void fill( component::Desktop::EntityRange r ); + void setPolicy( IconPolicy *p ) { m_policy = p; } + IconPolicy *policy() { return m_policy; } + virtual void notifyPreRebuild( cache::component::Base * ); + virtual void notifyPostRebuild( cache::component::Base * ); +public slots: + void clear(); + void fill(); +signals: + void request( cache::entity::Package, cache::component::State::Action ); + void showDescription( cache::entity::Desktop ); +protected: + IconPolicy *m_policy; + std::vector< QWidget * > m_pages; + // IconPolicy m_defaultPolicy; +}; + +} diff --git a/adept/libadept/installerview.cpp b/adept/libadept/installerview.cpp new file mode 100644 index 0000000..eac9dc7 --- /dev/null +++ b/adept/libadept/installerview.cpp @@ -0,0 +1,88 @@ +#include <qlineedit.h> +#include <qcombobox.h> +#include <qtextbrowser.h> +#include <qcheckbox.h> +#include <klocale.h> + +#include <apt-front/cache/entity/desktop.h> +#include <apt-front/predicate/factory.h> +#include <apt-front/cache/component/tags.h> +#include <adept/installerview.h> +#include <adept/packageinfo.h> +#include <adept/utils.h> + +using namespace adept; +using namespace aptFront; +using namespace cache; + +void InstallerView::rebuild() +{ + typedef predicate::Factory< entity::Desktop > Factory; + if ( m_inRebuild ) { + QTimer::singleShot( 500, this, SLOT( rebuild() ) ); + return; + } + m_inRebuild = true; + + component::Desktop &d = cache::Global::get().component< component::Desktop >(); + component::Tags &t = + cache::Global::get().component< component::Tags >(); + + Predicate p = predicate::True< entity::Desktop >(); + if ( m_search->text() != u8( "" ) ) { + Predicate tmp = Factory::name( u8( m_search->text() ) ) + or Factory::description( u8( m_search->text() ) ); + p = p and tmp; + } + + std::string st = ""; + int si = m_suite->currentItem(); + + if ( si == 0 ) st = "suite::kde"; + if ( si == 1 ) st = "suite::gnome"; + + if ( st != "" ) + p = p and Factory::tag( t.tagByName( st ) ); + + if ( !m_unsupported->isChecked() ) { + p = p and not Factory::sectionSubstring( "contrib" ) + and not Factory::sectionSubstring( "universe" ) + and not Factory::sectionSubstring( "multiverse" ); + } + + if ( !m_nonfree->isChecked() ) { + p = p and not Factory::sectionSubstring( "non-free" ) + and not Factory::sectionSubstring( "multiverse" ) + and not Factory::sectionSubstring( "restricted" ); + } + + selector()->fill( filteredRange( d.entries(), p ) ); + + m_inRebuild = false; +} + +InstallerView::InstallerView( QWidget *p , const char *n ) + : InstallerViewUi( p, n ), m_inRebuild( false ) +{ + connect( m_search, SIGNAL( textChanged( const QString & ) ), + this, SLOT( textChanged() ) ); + connect( &timer, SIGNAL( timeout() ), this, SLOT( rebuild() ) ); + connect( m_suite, SIGNAL( activated( int ) ), this, SLOT( rebuild() ) ); + connect( m_unsupported, SIGNAL( toggled( bool ) ), this, SLOT( rebuild() ) ); + connect( m_nonfree, SIGNAL( toggled( bool ) ), this, SLOT( rebuild() ) ); + connect( selector(), SIGNAL( showDescription( cache::entity::Desktop ) ), + this, SLOT( showDescription( cache::entity::Desktop ) ) ); +} + +void InstallerView::textChanged() { + timer.start( 1000, true ); +} + +void InstallerView::showDescription( entity::Desktop e ) +{ + kdDebug() << "InstallerView::showDescription..." << endl; + m_description->setText( u8( "<b>" ) + e.name() + u8( "</b>" ) + + i18n( "<br><b>Package:</b> " ) + e.package().name() + + formatLongDescription( + e.package().longDescription( std::string( "" ) ) ) ); +} diff --git a/adept/libadept/installerview.h b/adept/libadept/installerview.h new file mode 100644 index 0000000..ed955dc --- /dev/null +++ b/adept/libadept/installerview.h @@ -0,0 +1,33 @@ +/** -*- C++ -*- + @file adept/installerview.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qtimer.h> +#include <adept/installerviewui.h> +#include <adept/groupeddesktopselector.h> + +#ifndef EPT_INSTALLERVIEW_H +#define EPT_INSTALLERVIEW_H + +namespace adept { +class InstallerView : public InstallerViewUi +{ + Q_OBJECT +public: + typedef predicate::Predicate< entity::Desktop > Predicate; + InstallerView( QWidget *p = 0, const char *n = 0 ); + GroupedDesktopSelector *selector() { return m_selector; } +protected slots: + void textChanged(); + void showDescription( cache::entity::Desktop ); +public slots: + void rebuild(); +protected: + bool m_inRebuild; + QTimer timer; +}; + +} + +#endif diff --git a/adept/libadept/installerviewui.ui b/adept/libadept/installerviewui.ui new file mode 100644 index 0000000..6f8b5d7 --- /dev/null +++ b/adept/libadept/installerviewui.ui @@ -0,0 +1,194 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>InstallerViewUi</class> +<widget class="QWidget"> + <property name="name"> + <cstring>InstallerViewUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>666</width> + <height>314</height> + </rect> + </property> + <property name="caption"> + <string>Form1</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLayoutWidget" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>4</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Search:</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_search</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>KDE</string> + </property> + </item> + <item> + <property name="text"> + <string>GNOME</string> + </property> + </item> + <item> + <property name="text"> + <string>Any Suite</string> + </property> + </item> + <property name="name"> + <cstring>m_suite</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Show:</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_unsupported</cstring> + </property> + <property name="text"> + <string>unsupported,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_nonfree</cstring> + </property> + <property name="text"> + <string>proprietary software.</string> + </property> + </widget> + </hbox> + </widget> + <widget class="adept::GroupedDesktopSelector" row="1" column="0"> + <property name="name"> + <cstring>m_selector</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>6</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QTextBrowser" row="1" column="1"> + <property name="name"> + <cstring>m_description</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>4</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </grid> +</widget> +<customwidgets> + <customwidget> + <class>adept::GroupedDesktopSelector</class> + <header location="local">adept/groupeddesktopselector.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</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="PNG" length="1122">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042949444154388db5954d6c545514c77ff7de37eff1a6a550da994e5ba798868f948fc847a2a2911816c436b0a02ed0083161a1981877ee10d90aa94656063491882c5cd4c4b8103f20cd806909a98604da8482341de80cb69de9bcd799799d79efba980f1da3a80b4f727273939bdff99f9b93f3175a6b6a21849080020c4002a29a8f0a5dcd002803bed63a1035f0d0d0504b6f6fef51d7758fa4d3e98d8ee3fc03af128ee3303939399548242eb8aefb09300f78464de9f0f0f0d148cc7caf3d5424de97a7ec17104220242805520a44557bbd4b21f083801d33e63a6d1bc7bf19c6064e0319a35a58b9ae7ba43d54e4d7c54b64dc097c7f09d30ef04b36736983cc7c11b4456b9b492c5e20dc54a6540e00896a8268a7017010f8bcae1830d2e9f4c69ebe3c197782b2ce60d94ddc9b30f9feeb45ae5d7181c5ead35636ef08d3ffe26a76ee3208b4031a56d80aa00768fda362e9380e25bf80ef3b587613d7afc099533380a4b5dda46fcb5aa42998b9eb7173dce5e6788e434763ec7fc942532008ea436003660d2caa7f8d69c3bd8910674e4d033e83877ad8d36fb0aa4d6058658ac5358c5df6383bf480f31fdda5a3632bbbfb6da4ccd5c00a10b2012cc12fd97cfb5516f0187c25cee0619396480ec3ca909d0f3372d1e5f9fe66de3ad605587c712ec55256a2540d5519d19ae24a29057329839f7ecc138944d833102290f3184ae1e6d6f0e98739c61229e6d21eafbed1c9c8c5558c8f3ee4ceed76946a1c43d97091828585223e2eebfbc295f60d45de89707628cb58224577bc85a79e5d4d786581cddb9b0148259711b20145836221400416e0232d1f6595c9ce4538773ac7b54406f0b15784e8e80aa1ac2594190220d021e49f2437960156b70ba095e95f96f18acd8c263cc6122962b1167a7ba34cdd7ec8c977a699bed546722a8fc2a02b6e2185fff78ab586ce78894ddb9ab9f5738ed14b1e030756929d8ff2e4ae5544632b38f96e89a99b298ebd6950cc2d12ed0eb3618b26f520788462ad09877df60db600f0f1fb49c646f21c7ebd836dcf94e9d9b4c0db27d6d3bd36c6426a96bce731703046d7da129a4670836284a054869d4f1b1c7e2dca67676ef3c1898091ef5ad8bc358c3205c93bf7c9a40ad4c660f4728edd7bbb3142ea2fc1da711cfc200011e08b45f6bd1c261adbce9717928c5f9d63fc6a19f0014567773303073790f8214bd6f5282dfbb8b9fa1f6b40d7c1939393533b92e63ad9240990484aec7e41b27d579cbb531e0f67023492d86316ebb768ba1e0f786e6f37e56550c62237aee7011e54abd7c1412291b8a06de378b4d3c0b215da9708e5a3a442192085404a83d4accfecac067c0c43e13a70e3fa12e96409e0325000966bbb354465339d04a6f9dd15fe6dde07ce030780278088d05ad72cc9a6b2f2daaaa74d75a1f0e8d0d5f60b40868a8364ead6248430000b0857a126ffcdf396abf03ce089ffcb4c7f033046c6b4a995e7a00000000049454e44ae426082</data> + </image> +</images> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>adept/groupeddesktopselector.h</includehint> +</includehints> +</UI> diff --git a/adept/libadept/lister.cpp b/adept/libadept/lister.cpp new file mode 100644 index 0000000..85142c3 --- /dev/null +++ b/adept/libadept/lister.cpp @@ -0,0 +1,707 @@ +// -*- Mode: C++; c-basic-offset: 4; -*- +#include <qlabel.h> +#include <qtimer.h> +#include <qpainter.h> +#include <qpushbutton.h> +#include <qthread.h> +#include <qtextbrowser.h> + +#include <kpopupmenu.h> +#include <kdebug.h> +#include <klineedit.h> +#include <klocale.h> +#include <kapplication.h> +#include <kglobal.h> +#include <kiconloader.h> + +#include <functional> +#include <iostream> + +#include <apt-front/cache/cache.h> +#include <apt-front/actor.h> +#include <apt-front/cache/component/packages.h> +#include <apt-front/cache/component/state.h> +#include <apt-front/predicate/factory.h> + +#include <adept/utils.h> +#include <adept/lister.h> +#include <adept/packageinfo.h> + +using namespace aptFront; +using namespace aptFront::predicate; +using namespace aptFront::cache; +using namespace aptFront::utils; +using namespace adept; + +Lister::Lister( QWidget *parent, const char *name ) + : ExtendableList( parent, name ), + m_rangeProvider( 0 ), + m_baseF( predicate::True< entity::Entity >() ), + m_interactiveF( True<entity::Entity>() ), m_itemCount( -1 ), + m_rebuildScheduled( false ), m_inRebuild( false ), m_cancelRebuild( false ), + m_openToplevel( false ), m_rebuildMutex( true ) +{ + observeComponent< component::State >(); + observeComponent< component::Packages >(); + observeComponent< component::PackageTags >(); + setRootIsDecorated( false ); + setSelectionModeExt( Extended ); + setAllColumnsShowFocus (true); + + m_icons[ u8( "package-install" ) ] = u8( "adept_install" ); + m_icons[ u8( "package-remove" ) ] = u8( "adept_remove" ); + m_icons[ u8( "package-upgrade" ) ] = u8( "adept_upgrade" ); + m_icons[ u8( "package-keep" )] = u8( "adept_keep" ); + m_icons[ u8( "package-reinstall" )] = u8( "adept_reinstall" ); + m_icons[ u8( "package-purge" )] = u8( "adept_purge" ); + + setSorting( -1 ); + // addColumn(" ", 40); + // addColumn(" ", 18); + addColumn( i18n( "Package" ), 180); + addColumn( i18n( "Status" ), 110); + addColumn( i18n( "Requested" ), 90); + addColumn( i18n( "Description" ), 300); + setToggleColumn( 0 ); + + setResizeMode (LastColumn); + connect( this, SIGNAL( selectionChanged() ), SLOT( updateActions() ) ); + connect( this, + SIGNAL( contextMenuRequested( QListViewItem *, + const QPoint &, int ) ), + this, SLOT( + contextMenu( QListViewItem *, const QPoint &, int) ) ); + m_tip = 0; + // m_tip = new ListerTooltip( viewport(), this ); +} + +Lister::~Lister() +{ + delete m_tip; +} + +void Lister::scheduleRebuild() +{ + if (!m_rebuildScheduled) { + // kdDebug() << "Lister scheduling rebuild" << endl; + QTimer::singleShot( 0, this, SLOT( rebuild() ) ); + } + m_rebuildScheduled = true; +} + +void Lister::updateActions() +{ + emit actionsChanged( this ); +} + +void Lister::notifyPostChange( component::Base * ) +{ + kdDebug() << "notifyRefresh()" << endl; + updateActions(); + triggerUpdate(); +} + +void Lister::notifyPreRebuild( component::Base *b ) +{ + kdDebug() << "Lister::notifyPreRebuild( " << b << " )" << endl; + Cache &c = cache::Global::get( m_cache ); + setEnabled( false ); + if ( dynamic_cast< component::PackageTags * >( b ) != 0 ) { + kdDebug() << "clearing cardinality" << endl; + m_cardinality.clear(); + } + if ( dynamic_cast< component::Packages * >( b ) != 0 ) { + kdDebug() << "clearing lister" << endl; + clear(); + m_items.clear(); + m_cardinality.clear(); + } +} + +void Lister::notifyPostRebuild( component::Base *b ) +{ + kdDebug() << "Lister::notifyPostRebuild( " << b << " )" << endl; + scheduleRebuild(); + if ( dynamic_cast< component::State * >( b ) != 0 ) { + setEnabled( true ); + } +} + +bool lessByName( const entity::Entity &e1, const entity::Entity &e2 ) +{ + if ( e1.is< entity::Named >() && e2.is< entity::Named >() ) { + entity::Named &n1 = downcast< entity::Named >( e1 ), + &n2 = downcast< entity::Named >( e2 ); + return n1.name() < n2.name(); + } + return e1 < e2; +} + +bool Lister::cancelRebuild() { + // kdDebug() << "cancel rebuild: " << m_inRebuild << ", " << m_cancelRebuild << endl; + if ( m_inRebuild ) { + m_rebuildScheduled = false; + m_cancelRebuild = true; + } + if ( !cache::Global::get( m_cache ).isOpen() ) { + m_rebuildScheduled = false; + return true; + } + return m_cancelRebuild; +} + +void Lister::cleanRebuild() +{ + scheduleRebuild(); +} + +Lister::CreateItem::CreateItem( Lister *_l, ListerItem *p ) + : l( _l ), time( 0 ), items( 0 ), last( 0 ), parent( p ) +{ +} + +Lister::CreateItem::~CreateItem() +{ + // delete timer; +} + +Lister::Map::value_type Lister::CreateItem::operator()( entity::Entity e ) +{ + items ++; + if ( l->m_cancelRebuild ) throw 0; // XXX proper exception please + // kdDebug() << "trying to acquire mutex" << endl; + l->m_rebuildMutex.lock(); + // kdDebug() << "mutex acquired" << endl; + + // count tags + if ( e.is< entity::Package >() ) { + const entity::Tag::Set &tags = downcast< entity::Package >( e ).tags(); + for (entity::Tag::Set::iterator i = tags.begin(); i != tags.end(); ++ i ) + l->m_cardinality[ *i ] ++; + } + + if ( last ) { + if ( parent ) + last = new ListerItem( parent, last, e ); + else + last = new ListerItem( l, last, e ); + } else { + if ( parent ) + last = new ListerItem( parent, e ); + else + last = new ListerItem( l, e ); + } + l->m_rebuildMutex.unlock(); + if ( e.is< entity::Relation >() ) + // this should be safe because the parent thread is waiting + // for us and ensures that universe (libapt-front) is kept + // unchanged while we run + l->insertRangeInternal( InsertRangePair( + last, downcast< entity::Relation >( e ).targetPackages() ) ); + // we may want to use recursive async call instead? why? + /* Threads::enqueue( + asyncCall( std::bind2nd( std::mem_fun( &Lister::insertRangeInternal ), + InsertRangePair( + last, + downcast< entity::Relation >( e ).targetPackages() ) ), + l ), &(l->m_rebuildMutex) ); + */ + return std::make_pair( e, last ); +} + +void Lister::reallyUpdate() +{ + bool en = isUpdatesEnabled(); + setUpdatesEnabled( true ); + triggerUpdate(); + setUpdatesEnabled( en ); +} + +void Lister::insertRange( Range r ) { + insertRangeInternal( InsertRangePair( 0, r ) ); +} +void Lister::insertRangeInternal( InsertRangePair a ) +{ + // kdDebug() << "insertRange running..." << endl; + try { + std::transform( a.second, a.second.end(), + inserter( m_items, m_items.begin() ), + CreateItem( this, a.first ) ); + } catch ( ... ) {} + m_itemCount = m_items.size(); +} + +/* void Lister::rebuildInsertRange( Range r ) { + insertRange( 0, r ); + } */ + +void Lister::rebuild() +{ + Cache &c = cache::Global::get( m_cache ); + if ( cancelRebuild() ) { + scheduleRebuild(); + return; + } + + m_inRebuild = true; + m_rebuildMutex.lock(); + + emit rebuildStarted(); + + c.progress().OverallProgress( 0, 0, 0, i18n( "Filtering" ) ); + kdDebug() << "rebuild running" << endl; + clock_t _c = clock(), C; + for ( Cardinality::iterator i = m_cardinality.begin(); + i != m_cardinality.end(); ++i ) + i->second = 0; + + kdDebug() << "querying m_rangeProvider " << m_rangeProvider << "..." << endl; + + Range r = filteredRange( m_rangeProvider ? + m_rangeProvider->listerRange() : range( VectorRange() ), + m_baseF ); + C = (clock() - _c) / 1000; _c = clock(); + + setUpdatesEnabled( false ); + kdDebug() << "clearing..." << endl; + clear(); + m_items.clear(); + + kdDebug() << "asyncCall to rebuildInsertRange..." << endl; + QThread *t = asyncCall( std::bind2nd( + std::mem_fun( &Lister::insertRangeInternal ), + InsertRangePair( 0, r ) ), + this ); + + kdDebug() << "starting the thread..." << endl; + + QTimer timer; + connect( &timer, SIGNAL( timeout() ), + this, SLOT( reallyUpdate() ) ); + timer.start( 0 ); + + m_rebuildMutex.unlock(); + Threads::enqueue( t, &m_rebuildMutex ); + Threads::wait(); + + timer.stop(); + + kdDebug() << "thread finished..." << endl; + C = (clock() - _c) / 1000; _c = clock(); + kdDebug() << m_items.size() << " entities synced, time = " << C << endl; + + setUpdatesEnabled( true ); + c.progress().Done(); + if ( m_openToplevel ) openToplevel(); + triggerUpdate(); + + if ( !m_cancelRebuild ) { + for ( Cardinality::iterator i = m_cardinality.begin(); + i != m_cardinality.end(); ++i ) + if ( i->second == m_itemCount ) + i->second = -1; + emit cardinalityChanged( m_cardinality ); + } + + m_inRebuild = false; + m_rebuildScheduled = false; + m_cancelRebuild = false; + emit rebuildFinished(); +} + +void Lister::baseAnd( Predicate o ) +{ + m_baseF = predicate::predicate( m_baseF and o ); + // emit filterChanged( m_baseF ); + cancelRebuild(); + scheduleRebuild(); +} + +void Lister::baseSet( Predicate o ) +{ + m_baseF = o; + // emit filterChanged( m_baseF ); + cancelRebuild(); + scheduleRebuild(); +} + +void Lister::interactiveAnd( Predicate o ) +{ + m_interactiveF = predicate::predicate( m_interactiveF and o ); + cancelRebuild(); + scheduleRebuild(); +} + +void Lister::interactiveDrop( Predicate o ) +{ + m_interactiveF = predicate::remove( m_interactiveF, o ); + cancelRebuild(); + scheduleRebuild(); +} + +bool Lister::itemSelected( Map::value_type i ) +{ + return not i.second->isSelected(); +} + +entity::Entity Lister::extractKey( Map::value_type i ) +{ + return i.first; +} + +Lister::VectorRange Lister::selection() +{ + VectorRange ret; + Map m; + std::remove_copy_if( m_items.begin(), m_items.end(), + inserter( m, m.begin() ), + itemSelected ); + std::transform( m.begin(), m.end(), + consumer( ret ), + extractKey ); + return ret; +} + +Lister::VectorRange Lister::content() +{ + VectorRange ret; + std::transform( m_items.begin(), m_items.end(), + consumer( ret ), + extractKey ); + return ret; +} + +QString ListerItem::text( int column ) const +{ + // if (column == 0) return ""; // until we redo paintcell for the col + if (entity().is<entity::Package>()) { + entity::Package p = entity(); + switch (column) { + case 0: return u8( p.name( u8( i18n( "n/a" ) ) ) ); + case 1: return u8( p.statusString( u8( i18n( "n/a" ) ) ) ); + case 2: return u8( p.actionString( u8( i18n( "n/a" ) ) ) ); + case 3: return u8( p.shortDescription( u8( i18n( "n/a" ) ) ) ); + // case 2: return p.candidateVersion().versionString(); + } + } + if ( entity().is< entity::Relation >() && column == 0 ) + return downcast< entity::Relation >( entity() ).format(); + return u8( "" ); +} + +void ListerItem::paintCell (QPainter *p, const QColorGroup &cg, + int column, int width, int alignment ) +{ + if ( width <= 0 ) + return; + QColorGroup _cg( cg ); + QColor c = _cg.text(); + QPixmap pm( width, height() ); + QPainter _p( &pm ); + if (entity().is<entity::Package>()) { + entity::Package p = entity(); + if (column == 1) + c = statusColor( p ); + if (column == 2) + c = actionColor( p ); + } + _cg.setColor( QColorGroup::Text, c ); + KListViewItem::paintCell( &_p, _cg, column, width, AlignTop ); + p->drawPixmap( 0, 0, pm ); +} + +void Lister::contextMenu( QListViewItem *it, const QPoint &pt, int /*c*/ ) +{ + if (! it) // check for actor when we have one... + return; + m_context = dynamic_cast< ListerItem * >( it ); + VectorRange sel = selection(); + // entity::Package p = (dynamic_cast<ListerItem *>(it)->entity()); + KPopupMenu *m = new KPopupMenu (this); + utils::Range< Actor > r = actor::Global< entity::Package >::list(); + int id = 8; + try { + for (; r != r.end(); ++r) { + m->insertItem( SmallIconSet( m_icons[ u8( r->name() ) ] ), + r->prettyName(), id ); + m->setItemEnabled( + id, r->possible( utils::upcastRange< entity::Package >( sel ) ) ); + ++id; + } + } catch ( std::bad_cast ) {} // ignore (this is broken, but + // easiest fix) + bool open = m_context->extender(); + m->insertItem( open ? i18n( "Hide details" ) : + i18n( "Show details" ), open ? 1 : 0 ); + connect(m, SIGNAL(activated(int)), this, SLOT(contextActivated(int))); + m->exec(pt); + delete m; +} + +void Lister::contextActivated( int id ) +{ + VectorRange sel = selection(); + try { + if (id >= 8) { + utils::Range< Actor > r = actor::Global< entity::Package >::list(); + std::advance( r, id - 8 ); + (*r)( utils::upcastRange< entity::Package >( sel ) ); + updateActions(); + } + if (id < 8) { + VectorRange i = sel.begin(); + while (i != i.end()) { + if (id == 0) + m_items[*i]->showExtender(); + if (id == 1) + m_items[*i]->hideExtender(); + ++ i; + } + } + } catch ( std::bad_cast ) {} // ignore (this is broken, but +} + +ListerItemExtender::~ListerItemExtender() +{ +} + +ListerItemExtender::ListerItemExtender( QWidget *parent, const char * n) + : ListerItemExtenderUi( parent, n ) +{ + observeComponent< component::State >(); + adjustFontSize( m_description, -1 ); + connect( m_details, SIGNAL( clicked() ), + this, SLOT( detailsClicked() ) ); + + m_packageInfo->adjustFontSize( -1 ); + m_packageInfo->hideStatus(); +} + +void ListerItemExtender::detailsClicked() { + detailsRequested( m_entity ); +} + +ListerItem *ListerItemExtender::item() +{ + return dynamic_cast< ListerItem * >( m_item ); +} + +void ListerItemExtender::mouseReleaseEvent( QMouseEvent *e ) { + e->ignore(); + if ( childAt( e->pos() ) != static_cast< QWidget * >( m_name ) ) + e->accept(); +} +void ListerItemExtender::setItem( ExtendableItem *i ) +{ + ItemExtender::setItem( i ); + m_entity = item()->entity(); + // setupColors(); + + kdDebug() << "ListerItemExtender::setItem connecting" << endl; + connect( this, SIGNAL( detailsRequested( Lister::Entity ) ), + item()->list(), SIGNAL( detailsRequested( Lister::Entity ) ) ); + + entity::Version v; + entity::Package p; + + if ( m_entity.is< entity::Version >() ) { + v = m_entity; + p = v.package(); + } + + if ( m_entity.is< entity::Package >() ) { + p = m_entity; + v = p.anyVersion(); + } + + if ( !v.valid() ) { + m_logical->setText( i18n( "Immutable" ) ); + m_logical->setEnabled( false ); + m_details->setEnabled( false ); + return; + } + + m_name->setText( /* QString( "<b>" ) + */ + v.package().name( std::string( "oops" ) ) /* + "</b>" */ ); + QString l = u8( v.longDescription( + u8( i18n( "No long description available" ) ) ) ); + + m_description->setText( QString( "<qt>" ) + + formatLongDescription( l ) + "</qt>" ); + m_description->adjustSize(); + m_description->installEventFilter( this ); + + m_packageInfo->setVersion( v, m_entity.is< entity::Version >() ); + + notifyPostChange( 0 ); +} + +void ListerItemExtender::notifyPostRebuild( component::Base *b ) +{ // need to catch undo/redo effects + return notifyPostChange( b ); +} + +void ListerItemExtender::notifyPostChange( component::Base * ) +{ + // without the timer to break it, there could be a loop where + // we connect the clicked() signal to a slot which would be + // invoked right away when we return -> evil + QTimer::singleShot( 0, this, SLOT( updateLogical() ) ); +} + +void ListerItemExtender::updateLogical() { + entity::Package pkg = entity(); + EntityActor *a = 0; + + m_status->setText( colorify( + statusColor( pkg ), + u8( pkg.statusString( u8( i18n( "Unknown" ) ) ) ) ) ); + m_change->setText( colorify( + actionColor( pkg ), + u8( pkg.actionString( u8( i18n( "Unknown" ) ) ) ) ) ); + + + m_logical->setEnabled( true ); + if (pkg.canUpgrade()) { + a = new EntityActor( pkg.upgrade() ); + } else if (pkg.canInstall()) { + a = new EntityActor( pkg.install() ); + } else if (pkg.canKeep()) { + a = new EntityActor( pkg.keep() ); + } else if (pkg.canRemove()) { + a = new EntityActor( pkg.remove() ); + } + + if (a) { + m_logical->setText( u8( a->actor().prettyName() ) ); + connect( m_logical, SIGNAL( clicked() ), + a, SLOT( destructiveAct() ) ); + } else { + m_logical->setText( i18n( "Immutable" ) ); + m_logical->setEnabled( false ); + } + +} + +bool ListerItemExtender::eventFilter( QObject *o, QEvent *e ) +{ + if (o == m_description && e->type() == QEvent::Wheel) { + // kdDebug() << "discarding wheel event..." << endl; + QApplication::sendEvent( this, e ); + return true; + } + return false; +} + +void ListerItemExtender::resize( int w, int h ) +{ + int namew = - item()->lister()->extenderOffset( item() ) - 2 + - layout()->margin() + - layout()->spacing() + + item()->lister()->columnWidth( 0 ); + int statw = item()->lister()->columnWidth( 1 ) + - layout()->spacing(); + int chw = item()->lister()->columnWidth( 2 ) - 2 + - layout()->spacing(); + m_name->setMinimumWidth( namew ); + m_status->setMinimumWidth( statw ); + m_change->setMinimumWidth( chw ); + m_packageInfo->adjustSize(); + m_leftHeight = m_name->height() + m_packageInfo->height() + + m_logical->height() + 20; + QWidget::resize( w, 500 ); + QWidget::resize( + w, + QMAX( m_description->contentsHeight() + 16, + m_leftHeight ) ); +} + +bool entityLess::operator()( entity::Entity e1, entity::Entity e2 ) +{ + if ( e1.is< entity::Package >() ) { + if ( e2.is< entity::Package >() ) + return e1 < e2; + return true; + } + + if ( e1.is< entity::Version >() ) { + if ( e2.is< entity::Package >() ) + return false; + if ( e2.is< entity::Version >() ) + return e1 < e2; + return true; + } + + if ( e1.is< entity::Relation >() ) { + if ( e2.is< entity::Package >() ) + return false; + if ( e2.is< entity::Version >() ) + return false; + if ( e2.is< entity::Relation >() ) + return e1 < e2; + return true; + } + return true; +} + +bool ListerItem::less( const ExtendableItem *b ) const +{ + entity::Entity e1 = entity(), e2 = dynamic_cast< const ListerItem * >( b )->entity(); + return entityLess()( e1, e2 ); +} + +bool ListerItem::keepLess( const ListerItem *o ) const +{ + const ListerItem *b = o; + while ( b != 0 ) { + if ( b == this ) + return false; + b = b->m_previous; + } + while ( o != 0 ) { + o = dynamic_cast< const ListerItem * >( o->nextSibling() ); + if ( o == this ) + return true; + } + return false; +} + +QString ListerTooltip::format( const QString &what, + const QString &txt, bool nobr ) +{ + QString ret = "<b>" + what + "</b> " + (nobr ? "<nobr>" : "") + + txt + (nobr ? "</nobr>" : "") + "<br>"; + return ret; +} + +void ListerTooltip::maybeTip( const QPoint &pt ) +{ + if ( !m_parent ) + return; + kdDebug() << "ListTreeWidgetTooltip::maybeTip ()" << endl; + ListerItem *x = dynamic_cast<ListerItem *>( m_parent->itemAt( pt ) ); + if ( !x ) + return; + if ( x->extender() ) + return; // no tips for extended items, thank you + QString str = u8( "<qt>" ); + QString descr, cand, cur; + descr = cand = cur = i18n( "<i>Not available</i>" ); + entity::Package p( x->entity() ); + descr = p.shortDescription( std::string( + i18n( "<i>Not available</i>" ).local8Bit() ) ); + try { + cand = u8( p.candidateVersion().versionString() ); + } catch (...) {} + try { + cur = u8( p.installedVersion().versionString() ); + } catch (...) {} + + str += format( i18n( "Package:" ), u8( p.name() ) ); + str += format( i18n( "Description:" ), descr ); + str += format( i18n( "Current Version:" ), cur ); + str += format( i18n( "Candidate Version:" ), cand ); + + str.append( u8( "</qt>" ) ); + tip( m_parent->itemRect( x ), str ); +} diff --git a/adept/libadept/lister.h b/adept/libadept/lister.h new file mode 100644 index 0000000..dede538 --- /dev/null +++ b/adept/libadept/lister.h @@ -0,0 +1,220 @@ +/** -*- C++ -*- + @file adept/lister.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qtooltip.h> +#include <qmap.h> +#include <qmutex.h> +#include <set> + +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/entity/package.h> +#include <apt-front/actor.h> +#include <apt-front/predicate/matchers.h> +#include <apt-front/predicate/combinators.h> +#include <apt-front/utils/range.h> + +#include <adept/extendablelist.h> +#include <adept/listerextenderui.h> +#include <adept/actor.h> +#include <adept/listerpredicate.h> + +#ifndef EPT_LISTER_H +#define EPT_LISTER_H + +class KLineEdit; + +namespace adept { + +using namespace aptFront; +using namespace aptFront::cache; +class ListerTooltip; +class ListerItemExtender; +class ListerItem; +class Lister; + +struct entityLess { + bool operator()( entity::Entity e1, entity::Entity e2 ); +}; + +class Lister: public ExtendableList, public Observer +{ + Q_OBJECT +public: + typedef entity::Entity Entity; + typedef std::vector< Entity > Vector; + typedef utils::Range< Entity > Range; + typedef utils::VectorRange< Entity > VectorRange; + typedef std::set< Entity > Set; + typedef std::map< Entity, ListerItem *, entityLess > Map; + typedef actor::Actor< entity::Package > Actor; + typedef predicate::Predicate< Entity > Predicate; + typedef std::map< cache::entity::Tag, int > Cardinality; + struct RangeProvider { + virtual Range listerRange() = 0; + }; + + Lister (QWidget *parent = 0, const char *name = 0); + ~Lister(); + void setSource(); + virtual void notifyPostChange( component::Base * ); + virtual void notifyPreRebuild( component::Base * ); + virtual void notifyPostRebuild( component::Base * ); + VectorRange selection(); + VectorRange content(); + int itemCount() { return m_itemCount; } + // void setRange( const Range &r ) { m_range = r; } + void setRangeProvider( RangeProvider *r ) { m_rangeProvider = r; } + void insertRange( Range ); + void setOpenToplevel( bool o ) { m_openToplevel = o; } + + bool busy() { return m_rebuildScheduled || m_inRebuild; } + +signals: + // this is adept::Lister because of braindead moc + void actionsChanged( adept::Lister * ); + void cardinalityChanged( const Lister::Cardinality & ); + void detailsRequested( Lister::Entity ); + void rebuildStarted(); + void rebuildFinished(); + // void filterChanged( Lister::Predicate ); + +public slots: + virtual void cleanRebuild(); + virtual void rebuild(); + virtual void baseAnd( ListerPredicate ); + virtual void interactiveDrop( ListerPredicate ); + virtual void interactiveAnd( ListerPredicate ); + virtual void baseSet( ListerPredicate ); + virtual void updateActions(); + virtual void scheduleRebuild(); + virtual void reallyUpdate(); +protected slots: + void contextMenu( QListViewItem *, const QPoint &, int ); + void contextActivated( int ); +protected: + typedef std::pair< ListerItem *, Range > InsertRangePair; + void insertRangeInternal( InsertRangePair ); + ListerTooltip *m_tip; + + static Entity extractKey( Map::value_type ); + static bool itemSelected( Map::value_type ); + + struct CreateItem { + CreateItem( Lister *, ListerItem * ); + ~CreateItem(); + Map::value_type operator()( Entity ); + Lister *l; + int time; + int items; + ListerItem *last; + ListerItem *parent; + }; + + bool cancelRebuild(); + void rebuildInsertRange( Range ); + + ListerItem *m_context; + QMap< QString, QString > m_icons; + Map m_items; + Vector m_all; + RangeProvider *m_rangeProvider; + Predicate m_baseF, m_interactiveF; + int m_itemCount; + bool m_rebuildScheduled:1; + bool m_inRebuild:1; + bool m_cancelRebuild:1; + bool m_openToplevel:1; + Cardinality m_cardinality; + QMutex m_rebuildMutex; +}; + +class ListerTooltip : public QToolTip +{ +public: + ListerTooltip (QWidget *v, Lister *p) : QToolTip (v, 0), m_parent (p) {}; +protected: + QString format( const QString &, const QString &, bool = true ); + virtual void maybeTip (const QPoint &p); + Lister *m_parent; +}; + +class ListerItemExtender : public ListerItemExtenderUi, + public cache::Observer { + Q_OBJECT +public: + ListerItemExtender( QWidget *parent = 0, const char * n = 0 ); + ~ListerItemExtender(); + virtual void resize( int w, int h ); + void setItem( ExtendableItem *i ); + ListerItem *item(); + entity::Entity entity() const { return m_entity; } + void notifyPostChange( component::Base * ); + void notifyPostRebuild( component::Base * ); +protected slots: + void detailsClicked(); + void updateLogical(); +signals: + void detailsRequested( Lister::Entity ); +protected: + bool eventFilter( QObject *o, QEvent *e ); + void mouseReleaseEvent( QMouseEvent *e ); + entity::Entity m_entity; + unsigned m_leftHeight; +}; + +class ListerItem: public ExtendableItem +{ +public: + ListerItem(Lister *v, entity::Entity e) + : ExtendableItem (v), m_previous( 0 ), m_entity( e ) + {} + ListerItem(Lister *v, ListerItem *i, entity::Entity e) + : ExtendableItem( v, i ), m_previous( i ), m_entity( e ) + {} + ListerItem(ListerItem *p, ListerItem *i, entity::Entity e) + : ExtendableItem( p, i ), m_previous( i ), m_entity( e ) + {} + ListerItem(ListerItem *p, entity::Entity e) + : ExtendableItem( p ), m_previous( 0 ), m_entity( e ) + {} + + virtual ItemExtender *createExtender() { + if ( extendable() ) + return new ListerItemExtender(); + return 0; + } + + /* virtual void updateIcon( const QPixmap &p ) { + if ( m_entity.is< entity::Package >() + || m_entity.is< entity::Version >() ) + return ExtendableItem::updateIcon( p ); + setPixmap( list()->toggleColumn(), QPixmap() ); + } */ + + virtual QString text( int column ) const; + entity::Entity entity() { return m_entity; } + const entity::Entity entity() const { return m_entity; } + virtual void paintCell (QPainter *p, const QColorGroup &cg, + int column, int width, int alignment); + virtual bool less( const ExtendableItem * ) const; + Lister *lister() { + return dynamic_cast< Lister* >( listView() ); + } + + // beware, makes sort O(n^2lg(n^2)) + bool keepLess( const ListerItem *o ) const; + virtual bool extendable() const { + return ( entity().is< entity::Package >() + || m_entity.is< entity::Version >() ); + } + +protected: + ListerItem *m_previous; + entity::Entity m_entity; +}; + +} + +#endif /* ifndef PKGLIST_H */ diff --git a/adept/libadept/listerextenderui.ui b/adept/libadept/listerextenderui.ui new file mode 100644 index 0000000..de2e481 --- /dev/null +++ b/adept/libadept/listerextenderui.ui @@ -0,0 +1,310 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::ListerItemExtenderUi</class> +<widget class="adept::ItemExtender"> + <property name="name"> + <cstring>ListerItemExtenderrUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>587</width> + <height>230</height> + </rect> + </property> + <property name="caption"> + <string>ListerItemExtenderrUi</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <spacer row="3" column="1"> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <spacer row="4" column="2"> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>4</height> + </size> + </property> + </spacer> + <spacer row="2" column="3"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>4</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget" row="0" column="1"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_name</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="text"> + <string>name</string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_status</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="text"> + <string>status</string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_change</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="text"> + <string>change</string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + </hbox> + </widget> + <widget class="QTextBrowser" row="0" column="2" rowspan="4" colspan="1"> + <property name="name"> + <cstring>m_description</cstring> + </property> + <property name="focusPolicy"> + <enum>NoFocus</enum> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <property name="resizePolicy"> + <enum>AutoOneFit</enum> + </property> + <property name="vScrollBarMode"> + <enum>AlwaysOff</enum> + </property> + <property name="hScrollBarMode"> + <enum>AlwaysOff</enum> + </property> + <property name="text"> + <string>description...</string> + </property> + </widget> + <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>4</number> + </property> + <property name="spacing"> + <number>4</number> + </property> + <spacer> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>10</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_logical</cstring> + </property> + <property name="text"> + <string>logical</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_details</cstring> + </property> + <property name="text"> + <string>Details</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer5_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>10</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="adept::PackageInfo" row="1" column="1"> + <property name="name"> + <cstring>m_packageInfo</cstring> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>80</height> + </size> + </property> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer13</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>4</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> +</widget> +<customwidgets> + <customwidget> + <class>adept::PackageInfo</class> + <header location="global">adept/packageinfo.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</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="PNG" length="1003">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082</data> + </image> +</images> +<includes> + <include location="global" impldecl="in declaration">adept/extendablelist.h</include> +</includes> +<layoutdefaults spacing="0" margin="4"/> +<includehints> + <includehint>adept/packageinfo.h</includehint> +</includehints> +</UI> diff --git a/adept/libadept/listerpredicate.h b/adept/libadept/listerpredicate.h new file mode 100644 index 0000000..98f1b41 --- /dev/null +++ b/adept/libadept/listerpredicate.h @@ -0,0 +1,14 @@ +// -*- C++ -*- +#include <apt-front/cache/entity/entity.h> +#include <apt-front/predicate/predicate.h> + +#ifndef EPT_LISTERPREDICATE_H +#define EPT_LISTERPREDICATE_H + +namespace adept { +using namespace aptFront; +using namespace cache; +typedef predicate::Predicate< entity::Entity > ListerPredicate; +} + +#endif diff --git a/adept/libadept/packagedetails.cpp b/adept/libadept/packagedetails.cpp new file mode 100644 index 0000000..4e97fd4 --- /dev/null +++ b/adept/libadept/packagedetails.cpp @@ -0,0 +1,253 @@ +#include <qtoolbutton.h> +#include <qtextbrowser.h> +#include <qlabel.h> +#include <klocale.h> +#include <kiconloader.h> +#include <qpushbutton.h> +#include <ktoolbar.h> +#include <ktoolbarbutton.h> + +#include <kfileitem.h> +#include <kfiledetailview.h> +#include <kapplication.h> + +#include <adept/lister.h> +#include <adept/tagchooser.h> +#include <adept/packageinfo.h> +#include <adept/packagedetails.h> +#include <adept/utils.h> + +#include <fstream> + +using namespace adept; + +PackageDetails::PackageDetails( QWidget *w, const char *n ) + : PackageDetailsUi( w, n ), + m_thread( 0 ), + m_qtMutex( true ), + m_logicalAct( 0 ), m_removeAct( 0 ), + m_fileListRunning( false ) +{ + m_toolbar->setIconSize( 22 ); + m_toolbar->setIconText( KToolBar::IconTextRight ); + + m_toolbar->insertButton( u8( "back" ), BBack, false, i18n( "Back" ) ); + m_toolbar->insertButton( u8( "forward" ), BForward, false, i18n( "Forward" ) ); + m_toolbar->insertLineSeparator(); + m_toolbar->insertButton( u8( "" ), BShow, true, i18n( "Show List" ) ); + + m_tags->setTitle( i18n( "Assigned Tags" ) ); + + m_lister->setRangeProvider( this ); // wee + // m_lister->setOpenToplevel( true ); + + m_description->setPaper( QBrush( colorGroup().background() ) ); + + connect( m_toolbar->getButton( BShow ), SIGNAL( clicked() ), + this, SIGNAL( showList() ) ); + connect( m_toolbar->getButton( BBack ), SIGNAL( clicked() ), + this, SIGNAL( back() ) ); + connect( m_toolbar->getButton( BForward ), SIGNAL( clicked() ), + this, SIGNAL( forward() ) ); + connect( m_lister, SIGNAL( detailsRequested( Lister::Entity ) ), + this, SIGNAL( detailsRequested( Lister::Entity ) ) ); + + observeComponent< component::State >(); + + adjustFontSize( m_name, 1 ); + + Cache &c = cache::Global::get( m_cache ); + component::Packages::iterator i = c.packages().packagesBegin(); + while ( !i->hasVersion() ) ++i; // ha hum... + setPackage( *i ); +} + +Lister::Range PackageDetails::listerRange() { + utils::Range< entity::Relation > r = m_package.depends(); + utils::VectorRange< entity::Entity > vr; + while ( r != r.end() ) { + if ( !r->targetPackages().empty() ) + std::cerr << r->targetPackages()->name() << std::endl; + vr.consume( *r ); + r = r.next(); + } + return vr.sorted(); +} + +void PackageDetails::loadFileListWorker() +{ + entity::Package p = m_package; + + std::string fl, flfile = "/var/lib/dpkg/info/" + p.name() + ".list"; + std::ifstream ifl( flfile.c_str() ); + + int i = 0; + kdDebug() << "PackageDetails::loadFileListWorker() entering loop" << endl; + + while ( ifl.is_open() && !ifl.eof() ) { + std::string line; + getline( ifl, line ); + if ( line == "/." || line == "" ) + continue; // nasty evil thing go away + m_qtMutex.lock(); + KURL url( "file:///" ); + url.addPath( u8( line ) ); + KFileItem *it = new KFileItem( url, u8( "" ), 0 ); + it->setName( u8( line ) ); + m_fileList->insertItem( it ); + ++i; + m_qtMutex.unlock(); + } + kdDebug() << "PackageDetails::loadFileListWorker() leaving loop" << endl; + ifl.close(); +} + +void PackageDetails::notifyPreRebuild( component::Base * ) { + kdDebug() << "PackageDetails::notifyPreRebuild()" << endl; + Threads::wait(); + m_logical->setEnabled( false ); + m_remove->setEnabled( false ); + m_logical->disconnect( SIGNAL( clicked() ) ); + m_remove->disconnect( SIGNAL( clicked() ) ); + delete m_logicalAct; + delete m_removeAct; + kdDebug() << "PackageDetails::notifyPreRebuild() done" << endl; +} + +void PackageDetails::loadFileList() { + Cache &c = cache::Global::get( m_cache ); + if ( m_fileListRunning || !c.isOpen() ) { + QTimer::singleShot( 100, this, SLOT( loadFileList() ) ); + return; + } + + kdDebug() << "PackageDetails::loadFileList()" << endl; + m_fileListRunning = true; + + // the following call is neccessary to invoke buildDefaultType of KMimeType + // the first time the method is called it will check for + // existence of application/octet-stream and *popup a dialog* if + // not found -- we don't want that to happen in a non-gui thread + KMimeType::defaultMimeTypePtr(); + m_thread = asyncCall( std::mem_fun( &PackageDetails::loadFileListWorker ), this ); + + m_qtMutex.lock(); + m_fileList->KFileView::clear(); + c.progress().OverallProgress( 0, 0, 0, i18n( "Loading filelist..." ) ); + + m_qtMutex.unlock(); + Threads::enqueue( m_thread, &m_qtMutex ); + Threads::wait(); + c.progress().Done(); + m_fileListRunning = false; + kdDebug() << "PackageDetails::loadFileList() finished" << endl; +} + +void PackageDetails::setPackage( cache::entity::Package p ) +{ + kdDebug() << "PackageDetails::setPackage()" << endl; + m_package = p.stable(); + m_name->setText( QString( "<b>" ) + + p.name( std::string( "No package" ) ) + "</b>" ); + m_info->setPackage( p ); + QString l = p.longDescription( + std::string( i18n( "No long description available" ).local8Bit() ) ); + m_description->setText( QString( "<qt>" ) + + formatLongDescription( l ) + "</qt>" ); + + std::string na = u8( i18n( "not available" ) ); + m_tags->setTags( p.tags( entity::Package::TagSet() ) ); + m_tags->openToplevel(); + m_architecture->setText( labelFormat( i18n( "Architecture: " ), + p.architecture( na ) ) ); + m_filename->setText( labelFormat( i18n( "Filename: " ), p.fileName( na ) ) ); + m_md5->setText( labelFormat( i18n( "MD5: " ), p.md5sum( na ) ) ); + m_source->setText( labelFormat( i18n( "Source Package: " ), p.source( na ) ) ); + + + notifyPostChange( 0 ); + m_lister->cleanRebuild(); + loadFileList(); +} + +void PackageDetails::notifyPostChange( cache::component::Base * ) +{ + kdDebug() << "PackageDetails::notifyPostChange()" << endl; + // without the timer to break it, there could be a loop where + // we connect the clicked() signal to a slot which would be + // invoked right away when we return -> evil + QTimer::singleShot( 0, this, SLOT( updateLogical() ) ); +} + +void PackageDetails::notifyPostRebuild( cache::component::Base *b ) +{ + kdDebug() << "PackageDetails::notifyPostRebuild( " << b << " )" << endl; + // can't call directly because stable entities are not guaranteed + // to be stabilised at this point yet + QTimer::singleShot( 0, this, SLOT( updateLogical() ) ); + QTimer::singleShot( 0, this, SLOT( loadFileList() ) ); + m_lister->cleanRebuild(); +} + +void PackageDetails::updateLogical() +{ + Cache &c = cache::Global::get( m_cache ); + if ( !c.isOpen() ) { + QTimer::singleShot( 100, this, SLOT( updateLogical() ) ); + return; + } + kdDebug() << "PackageDetails::updateLogical()" << endl; + entity::Package p = m_package; + kdDebug() << "PackageDetails::updateLogical: p = " << p.name() + << " p.component() = " << &p.component() << endl; + if ( !p.valid() ) return; // nothing to update + EntityActor *a = 0, *b = 0; + + if ( p.canUpgrade() ) { + a = new EntityActor( p.upgrade() ); + } else if ( p.canInstall() ) { + a = new EntityActor( p.install() ); + } else if ( p.canKeep() ) { + a = new EntityActor( p.keep() ); + } + + if ( p.canRemove() ) { + b = new EntityActor( p.remove() ); + } + + if ( a ) { + m_logical->setEnabled( true ); + m_logical->setText( u8( a->actor().prettyName() ) ); + connect( m_logical, SIGNAL( clicked() ), + a, SLOT( destructiveAct() ) ); + } else { + m_logical->setText( i18n( "Install" ) ); + m_logical->setEnabled( false ); + } + + if ( b ) { + m_remove->setEnabled( true ); + m_remove->setText( u8( b->actor().prettyName() ) ); + connect( m_remove, SIGNAL( clicked() ), + b, SLOT( destructiveAct() ) ); + } else { + m_remove->setText( i18n( "Remove" ) ); + m_remove->setEnabled( false ); + } + + m_logicalAct = a; + m_removeAct = b; + // std::copy( r, r.last(), vr ); + + // r.consume( utils::upcastRange< entity::Entity >( p.depends() ) ); +} + +void PackageDetails::setHasForward( bool e ) { + m_toolbar->setItemEnabled( BForward, e ); + // m_forward->setEnabled( e ); +} + +void PackageDetails::setHasBack( bool e ) { + m_toolbar->setItemEnabled( BBack, e ); + // m_back->setEnabled( e ); +} diff --git a/adept/libadept/packagedetails.h b/adept/libadept/packagedetails.h new file mode 100644 index 0000000..655e226 --- /dev/null +++ b/adept/libadept/packagedetails.h @@ -0,0 +1,55 @@ +/* -*- C++ -*- adept/packagedetails.h + written by Peter Rockai <me@mornfall.net> */ + +#include <apt-front/cache/entity/package.h> +#include <adept/packagedetailsui.h> +#include <adept/lister.h> + +#include <qmutex.h> +#include <qguardedptr.h> + +#ifndef EPT_PACKGEDETAILS_H +#define EPT_PACKGEDETAILS_H + +class KToolBarButton; +class QThread; + +namespace adept { + +using namespace aptFront; + +class PackageDetails : public PackageDetailsUi, public Lister::RangeProvider, + public cache::Observer +{ + Q_OBJECT +public: + enum ButtonID { BForward, BBack, BShow }; + PackageDetails( QWidget *p = 0, const char *n = 0 ); + void setPackage( cache::entity::Package ); + void setHasForward( bool ); + void setHasBack( bool ); + virtual Lister::Range listerRange(); + void notifyPostChange( cache::component::Base * ); + void notifyPreRebuild( cache::component::Base * ); + void notifyPostRebuild( cache::component::Base * ); +signals: + void showList(); + void back(); + void forward(); + void detailsRequested( Lister::Entity ); +protected slots: + void loadFileList(); + void updateLogical(); +protected: + void loadFileListWorker(); + cache::entity::StablePackage m_package; + QMutex m_qtMutex; + QThread *m_thread; + QGuardedPtr< EntityActor > m_logicalAct, m_removeAct; + int m_fileListRunning; + +}; + +} + +#endif diff --git a/adept/libadept/packagedetailsui.ui b/adept/libadept/packagedetailsui.ui new file mode 100644 index 0000000..dacf7be --- /dev/null +++ b/adept/libadept/packagedetailsui.ui @@ -0,0 +1,464 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>PackageDetailsUi</class> +<widget class="QWidget"> + <property name="name"> + <cstring>PackageDetailsUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>705</width> + <height>529</height> + </rect> + </property> + <property name="caption"> + <string>Form1</string> + </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="KToolBar"> + <property name="name"> + <cstring>m_toolbar</cstring> + </property> + </widget> + <widget class="QFrame"> + <property name="name"> + <cstring>frame3</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>8</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="spacing"> + <number>2</number> + </property> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>m_name</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>(title)</string> + </property> + </widget> + <widget class="adept::PackageInfo" row="1" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>m_info</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>8</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>75</height> + </size> + </property> + </widget> + <spacer row="2" column="1"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="3" column="2"> + <property name="name"> + <cstring>m_remove</cstring> + </property> + <property name="text"> + <string>(remove)</string> + </property> + </widget> + <spacer row="3" column="0"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="3" column="1"> + <property name="name"> + <cstring>m_logical</cstring> + </property> + <property name="text"> + <string>(logical)</string> + </property> + </widget> + <spacer row="3" column="3"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QTextBrowser" row="0" column="4" rowspan="4" colspan="1"> + <property name="name"> + <cstring>m_description</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>28</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>NoFocus</enum> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="resizePolicy"> + <enum>AutoOneFit</enum> + </property> + <property name="vScrollBarMode"> + <enum>Auto</enum> + </property> + <property name="hScrollBarMode"> + <enum>AlwaysOff</enum> + </property> + <property name="text"> + <string>description...</string> + </property> + </widget> + </grid> + </widget> + <widget class="QTabWidget"> + <property name="name"> + <cstring>tabWidget2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>16</verstretch> + </sizepolicy> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Package Relationships</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="adept::Lister" row="0" column="0"> + <property name="name"> + <cstring>m_lister</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>120</height> + </size> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Installed Files</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KFileDetailView" row="0" column="0"> + <property name="name"> + <cstring>m_fileList</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage</cstring> + </property> + <attribute name="title"> + <string>Additional Information</string> + </attribute> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="adept::TagChooser"> + <property name="name"> + <cstring>m_tags</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>200</width> + <height>0</height> + </size> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_source</cstring> + </property> + <property name="text"> + <string>source</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_architecture</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>architecture</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_filename</cstring> + </property> + <property name="text"> + <string>file</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_md5</cstring> + </property> + <property name="text"> + <string>md5</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>61</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </hbox> + </widget> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>adept::TagChooser</class> + <header location="global">adept/tagchooser.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> + <customwidget> + <class>adept::PackageInfo</class> + <header location="global">adept/packageinfo.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> + <customwidget> + <class>adept::Lister</class> + <header location="global">adept/lister.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> + <customwidget> + <class>KToolBar</class> + <header location="global">ktoolbar.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> + <customwidget> + <class>KFileDetailView</class> + <header location="global">kfiledetailview.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</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="PNG" length="1003">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082</data> + </image> +</images> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>ktoolbar.h</includehint> + <includehint>adept/packageinfo.h</includehint> + <includehint>adept/lister.h</includehint> + <includehint>kfiledetailview.h</includehint> + <includehint>adept/tagchooser.h</includehint> +</includehints> +</UI> diff --git a/adept/libadept/packageinfo.cpp b/adept/libadept/packageinfo.cpp new file mode 100644 index 0000000..dac788b --- /dev/null +++ b/adept/libadept/packageinfo.cpp @@ -0,0 +1,181 @@ +/** -*- C++ -*- + @file adept/packageinfo.cpp + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qcolor.h> +#include <qlabel.h> +#include <qregexp.h> +#include <kdebug.h> +#include <klocale.h> + +#include <adept/packageinfo.h> +#include <adept/utils.h> + +using namespace adept; +using namespace cache; + +PackageInfo::PackageInfo( QWidget *p, const char *n ) + : PackageInfoUi( p, n ), m_specificVersion( false ) +{ + observeComponent< component::State >(); +} + +void PackageInfo::adjustFontSize( int s ) { + adept::adjustFontSize( m_status, s ); + adept::adjustFontSize( m_change, s ); + adept::adjustFontSize( m_section, s ); + adept::adjustFontSize( m_installedSize, s ); + adept::adjustFontSize( m_maintainer, s ); + adept::adjustFontSize( m_candidateVer, s ); + adept::adjustFontSize( m_installedVer, s ); +} + +void PackageInfo::hideStatus() { + m_status->hide(); + m_change->hide(); +} + +namespace adept { + +QColor statusColor( entity::Package p ) +{ + if ( !p.valid() ) + return Qt::black; + + QColor c = Qt::blue; + if (p.isInstalled()) + c = Qt::darkGreen; + if (p.isUpgradable()) + c = Qt::darkYellow; + if (p.isBroken()) + c = Qt::red; + return c; +} + +QColor actionColor( entity::Package p ) +{ + if ( !p.valid() ) + return Qt::black; + + QColor c = Qt::blue; + if (p.markedNewInstall()) + c = Qt::darkGreen; + if (p.markedUpgrade()) + c = Qt::darkYellow; + if (p.markedReInstall()) + c = Qt::darkYellow; + if (p.markedRemove()) + c = Qt::darkRed; + if (p.markedPurge()) + c = Qt::red; + if (p.willBreak()) + c = Qt::red; + return c; +} + +/* QString hexColor( QColor c ) +{ + QString r( "#%1%2%3" ); + return r.arg( c.red(), -2, 16 ).arg( c.green(), -2, 16 ).arg( c.blue(), -2, 16 ); + } */ + +QString colorify( QColor c, QString s ) +{ + return QString( "<font color=\"" ) + c.name() + + "\">" + s + "</font>"; +} + +QString formatLongDescription( QString l ) +{ + QRegExp rx( u8( "^(.*)\n" ) ); + rx.setMinimal( true ); + l.replace( rx, u8( "\\1</p><p>" ) ); + rx = QRegExp( u8( "\\n[ ]*\\.\\n" ) ); + l.replace( rx, u8( "</p><p>" ) ); + rx = QRegExp( u8( "\n " ) ); + l.replace( rx, u8( " " ) ); + rx = QRegExp( u8( "\n - (.*)(\n|$)" ) ); + rx.setMinimal( true ); + l.replace( rx, u8( "\n<li>\\1</li>\n" ) ); + l.replace( rx, u8( "\n<li>\\1</li>\n" ) ); + return QString( "<p>" ) + l + u8( "</p>" ); +} + +void PackageInfo::setPackage( entity::Package p ) +{ + kdDebug() << "PackageInfo::setPackage()" << endl; + // ho hum, probably XXX fix libapt-front? + setVersion( p.valid() ? p.anyVersion() : entity::Version(), false ); +} + +void PackageInfo::setVersion( entity::Version v, bool specific ) +{ + m_specificVersion = specific; + m_version = v.stable(); + if ( !m_version.valid() ) return; + kdDebug() << "PackageInfo::setVersion() (valid)" << endl; + m_section->setText( + labelFormat( i18n( "Section:" ), u8( v.section( u8( i18n( "Unknown" ) ) ) ) ) ); + m_maintainer->setText( + labelFormat( i18n( "Maintainer:" ), u8( v.maintainer( u8( i18n( "Unknown" ) ) ) ), + false ) ); + + notifyPostChange( 0 ); +} + +void PackageInfo::notifyPostRebuild( component::Base *b ) { + return notifyPostChange( b ); +} + +void PackageInfo::notifyPostChange( component::Base * ) +{ + if ( !m_version.valid() ) return; + entity::Version v = m_version; + entity::Package p = v.package(); + QString cv = i18n( "n/a" ), iv = i18n( "n/a" ), is = i18n( "n/a" ), status, action; + + if (p.valid()) { + entity::Version _cv = p.candidateVersion(); + entity::Version _iv = p.installedVersion(); + + if (_cv.valid()) { + cv = u8( _cv.versionString() ); + is = u8( _cv.installedSizeString() ); + } + + if (_iv.valid()) { + iv = _iv.versionString(); + } + } + + std::string unk = u8( i18n( "unknown" ) ); + /* m_status->setText( i18n( "<nobr>Currently " ) + colorify( + statusColor( p ), + u8( p.statusString( unk ) ) ) + + i18n( ", " ) + colorify( + actionColor( p ), + u8( p.actionString( unk ) ) ) + i18n( " + requested</nobr>" ) ); */ + m_status->setText( + labelFormat( i18n( "Status:" ), colorify( + statusColor( p ), + u8( p.statusString( u8( i18n( "Unknown" ) ) ) ) ) ) ); + m_change->setText( + labelFormat( i18n( "Requested change:" ), colorify( + actionColor( p ), + u8( p.actionString( u8( i18n( "Unknown" ) ) ) + ) ) ) ); + + m_candidateVer->setText( + m_specificVersion ? + labelFormat( i18n( "Version:" ), + v.versionString() + "(" + i18n( "candidate" ) + " " + cv + ")" ) + : labelFormat( i18n( "Candidate Version:" ), cv ) ); + m_installedVer->setText( + labelFormat( i18n( "Installed Version:" ), iv ) ); + m_installedSize->setText( + labelFormat( i18n( "Installed Size:" ), is ) ); +} + +} diff --git a/adept/libadept/packageinfo.h b/adept/libadept/packageinfo.h new file mode 100644 index 0000000..1a83c0d --- /dev/null +++ b/adept/libadept/packageinfo.h @@ -0,0 +1,49 @@ +/* -*- C++ -*- adept/packageinfo.h + written by Peter Rockai <me@mornfall.net> */ + +#include <apt-front/cache/entity/package.h> +#include <apt-front/cache/cache.h> +#include <adept/packageinfoui.h> + +#ifndef EPT_PACKAGEINFO_H +#define EPT_PACKAGEINFO_H + +namespace adept { + +using namespace aptFront; + +class PackageInfo : public PackageInfoUi, public cache::Observer +{ + Q_OBJECT +public: + PackageInfo( QWidget *p, const char *n = 0 ); +public slots: + void setVersion( cache::entity::Version v, bool = true ); + void setPackage( cache::entity::Package v ); + void adjustFontSize( int ); +public: + void notifyPostChange( cache::component::Base * ); + void notifyPostRebuild( cache::component::Base * ); + void hideStatus(); +protected: + cache::entity::StableVersion m_version; + bool m_specificVersion; +}; + +inline QString labelFormat( const QString &what, + const QString &txt, bool nobr = true ) +{ + QString ret = "<b><nobr>" + what + "</nobr></b> " + (nobr ? "<nobr>" : "") + + txt + (nobr ? "</nobr>" : ""); + return ret; +} + +QColor actionColor( cache::entity::Package p ); +QColor statusColor( cache::entity::Package p ); + +QString formatLongDescription( QString in ); +QString colorify( QColor c, QString s ); + +} + +#endif diff --git a/adept/libadept/packageinfoui.ui b/adept/libadept/packageinfoui.ui new file mode 100644 index 0000000..d7d5dc5 --- /dev/null +++ b/adept/libadept/packageinfoui.ui @@ -0,0 +1,180 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>PackageInfoUi</class> +<widget class="QWidget"> + <property name="name"> + <cstring>details</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>253</width> + <height>128</height> + </rect> + </property> + <property name="caption"> + <string>Form2</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>1</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>m_indent</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>16</width> + <height>5</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16</width> + <height>5</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="4" column="1"> + <property name="name"> + <cstring>m_maintainer</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>maintainer</string> + </property> + <property name="alignment"> + <set>AlignBottom</set> + </property> + </widget> + <widget class="QLabel" row="5" column="1"> + <property name="name"> + <cstring>m_candidateVer</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>candidate version</string> + </property> + </widget> + <widget class="QLabel" row="6" column="1"> + <property name="name"> + <cstring>m_installedVer</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>installed version</string> + </property> + </widget> + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>m_section</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>section</string> + </property> + </widget> + <widget class="QLabel" row="3" column="1"> + <property name="name"> + <cstring>m_installedSize</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>installed size</string> + </property> + </widget> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>m_status</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>status</string> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>m_change</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>change</string> + </property> + </widget> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/adept/libadept/progress.cpp b/adept/libadept/progress.cpp new file mode 100644 index 0000000..60a3bd3 --- /dev/null +++ b/adept/libadept/progress.cpp @@ -0,0 +1,58 @@ +#include <kapplication.h> +#include <qcursor.h> +#include <kdebug.h> +#include <adept/progress.h> +#include <adept/utils.h> + +using namespace adept; + +Progress::Progress() + : m_pbar( 0 ), m_sbar( 0 ), m_busy( false ) +{ +} + +void Progress::Update () +{ + if (!m_sbar) + return; + if (!m_pbar) { + if (Percent) { + m_pbar = new KProgress( m_sbar ); + m_pbar->setMinimumWidth( 80 ); + m_pbar->setMaximumWidth( 120 ); + m_pbar->setTextEnabled( false ); + m_pbar->show(); + m_sbar->addWidget( m_pbar, 0, true ); + m_pbar->setTotalSteps( 100 ); + } + MajorChange = true; + } + if (MajorChange) { + if ( !m_busy ) { + QApplication::setOverrideCursor( QCursor( Qt::BusyCursor ) ); + m_busy = true; + } + m_sbar->message( u8( Op + "..." ) ); + } + if (CheckChange (0.05) == false) + return; + // kdDebug() << "Progress::Update()" << endl; + if (m_pbar) + m_pbar->setProgress( Percent ); + kapp->processEvents(); +} + +void Progress::Done () +{ + kdDebug() << "Progress::Done()" << endl; + + QApplication::restoreOverrideCursor(); + m_busy = false; + + if (m_sbar) + m_sbar->clear(); + delete m_pbar; + m_pbar = 0; +} + +Progress::~Progress() {} diff --git a/adept/libadept/progress.h b/adept/libadept/progress.h new file mode 100644 index 0000000..aef3d92 --- /dev/null +++ b/adept/libadept/progress.h @@ -0,0 +1,30 @@ +/** -*- C++ -*- + @file adept/progress.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <kprogress.h> +#include <kstatusbar.h> +#include <apt-pkg/progress.h> + +#ifndef EPT_PROGRESS_H +#define EPT_PROGRESS_H + +namespace adept { + +class Progress : public OpProgress { +public: + Progress(); + virtual ~Progress(); + virtual void Update(); + virtual void Done(); + void setStatusBar( KStatusBar *b ) { m_sbar = b; } +protected: + KProgress *m_pbar; + KStatusBar *m_sbar; + bool m_busy; +}; + +} + +#endif diff --git a/adept/libadept/quickfilter.cpp b/adept/libadept/quickfilter.cpp new file mode 100644 index 0000000..2cb0577 --- /dev/null +++ b/adept/libadept/quickfilter.cpp @@ -0,0 +1,79 @@ +#include <apt-front/predicate/combinators.h> +#include <apt-front/predicate/factory.h> +#include <qobjectlist.h> +#include <klocale.h> +#include <kdebug.h> +#include <klineedit.h> +#include <qcheckbox.h> + +#include "quickfilter.h" + +using namespace aptFront; +using namespace adept; + +QuickFilterWidget::QuickFilterWidget( QWidget *parent, const char *name ) + : QuickFilterUi( parent, name ) +{ + setFocusProxy( m_match ); + connect( m_match, SIGNAL( textChanged( const QString & ) ), + this, SLOT( textChanged( const QString & ) ) ); + /* connect( m_reset, SIGNAL( clicked() ), + this, SLOT( reset() ) ); */ + connect( m_match, SIGNAL( returnPressed() ), + this, SLOT( widgetsChanged() ) ); + connect( &timer, SIGNAL( timeout() ), + this, SLOT( widgetsChanged() ) ); + + QObjectList *chld = queryList( "QCheckBox" ); + QObjectListIt it( *chld ); + while( it.current() != 0 ) { + connect( it.current(), SIGNAL( toggled( bool ) ), + this, SLOT( widgetsChanged() ) ); + ++it; + } +} + +void QuickFilterWidget::mouseReleaseEvent( QMouseEvent *e ) { + m_match->setFocus(); + QuickFilterUi::mouseReleaseEvent( e ); +} + +void QuickFilterWidget::textChanged( const QString & ) +{ + kdDebug() << "QuickFilterWidget::textChanged" << endl; + timer.start( 1000, true ); +} + +QuickFilterWidget::Predicate QuickFilterWidget::predicate() +{ + typedef QuickFilter< entity::Package > F; + F f; int w = 0; + if ( m_name->isChecked() ) w |= F::Name; + if ( m_description->isChecked() ) w |= F::Description; + if ( m_maintainer->isChecked() ) w |= F::Maintainer; + + f.setMatch( u8( m_match->text() ) ); + f.setWhat( w ); + + return predicate::adapt< entity::Entity >( f ); +} + +static void blockedSet( QCheckBox *b, bool v ) { + b->blockSignals( true ); + b->setChecked( v ); + b->blockSignals( false ); +} + +void QuickFilterWidget::predicateChanged() { + typedef QuickFilter< entity::Package > F; + F f = downcast< F >( m_pred ); + m_match->blockSignals( true ); + m_match->setText( f.match() ); + m_match->blockSignals( false ); + int w = f.what(); + + blockedSet( m_name, w & F::Name ); + blockedSet( m_description, w & F::Description ); + blockedSet( m_maintainer, w & F::Maintainer ); +} + diff --git a/adept/libadept/quickfilter.h b/adept/libadept/quickfilter.h new file mode 100644 index 0000000..788c9da --- /dev/null +++ b/adept/libadept/quickfilter.h @@ -0,0 +1,119 @@ +/** -*- C++ -*- + @file adept/quickfilter.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <klocale.h> +#include <qlayout.h> +#include <qtimer.h> + +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/entity/package.h> +#include <apt-front/predicate/factory.h> +#include <adept/quickfilterui.h> +#include <adept/filterlist.h> +#include <adept/lister.h> +#include <adept/utils.h> + +#ifndef EPT_QUICKFILTER_H +#define EPT_QUICKFILTER_H + +class KLineEdit; + +namespace adept { + +template< typename T > +struct QuickFilter : predicate::Implementation< T, QuickFilter< T > >, + InterfacingPredicate +{ + enum Type { Regex, Substring, Exact }; + enum What { Name = 0x1, Description = 0x2, Maintainer = 0x4 }; + + QuickFilter() + : m_type( Substring ), m_match( "" ), m_what( Name | Description ) { + setupPredicate(); + } + + void setupPredicate() { + predicate::ArgumentList l; + l.push_back( m_match ); + predicate::Predicate< T > a = not predicate::True< T >(); + if ( m_what & Name ) a = a or predicate::Factory< T >::name( m_match ); + if ( m_what & Description ) + a = a or predicate::Factory< T >::description( m_match ); + if ( m_what & Maintainer ) + a = a or predicate::Factory< T >::maintainer( m_match ); + m_op = a; + /* m_op = predicate::map( + predicate::predicate( predicate::Factory< T >::description( "" ) + or predicate::Factory< T >::name( "" ) + or predicate::Factory< T + >::maintainer( "" ) ), l ); */ + } + + std::string summary() const { + return u8( i18n( "Search: " ) ) + "\"" + m_match + "\""; + } + + void parseArguments( const predicate::ArgumentList & ) {} + + bool operator==( const QuickFilter &o ) const { + return o.m_type == m_type && o.m_match == m_match; + } + + std::string typeString() const { + if (m_type == Regex) return "Regular Expression"; + if (m_type == Substring) return "Substring"; + if (m_type == Exact) return "Exact Match"; + } + + bool operator()( const T &p ) { + return m_op( p ); + } + + std::string match() const { + return m_match; + } + + void setMatch( const std::string &s ) { + m_match = s; + setupPredicate(); + } + + void setWhat( int w ) { + m_what = w; + setupPredicate(); + } + + int what() { return m_what; } + + virtual void reset() { + m_match = ""; + setupPredicate(); + } + +protected: + Type m_type; + std::string m_match; + int m_what; + predicate::Predicate< T > m_op; +}; + +class QuickFilterWidget : public QuickFilterUi +{ + Q_OBJECT +public: + QuickFilterWidget( QWidget *parent, const char *name = 0 ); + virtual Predicate predicate(); +public slots: + void predicateChanged(); +protected slots: + void textChanged( const QString & ); +protected: + void mouseReleaseEvent( QMouseEvent *e ); + QTimer timer; +}; + +} + +#endif diff --git a/adept/libadept/quickfilterui.ui b/adept/libadept/quickfilterui.ui new file mode 100644 index 0000000..d45c154 --- /dev/null +++ b/adept/libadept/quickfilterui.ui @@ -0,0 +1,130 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::QuickFilterUi</class> +<widget class="adept::PredicateInterface"> + <property name="name"> + <cstring>QuickFilterUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>805</width> + <height>31</height> + </rect> + </property> + <property name="caption"> + <string>QuickFilterUi</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>2</number> + </property> + <property name="spacing"> + <number>1</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_title</cstring> + </property> + <property name="text"> + <string><b>Search:&nbsp;</b></string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_match</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>200</width> + <height>0</height> + </size> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Match: </string> + </property> + <property name="textFormat"> + <enum>AutoText</enum> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_name</cstring> + </property> + <property name="text"> + <string>package name,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_description</cstring> + </property> + <property name="text"> + <string>description,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_maintainer</cstring> + </property> + <property name="text"> + <string>maintainer.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>41</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> +</widget> +<includes> + <include location="global" impldecl="in declaration">adept/filterlist.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/adept/libadept/sourceseditor.cpp b/adept/libadept/sourceseditor.cpp new file mode 100644 index 0000000..3b04cf6 --- /dev/null +++ b/adept/libadept/sourceseditor.cpp @@ -0,0 +1,165 @@ +#include <fstream> +#include <iostream> + +#include <qpushbutton.h> +#include <qlineedit.h> +#include <qpainter.h> + +#include <kdebug.h> +#include <kpopupmenu.h> +#include <klocale.h> + +#include "sourceseditor.h" +#include <adept/utils.h> + +using namespace aptFront; +using namespace adept; + +SourcesEditor::SourcesEditor( std::string f, QWidget *p, const char *n ) + : SourcesEditorUi( p, n ), m_filename( f ) +{ + m_list->setSorting( -1 ); + m_list->setAcceptDrops( true ); + connect( m_close, SIGNAL( clicked() ), + this, SIGNAL( close() ) ); + connect( m_apply, SIGNAL( clicked() ), + this, SLOT( save() ) ); + connect( m_reset, SIGNAL( clicked() ), + this, SLOT( reset() ) ); + + connect( m_list, SIGNAL( contextMenuRequested( + QListViewItem *, const QPoint &, int) ), + this, SLOT( contextMenu( QListViewItem *, const QPoint & ) ) ); + + connect( m_newAdd, SIGNAL( clicked() ), + this, SLOT( newAdd() ) ); + + reset(); +} + +void SourcesEditor::newAdd() +{ + Sources::Entry e( true, Sources::Entry::Binary ); + std::string s = m_newLine->text(); + std::istringstream i( s ); + i >> e; + new EntryItem( e, m_list ); + m_newLine->setText( u8( "" ) ); +} + +void SourcesEditor::contextMenu( QListViewItem *, const QPoint &pt ) { + EntryItem *s = dynamic_cast< EntryItem * >( m_list->selectedItem() ); + if (!s) return; + KPopupMenu *m = new KPopupMenu (this); + m->insertItem( s->entry().enabled() ? i18n( "Disable" ) : i18n( "Enable" ), 0 ); + m->insertItem( i18n( "Clone" ), 1 ); + m->insertItem( i18n( "Remove" ), 2 ); + connect( m, SIGNAL( activated( int ) ), + this, SLOT( contextMenuActivated( int ) ) ); + m->exec( pt ); + delete m; +} + +void SourcesEditor::contextMenuActivated( int i ) { + EntryItem *s = dynamic_cast< EntryItem * >( m_list->selectedItem() ); + Sources::Entry e = s->entry(); + if (i == 0) { + e.setEnabled( !e.enabled() ); + s->setEntry( e ); + } + if (i == 2) + delete s; + if (i == 1) + new EntryItem( e, m_list, s ); +} + +void SourcesEditor::reset() { + std::ifstream in( m_filename.c_str() ); + m_sources.clear(); + in >> m_sources; + utils::Range< Sources::Entry > r = m_sources.entries(); + EntryItem *last = 0; + m_list->clear(); + while( r != r.end() ) { + last = last ? new EntryItem( *r, m_list, last ) : + new EntryItem( *r, m_list ); + ++ r; + } +} + +void SourcesEditor::save() { + m_sources.clear(); + EntryItem *i = dynamic_cast< EntryItem * >( m_list->firstChild() ); + while (i) { + m_sources.add( i->entry() ); + i = dynamic_cast< EntryItem * >( i->nextSibling() ); + } + std::ofstream out( m_filename.c_str() ); + out << m_sources; + std::cerr << "--" << m_sources << "--" << std::endl; + out.close(); + reset(); // re-parse +} + +/* void SourcesEditor::toggleSelectionEnabled() +{ + EntryItem *s = dynamic_cast< EntryItem * >( m_list->selectedItem() ); + if (s) { + Sources::Entry e = s->entry(); + e.setEnabled( !e.enabled() ); + s->setEntry( e ); + updateActions(); + } + } */ + +QString EntryItem::text( int c ) const { + if (entry().type() == Sources::Entry::Comment) { + if (c == 0) + if (entry().comment() == "") + return u8( "" ); + else + return entry().typeString(); + if (c == 1) + return entry().comment(); + return u8( "" ); + } + + if (c == 0) return entry().typeString(); + if (c == 1) return entry().url(); + if (c == 2) return entry().distribution(); + if (c == 3) return entry().components(); + return u8( "" ); +} + +void EntryItem::setText( int c, const QString &_s ) +{ + kdDebug() << "setText on column " << c << endl; + Sources::Entry e = entry(); + std::string s; + s = _s.local8Bit(); + if (c == 0) e.setTypeString( s ); + if (c == 1) + if (entry().type() == Sources::Entry::Comment) + e.setComment( s ); + else + e.setUrl( s ); + if (c == 2) e.setDistribution( s ); + if (c == 3) e.setComponents( s ); + setEntry( e ); + KListViewItem::setText( c, _s ); // stop qlistview from looping infinitely +} + +void EntryItem::paintCell (QPainter *p, const QColorGroup &cg, + int column, int width, int alignment ) +{ + QColorGroup _cg( cg ); + QColor c = _cg.text(); + QPixmap pm( width, height() ); + QPainter _p( &pm ); + if (!entry().enabled()) + c = Qt::gray; + _cg.setColor( QColorGroup::Text, c ); + KListViewItem::paintCell( &_p, _cg, column, width, AlignTop ); + p->drawPixmap( 0, 0, pm ); +} + diff --git a/adept/libadept/sourceseditor.h b/adept/libadept/sourceseditor.h new file mode 100644 index 0000000..32b474f --- /dev/null +++ b/adept/libadept/sourceseditor.h @@ -0,0 +1,63 @@ +/** -*- C++ -*- + @file adept/sourceseditor.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <apt-front/sources.h> +#include <adept/sourceseditorui.h> +#include <klistview.h> + +namespace adept { + +using namespace aptFront; + +class SourcesEditor : public SourcesEditorUi +{ + Q_OBJECT +public: + SourcesEditor( std::string f, QWidget *p = 0, const char *n = 0 ); +public slots: + void save(); + void reset(); +protected slots: + void contextMenu( QListViewItem *, const QPoint & ); + void contextMenuActivated( int ); + void newAdd(); +signals: + void close(); +protected: + aptFront::Sources m_sources; + std::string m_filename; +}; + +class EntryItem : public KListViewItem { +public: + Sources::Entry entry() const { + return m_entry; + } + void setEntry( const Sources::Entry &e ) { + m_entry = e; + } + EntryItem( Sources::Entry e, KListView *v, EntryItem *prev ) + : KListViewItem( v, prev ), m_entry( e ) { + init(); + } + EntryItem( Sources::Entry e, KListView *v ) + : KListViewItem( v ), m_entry( e ) { + init(); + } + void init() { + setRenameEnabled( 0, false ); + setRenameEnabled( 1, true ); + setRenameEnabled( 2, true ); + setRenameEnabled( 3, true ); + } + QString text( int c ) const; + void setText( int c, const QString &s ); + virtual void paintCell (QPainter *p, const QColorGroup &cg, + int column, int width, int alignment); +protected: + Sources::Entry m_entry; +}; + +} diff --git a/adept/libadept/sourceseditorui.ui b/adept/libadept/sourceseditorui.ui new file mode 100644 index 0000000..43397d3 --- /dev/null +++ b/adept/libadept/sourceseditorui.ui @@ -0,0 +1,173 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::SourcesEditorUi</class> +<widget class="QWidget"> + <property name="name"> + <cstring>adept::SourcesEditorUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>683</width> + <height>442</height> + </rect> + </property> + <property name="caption"> + <string>adept::SourcesEditorUi</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KListView"> + <column> + <property name="text"> + <string>Type</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>false</bool> + </property> + </column> + <column> + <property name="text"> + <string>URL</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Distribution</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Components</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>m_list</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="resizeMode"> + <enum>AllColumns</enum> + </property> + <property name="fullWidth"> + <bool>true</bool> + </property> + <property name="itemsMovable"> + <bool>true</bool> + </property> + <property name="itemsRenameable"> + <bool>true</bool> + </property> + <property name="dragEnabled"> + <bool>true</bool> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>New Repository:</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_newLine</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Write or paste a normal sources.list line here to add it to your sources</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_newAdd</cstring> + </property> + <property name="text"> + <string>Add</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout13</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_reset</cstring> + </property> + <property name="text"> + <string>Reset</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_apply</cstring> + </property> + <property name="text"> + <string>Apply</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_close</cstring> + </property> + <property name="text"> + <string>Close</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<tabstops> + <tabstop>m_newLine</tabstop> + <tabstop>m_newAdd</tabstop> + <tabstop>m_reset</tabstop> + <tabstop>m_apply</tabstop> + <tabstop>m_close</tabstop> + <tabstop>m_list</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klistview.h</includehint> +</includehints> +</UI> diff --git a/adept/libadept/statefilter.cpp b/adept/libadept/statefilter.cpp new file mode 100644 index 0000000..45ee470 --- /dev/null +++ b/adept/libadept/statefilter.cpp @@ -0,0 +1,60 @@ +#include <apt-front/predicate/combinators.h> +#include <apt-front/predicate/factory.h> +#include <klocale.h> +#include <kdebug.h> +#include <qcheckbox.h> +#include <qobjectlist.h> +#include "statefilter.h" + +using namespace aptFront; +using namespace adept; + +StateFilterWidget::StateFilterWidget( QWidget *parent, const char *name ) + : StateFilterUi( parent, name ) +{ + QObjectList *chld = queryList( "QCheckBox" ); + QObjectListIt it( *chld ); + while( it.current() != 0 ) { + connect( it.current(), SIGNAL( toggled( bool ) ), + this, SLOT( widgetsChanged() ) ); + ++it; + } +} + +StateFilterWidget::Predicate StateFilterWidget::predicate() +{ + typedef StateFilter< entity::Package > F; + unsigned mask = 0; + if (m_installed->isChecked()) mask |= F::Installed; + if (m_notInstalled->isChecked()) mask |= F::NotInstalled; + if (m_upgradable->isChecked()) mask |= F::Upgradable; + if (m_keep->isChecked()) mask |= F::Keep; + if (m_install->isChecked()) mask |= F::Install; + if (m_remove->isChecked()) mask |= F::Remove; + if (m_upgrade->isChecked()) mask |= F::Upgrade; + + StateFilter< entity::Package > f; + f.setMask( mask ); + return predicate::adapt< entity::Entity >( f ); +} + +static void blockedSet( QCheckBox *b, bool v ) { + b->blockSignals( true ); + b->setChecked( v ); + b->blockSignals( false ); +} + +void StateFilterWidget::predicateChanged() +{ + typedef StateFilter< entity::Package > F; + F f = downcast< F >( m_pred ); + unsigned mask = f.mask(); + blockedSet( m_installed, mask & F::Installed ); + blockedSet( m_notInstalled, mask & F::NotInstalled ); + blockedSet( m_upgradable, mask & F::Upgradable ); + blockedSet( m_keep, mask & F::Keep ); + blockedSet( m_install, mask & F::Install ); + blockedSet( m_upgrade, mask & F::Upgrade ); + blockedSet( m_remove, mask & F::Remove ); +} + diff --git a/adept/libadept/statefilter.h b/adept/libadept/statefilter.h new file mode 100644 index 0000000..570edb1 --- /dev/null +++ b/adept/libadept/statefilter.h @@ -0,0 +1,144 @@ +/** -*- C++ -*- + @file adept/filterwidgets.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/entity/package.h> +#include <apt-front/predicate/factory.h> + +#include <adept/statefilterui.h> +#include <adept/filterlist.h> +#include <adept/lister.h> + +#include <klocale.h> +#include <qlayout.h> +#include <iostream> +#include <sstream> + +#ifndef EPT_STATEFILTER_H +#define EPT_STATEFILTER_H + +class KLineEdit; + +namespace adept { + +template< typename T > +struct StateFilter : predicate::Implementation< T, StateFilter< T > >, + InterfacingPredicate +{ + enum Mask { Installed = 1 << 0, + NotInstalled = 1 << 1, + Upgradable = 1 << 2, + Install = 1 << 3, + Remove = 1 << 4, + Keep = 1 << 5, + Upgrade = 1 << 6 }; + + StateFilter() + : m_mask( 0xff ) { + setupPredicate(); + } + + void setupPredicate() { + predicate::Predicate< T > + p0 = not predicate::True< T >(), + p1 = not predicate::True< T >(); + if (m_mask & Installed) + p0 = p0 or (predicate::Factory< T >::member( &T::isInstalled ) + and not predicate::Factory< T >::member( &T::isUpgradable ) ); + if (m_mask & NotInstalled) + p0 = p0 or not predicate::Factory< T >::member( &T::isInstalled ); + if (m_mask & Upgradable) + p0 = p0 or predicate::Factory< T >::member( &T::isUpgradable ); + + if (m_mask & Install) + p1 = p1 or predicate::Factory< T >::member( &T::markedNewInstall ); + if (m_mask & Remove) + p1 = p1 or predicate::Factory< T >::member( &T::markedRemove ); + if (m_mask & Keep) + p1 = p1 or predicate::Factory< T >::member( &T::markedKeep ); + if (m_mask & Upgrade) + p1 = p1 or predicate::Factory< T >::member( &T::markedUpgrade ); + + m_op = p0 and p1; + } + + std::string summary() const { + std::ostringstream s; + std::vector< std::string > r; + s << "State filter: "; + if (m_mask & Installed && m_mask & NotInstalled && m_mask & Upgradable) + r.push_back( "Any State" ); + else { + if (m_mask & Installed) + r.push_back( i18n( "Installed" ) ); + if (m_mask & NotInstalled) + r.push_back( i18n( "Not Installed" ) ); + if (m_mask & Upgradable) + r.push_back( i18n( "Upgradable" ) ); + } + std::copy( r.begin(), r.end(), + std::ostream_iterator< std::string >( s, " " ) ); + s << "; "; + r.clear(); + if (m_mask & Install && m_mask & Remove + && m_mask & Keep && m_mask & Upgrade) + r.push_back( i18n( "Any Action" ) ); + else { + if (m_mask & Install) + r.push_back( i18n( "Install" ) ); + if (m_mask & Remove) + r.push_back( i18n( "Remove" ) ); + if (m_mask & Keep) + r.push_back( i18n( "Keep" ) ); + if (m_mask & Upgrade) + r.push_back( i18n( "Upgrade" ) ); + } + std::copy( r.begin(), r.end(), + std::ostream_iterator< std::string >( s, " " ) ); + return s.str(); + } + + unsigned mask() const { + return m_mask; + } + + void setMask( unsigned m ) { + m_mask = m; + setupPredicate(); + } + + void parseArguments( const predicate::ArgumentList & ) {} + + bool operator==( const StateFilter &o ) const { + return o.m_op == m_op; + } + + bool operator()( const T &p ) { + return m_op( p ); + } + + virtual void reset() { + m_mask = 0xff; + setupPredicate(); + } + +protected: + unsigned m_mask; + predicate::Predicate< T > m_op; +}; + +class StateFilterWidget : public StateFilterUi +{ + Q_OBJECT +public: + StateFilterWidget( QWidget *parent, const char *name = 0 ); + virtual Predicate predicate(); +public slots: + void predicateChanged(); +}; + +} + +#endif diff --git a/adept/libadept/statefilterui.ui b/adept/libadept/statefilterui.ui new file mode 100644 index 0000000..1ef19e0 --- /dev/null +++ b/adept/libadept/statefilterui.ui @@ -0,0 +1,166 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::StateFilterUi</class> +<widget class="adept::PredicateInterface"> + <property name="name"> + <cstring>StateFilterUi</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>574</width> + <height>55</height> + </rect> + </property> + <property name="caption"> + <string>StateFilterUi</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>2</number> + </property> + <property name="spacing"> + <number>1</number> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>m_title</cstring> + </property> + <property name="text"> + <string>Show: </string> + </property> + <property name="alignment"> + <set>AlignVCenter</set> + </property> + </widget> + <widget class="QLayoutWidget" row="0" column="1"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_notInstalled</cstring> + </property> + <property name="text"> + <string>not installed,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_installed</cstring> + </property> + <property name="text"> + <string>installed,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_upgradable</cstring> + </property> + <property name="text"> + <string>upgradable packages,</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>195</width> + <height>16</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QLayoutWidget" row="1" column="1"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_keep</cstring> + </property> + <property name="text"> + <string>no changes,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_install</cstring> + </property> + <property name="text"> + <string>install,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_remove</cstring> + </property> + <property name="text"> + <string>removal,</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_upgrade</cstring> + </property> + <property name="text"> + <string>upgrade requested.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>195</width> + <height>16</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>with: </string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + </grid> +</widget> +<includes> + <include location="global" impldecl="in declaration">adept/filterlist.h</include> +</includes> +<layoutdefaults spacing="3" margin="11"/> +</UI> diff --git a/adept/libadept/tagchooser.cpp b/adept/libadept/tagchooser.cpp new file mode 100644 index 0000000..6443663 --- /dev/null +++ b/adept/libadept/tagchooser.cpp @@ -0,0 +1,144 @@ +#include <klocale.h> +#include <qdragobject.h> + +#include <apt-front/cache/component/tags.h> +#include <apt-front/cache/component/packagetags.h> +#include <adept/tagchooser.h> +#include <adept/taglist.h> +#include <adept/utils.h> + +using namespace adept; + +FacetItem::FacetItem( TagChooser *t ) + : KListViewItem( t ) +{ +} + +void FacetItem::removeTag( TagItem::Tag t ) { + // kdDebug() << "removing tag " << t.fullname() << endl; + for ( QListViewItem *n, *i = firstChild(); i != 0; i = n ) { + n = i->nextSibling(); + if ( dynamic_cast< TagItem * >( i )->tag() == t ) + delete i; + } +} + +TagItem::TagItem( FacetItem *p ) + : KListViewItem( p ), m_toplevel( false ) +{ +} + +TagItem::TagItem( TagChooser *l ) + : KListViewItem( l ), m_toplevel( true ) +{ +} + +QString TagItem::text( int c ) const +{ + if (c != 0) return u8( "" ); + return QString( "[" ) + m_tag.name() + "] " + m_tag.shortDescription(""); +} + +TagChooser::TagChooser( QWidget *p, const char *n ) + : KListView( p, n ) +{ + observeComponent< cache::component::PackageTags >(); + // addColumn( " ", 20 ); + setRootIsDecorated( true ); + addColumn( i18n( "Available Tags" ) ); + setResizeMode( LastColumn ); + setDragEnabled( true ); + setAcceptDrops( true ); + viewport()->setAcceptDrops( false ); + // kdDebug() << "TagChooser: tags set" << endl; +} + +void TagChooser::openToplevel() { + QListViewItem *i; + for ( i = firstChild(); i != 0; i = i->nextSibling() ) { + i->setOpen( true ); + } +} + +QDragObject *TagChooser::dragObject() +{ + TagItem *sel = dynamic_cast< TagItem * >( selectedItem() ); + if (sel) + return new QTextDrag( sel->tag().fullname(), this ); + return 0; +} + +void TagChooser::dragEnterEvent( QDragEnterEvent *e ) +{ + // hmmmmm :-) + kdDebug() << "TagChooser::dragEnterEvent" << endl; + e->accept( dynamic_cast< TagList * >( e->source() ) + && QTextDrag::canDecode( e ) ); + kdDebug() << dynamic_cast< TagList * >( e->source() ) + << "; can decode " << QTextDrag::canDecode( e ) << endl; +} + +void TagChooser::dropEvent( QDropEvent* e ) +{ + TagList *tl = dynamic_cast< TagList * >( e->source() ); + QString tag; + QTextDrag::decode( e, tag ); + tl->setTags( tl->tags() - cache::Global::get().tags().tagByName( + static_cast< const char * >( tag.local8Bit() ) ) ); +} + +QString FacetItem::text( int column ) const +{ + if ( column == 0 ) + return QString( "[" ) + m_facet.name() + "] " + m_facet.shortDescription( "" ); + return u8( "" ); +} + +static bool drop( TagChooser::Tag t ) { + if ( t.facet().name() == "special" ) + return true; + if ( t.name() == "TODO" ) + return true; + return false; +} + +void TagChooser::setTags( Tag::Set s ) +{ + Tag::Set remove = m_tags - s; + Tag::Set add = s - m_tags; + m_tags = s; + Tag::Set::iterator i; + + for ( i = add.begin(); i != add.end(); ++i ) { + + if ( drop( *i ) ) + continue; + + FacetItem *fi = m_facets[ i->facet() ]; + if ( fi == 0 ) { + fi = m_facets[ i->facet() ] = new FacetItem( this ); + fi->setFacet( i->facet() ); + } + + TagItem *ti = new TagItem( fi ); + ti->setTag( *i ); + } + + for ( i = remove.begin(); i != remove.end(); ++i ) { + + if ( drop( *i ) ) + continue; + + FacetItem *fi = m_facets[ i->facet() ]; + fi->removeTag( *i ); + if ( fi->childCount() == 0 ) { + m_facets[ i->facet() ] = 0; + delete fi; + } + } + +} + +void TagChooser::notifyPreRebuild( cache::component::Base *b ) { + setTags( Tag::Set() ); +} diff --git a/adept/libadept/tagchooser.h b/adept/libadept/tagchooser.h new file mode 100644 index 0000000..082a60b --- /dev/null +++ b/adept/libadept/tagchooser.h @@ -0,0 +1,82 @@ +/* -*- C++ -*- file adept/tagchooser.h + written by Peter Rockai <me@mornfall.net> */ + +#include <kdebug.h> +#include <qlayout.h> + +#include <apt-front/utils/range.h> +#include <apt-front/cache/cache.h> +#include <apt-front/cache/entity/tag.h> + +#include <adept/extendablelist.h> + +#ifndef EPT_TAGCHOOSER_H +#define EPT_TAGCHOOSER_H + +namespace adept { + +using namespace aptFront; + +class FacetItem; +class FacetExtender; +class TagChooser; + +class TagItem : public KListViewItem { +public: + typedef cache::entity::Tag Tag; + virtual QString text( int ) const; + TagItem( TagChooser *t ); + TagItem( FacetItem *t ); + void setTag( Tag t ) { m_tag = t; } + Tag tag() { return m_tag; } +protected: + bool m_toplevel; + Tag m_tag; +}; + +class FacetItem : public KListViewItem +{ +public: + typedef cache::entity::Facet Facet; + virtual QString text( int ) const; + FacetItem( TagChooser *t ); + void setFacet( Facet f ) { m_facet = f; } + void removeTag( TagItem::Tag ); +protected: + Facet m_facet; +}; + +class TagChooser : public KListView, public cache::Observer // ExtendableList +{ + Q_OBJECT +public: + typedef cache::entity::Tag Tag; + typedef cache::entity::Facet Facet; + TagChooser( QWidget *p = 0, const char *n = 0 ); + virtual void notifyPreRebuild( cache::component::Base * ); +public slots: + virtual void setTags( TagChooser::Tag::Set ); + void setTitle( QString s ) { + setColumnText( 0, s ); + } + void openToplevel(); + +protected: + virtual void dragEnterEvent( QDragEnterEvent *e ); + virtual void dropEvent( QDropEvent* e ); + virtual void contentsDragEnterEvent( QDragEnterEvent *e ) { + kdDebug() << "TagChooser::contentsDragEnterEvent" << endl; + dragEnterEvent( e ); + } + virtual void contentsDropEvent( QDropEvent *e ) { + kdDebug() << "TagChooser::contentsDropEvent" << endl; + dropEvent( e ); + } + virtual QDragObject *dragObject(); + Tag::Set m_tags; + std::map< Facet, FacetItem * > m_facets; +}; + +} + +#endif diff --git a/adept/libadept/tagfilter.cpp b/adept/libadept/tagfilter.cpp new file mode 100644 index 0000000..4a08adc --- /dev/null +++ b/adept/libadept/tagfilter.cpp @@ -0,0 +1,67 @@ +/* -*- C++ -*- libapt/tagfilter.h + written by Peter Rockai <me@mornfall.net> */ + +#include <qpopupmenu.h> +#include <qpushbutton.h> +#include <qtoolbutton.h> + +#include <tagcoll/InputMerger.h> + +#include <adept/tagfilter.h> +#include <adept/taglist.h> + +using namespace adept; + +TagFilterWidget::TagFilterWidget( QWidget *w, const char *n ) + : TagFilterUi( w, n ) +{ + m_wanted->setName( i18n( "Tags I Want (drop tags here)" ) ); + m_unwanted->setName( i18n( "Tags I Do Not Want (drop tags here)" ) ); + + connect( m_wanted, SIGNAL( tagsChanged( TagList::Tag::Set ) ), + this, SLOT( wantedChanged() ) ); + connect( m_unwanted, SIGNAL( tagsChanged( TagList::Tag::Set ) ), + this, SLOT( unwantedChanged() ) ); +} + +TagFilterWidget::Predicate TagFilterWidget::predicate() +{ + TagFilter< entity::Package > f; + f.setWanted( m_wanted->tags() ); + f.setUnwanted( m_unwanted->tags() ); + return predicate::adapt< entity::Entity >( f ); +} + +static void setTagsBlocking( TagList *l, TagList::Tag::Set s ) { + l->blockSignals( true ); + l->setTags( s ); + l->blockSignals( false ); +} + +void TagFilterWidget::predicateChanged() +{ + typedef TagFilter< entity::Package > F; + F f = downcast< F >( m_pred ); + setTagsBlocking( m_wanted, f.wanted() ); + setTagsBlocking( m_unwanted, f.unwanted() ); + if ( item() && item()->list() ) { + setupColors(); + item()->list()->delayedUpdateExtenders(); + } +} + +void TagFilterWidget::wantedChanged() +{ + setTagsBlocking( m_unwanted, m_unwanted->tags() - m_wanted->tags() ); + setupColors(); + widgetsChanged(); + item()->list()->delayedUpdateExtenders(); +} + +void TagFilterWidget::unwantedChanged() +{ + setTagsBlocking( m_wanted, m_wanted->tags() - m_unwanted->tags() ); + setupColors(); + widgetsChanged(); + item()->list()->delayedUpdateExtenders(); +} diff --git a/adept/libadept/tagfilter.h b/adept/libadept/tagfilter.h new file mode 100644 index 0000000..1afa44a --- /dev/null +++ b/adept/libadept/tagfilter.h @@ -0,0 +1,113 @@ +/* -*- C++ -*- adept/tagfilter.h + written by Peter Rockai <me@mornfall.net> */ + +#include <klocale.h> +#include <qlayout.h> +#include <qtimer.h> +#include <qpoint.h> + +#include <apt-front/cache/entity/entity.h> +#include <apt-front/cache/entity/package.h> +#include <apt-front/cache/entity/tag.h> +#include <apt-front/predicate/factory.h> + +#include <adept/quickfilterui.h> +#include <adept/filterlist.h> +#include <adept/lister.h> +#include <adept/taglist.h> +#include <adept/tagfilterui.h> +#include <adept/utils.h> + +#ifndef EPT_TAGFILTER_H +#define EPT_TAGFILTER_H + +namespace adept { + +using namespace Tagcoll; + +template< typename T > +struct TagFilter : predicate::Implementation< T, TagFilter< T > >, + InterfacingPredicate, cache::Observer +{ + typedef cache::entity::Tag Tag; + + TagFilter() { + setupPredicate(); + observeComponent< cache::component::Tags >(); + } + + void setupPredicate() { + Cache &cache = cache::Global::get(); // FIXME? + m_op = predicate::Factory< T >::tagSet( m_wanted ); + for (Tag::Set::iterator i = m_unwanted.begin(); i != m_unwanted.end(); ++i ) { + m_op = m_op and not predicate::Factory< T >::tag( *i ); + } + } + + std::string summary() const { + return u8( i18n( "Tag Filter" ) ); + } + + void parseArguments( const predicate::ArgumentList & ) {} + + bool operator==( const TagFilter &o ) const { + return o.m_wanted == m_wanted && o.m_unwanted == m_unwanted; + } + + bool operator()( const T &p ) { + return m_op( p ); + } + + void setWanted( Tag::Set t ) { + m_wanted = t; + setupPredicate(); + } + + void setUnwanted( Tag::Set t ) { + m_unwanted = t; + setupPredicate(); + } + + Tag::Set wanted() const { return m_wanted; } + Tag::Set unwanted() const { return m_unwanted; } + + void notifyPreRebuild( cache::component::Base * ) { + kdDebug() << "TagFilter pre-rebuild" << endl; + m_unwanted.clear(); m_wanted.clear(); + } + + void notifyPostRebuild( cache::component::Base * ) { + Cache &c = cache::Global::get( m_cache ); + setupPredicate(); + } + + virtual void reset() { + m_wanted.clear(); + m_unwanted.clear(); + setupPredicate(); + } + +protected: + predicate::Predicate< T > m_op; + Tag::Set m_wanted; + Tag::Set m_unwanted; +}; + +class TagFilterWidget : public TagFilterUi +{ + Q_OBJECT +public: + TagFilterWidget( QWidget *p, const char *n ); + virtual Predicate predicate(); +public slots: + void predicateChanged(); + void wantedChanged(); + void unwantedChanged(); +protected: + TagList *m_addingTo; + std::vector< entity::Tag > m_tagMenuMap; +}; + +} + +#endif diff --git a/adept/libadept/tagfilterui.ui b/adept/libadept/tagfilterui.ui new file mode 100644 index 0000000..1f78b8a --- /dev/null +++ b/adept/libadept/tagfilterui.ui @@ -0,0 +1,95 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>adept::TagFilterUi</class> +<widget class="adept::PredicateInterface"> + <property name="name"> + <cstring>TagFilterUi</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>627</width> + <height>130</height> + </rect> + </property> + <property name="caption"> + <string>Form1</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>2</number> + </property> + <property name="spacing"> + <number>2</number> + </property> + <widget class="adept::TagList"> + <property name="name"> + <cstring>m_wanted</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>90</height> + </size> + </property> + </widget> + <widget class="adept::TagList"> + <property name="name"> + <cstring>m_unwanted</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </hbox> +</widget> +<customwidgets> + <customwidget> + <class>adept::TagList</class> + <header location="global">adept/taglist.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</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="PNG" length="1003">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082</data> + </image> +</images> +<includes> + <include location="global" impldecl="in declaration">adept/filterlist.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>adept/taglist.h</includehint> +</includehints> +</UI> diff --git a/adept/libadept/taglist.cpp b/adept/libadept/taglist.cpp new file mode 100644 index 0000000..22b3d58 --- /dev/null +++ b/adept/libadept/taglist.cpp @@ -0,0 +1,134 @@ +/* -*- C++ -*- adept/taglist.cpp + written by Peter Rockai <me@mornfall.net> */ + +#include <qlabel.h> +#include <qtimer.h> +#include <kdebug.h> +#include <qdragobject.h> +#include <qevent.h> +#include <klocale.h> + +#include <apt-front/cache/component/tags.h> +#include <adept/taglist.h> +#include <adept/utils.h> + +using namespace adept; + +TagLabel::TagLabel( Tag t, TagList *l, QWidget *p, const char *n ) + : QHBox( p, n ), m_tag( t ), m_list( l ) +{ + if ( t == Tag() ) { + m_description = new QLabel( QString( " " ) + i18n( "[none]" ), this ); + } else { + m_remove = new QLabel( this ); + m_remove->setPixmap( SmallIcon( u8( "cancel" ) ) ); + m_remove->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + m_description = new QLabel( QString( " [" ) + t.fullname( "n/a" ) + "] " + + t.shortDescription( "n/a" ), this ); + } +} + +void TagLabel::mouseReleaseEvent( QMouseEvent *e ) { + if ( e->button() == Qt::LeftButton && + dynamic_cast< QLabel * >( childAt( e->pos() ) ) == m_remove ) + m_list->setTags( m_list->tags() - m_tag ); +} + +TagList::TagList( QWidget *p, const char *n ) + : QVBox( p, n ) +{ + m_name = new QLabel( this ); + m_tagBox = new QVBox( this ); + m_tagBox->setFrameShape( QFrame::Panel ); + m_tagBox->setFrameShadow( QFrame::Sunken ); + m_updateScheduled = false; + setAcceptDrops( true ); + scheduleUpdateList(); + m_tagSpacer = new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding ); +} + +void TagList::setTags( Tag::Set t ) +{ + m_tags = t; + scheduleUpdateList(); + emit tagsChanged( m_tags ); +} + +void TagList::addTag( Tag t ) +{ + if ( t == Tag() ) + return; + m_tags += t; + scheduleUpdateList(); + emit tagsChanged( m_tags ); +} + +void TagList::setName( QString n ) +{ + m_name->setText( n ); +} + +void TagList::scheduleUpdateList() +{ + if (! m_updateScheduled) { + kdDebug() << "TagList: scheduling update" << endl; + QTimer::singleShot( 0, this, SLOT( updateList() ) ); + m_updateScheduled = true; + } +} + +void TagList::updateList() +{ + kdDebug() << "TagList (" + m_name->text() + "): updating list" << endl; + clearList(); + if ( m_tags.empty() ) { + appendLabel( new TagLabel( Tag(), this, m_tagBox ) ); + } else { + for ( Tag::Set::iterator i = m_tags.begin(); i != m_tags.end(); ++i ) { + appendLabel( new TagLabel( *i, this, m_tagBox ) ); + } + } + m_tagBox->layout()->addItem( m_tagSpacer ); + update(); + parentWidget()->adjustSize(); + m_updateScheduled = false; +} + +void TagList::appendLabel( TagLabel *l ) +{ + m_list.push_back( l ); + l->show(); +} + +void TagList::mouseMoveEvent( QMouseEvent *e ) { + TagLabel *child = dynamic_cast< TagLabel * >( childAt( e->pos() )->parentWidget() ); + if ( !child ) + return; + QDragObject *d = new QTextDrag( child->tag().fullname( "" ), this ); + d->dragCopy(); +} + +void TagList::dragEnterEvent( QDragEnterEvent *e ) { + kdDebug() << "TagList::dragEnterEvent" << endl; + e->accept( QTextDrag::canDecode( e ) ); +} + +void TagList::dropEvent( QDropEvent* e ) { + QString tag; + kdDebug() << "TagList: drop event" << endl; + QTextDrag::decode( e, tag ); + try { + addTag( cache::Global::get().tags().tagByName( + static_cast< const char * >( tag.local8Bit() ) ) ); + } catch (...) {} // not a tag, ignore + scheduleUpdateList(); +} + +void TagList::clearList() +{ + for (List::iterator i = m_list.begin(); i != m_list.end(); ++i ) { + delete *i; + } + m_list.clear(); + m_tagBox->layout()->removeItem( m_tagSpacer ); +} diff --git a/adept/libadept/taglist.h b/adept/libadept/taglist.h new file mode 100644 index 0000000..4cd55a3 --- /dev/null +++ b/adept/libadept/taglist.h @@ -0,0 +1,75 @@ +/** -*- C++ -*- + @file adept/taglist.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qvbox.h> +#include <qhbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <kiconloader.h> +#include <vector> + +#include <apt-front/cache/entity/tag.h> + +#ifndef EPT_TAGLIST_H +#define EPT_TAGLIST_H + +class QLabel; + +namespace adept { + +using namespace aptFront; + +class TagList; + +class TagLabel : public QHBox +{ + Q_OBJECT +public: + typedef cache::entity::Tag Tag; + TagLabel( Tag t, TagList *l, QWidget *p = 0, const char *n = 0 ); + Tag tag() { return m_tag; } +protected: + void mouseReleaseEvent( QMouseEvent *e ); + Tag m_tag; + QLabel *m_remove; + QLabel *m_description; + TagList *m_list; +}; + +class TagList : public QVBox +{ + Q_OBJECT +public: + typedef cache::entity::Tag Tag; + TagList( QWidget *p = 0, const char *n = 0 ); + void setTags( Tag::Set t ); + void addTag( Tag t ); + Tag::Set tags() { return m_tags; } + void setName( QString n ); +public slots: + void scheduleUpdateList(); + void updateList(); +signals: + void tagsChanged( TagList::Tag::Set ); +protected: + void mouseMoveEvent( QMouseEvent *e ); + void dropEvent( QDropEvent * ); + void dragEnterEvent( QDragEnterEvent * ); + void appendLabel( TagLabel * ); + void clearList(); + + bool m_updateScheduled; + Tag::Set m_tags; + QLabel *m_name; + QVBox *m_tagBox; + QSpacerItem *m_tagSpacer; + typedef std::vector< TagLabel * > List; + List m_list; +}; + +} + +#endif diff --git a/adept/libadept/threadutils.cpp b/adept/libadept/threadutils.cpp new file mode 100644 index 0000000..722f75d --- /dev/null +++ b/adept/libadept/threadutils.cpp @@ -0,0 +1,44 @@ +/** -*- C++ -*- + @file adept/utils.cpp + @author Peter Rockai <me@mornfall.net> +*/ + +#include <map> +#include <adept/utils.h> + +namespace adept { + +QMutex Threads::serialize; +Threads::Queue Threads::threads; + +void Threads::wait() { + static std::map< QMutex *, int > locked; + while ( !threads.empty() ) { + QThread *current = threads.front().first; + if ( current->finished() ) { + delete current; + threads.pop_front(); + continue; + } + for ( Queue::iterator thr = threads.begin(); thr != threads.end(); ++thr ) { + ++locked[ thr->second ]; + thr->second->lock(); + } + kapp->processEvents(); + for ( Queue::iterator thr = threads.begin(); thr != threads.end(); ++thr ) { + while ( locked[ thr->second ] > 0 ) { + thr->second->unlock(); + --locked[ thr->second ]; + } + } + usleep( 50000 ); + } +} + +void Threads::enqueue( QThread *t, QMutex *m ) +{ + threads.push_back( std::make_pair( t, m ) ); + t->start(); +} + +} diff --git a/adept/libadept/utils.h b/adept/libadept/utils.h new file mode 100644 index 0000000..6c3a3d3 --- /dev/null +++ b/adept/libadept/utils.h @@ -0,0 +1,71 @@ +/** -*- C++ -*- + @file adept/utils.h + @author Peter Rockai <me@mornfall.net> +*/ + +#include <qthread.h> +#include <qstring.h> +#include <kapplication.h> +#include <string> +#include <queue> +#include <kdebug.h> + +#ifndef EPT_UTILS_H +#define EPT_UTILS_H + +namespace adept { + +inline QString u8( std::string s ) { + return QString::fromUtf8( s.c_str() ); +} + +inline std::string u8( QString s ) { + return std::string( s.utf8() ); +} + +inline QString u8( const char *s ) { + return QString::fromUtf8( s ); +} + +struct Threads { + static QMutex serialize; + typedef std::deque< std::pair< QThread *, QMutex * > > Queue; + static Queue threads; + static void enqueue( QThread *t, QMutex *m ); + static void wait(); +}; + +template< typename F, typename P > +struct AsyncCall : public QThread +{ + AsyncCall( F f, P p ) : func( f ), param( p ) {} + virtual void run() + { + // kdDebug() << "Thread waiting for mutex..." << endl; + Threads::serialize.lock(); + // kdDebug() << "starting thread (mutex acquired)" << endl; + func( param ); + // kdDebug() << "finishing thread (releasing mutex)" << endl; + Threads::serialize.unlock(); + } + virtual ~AsyncCall() {} +protected: + F func; + P param; +}; + + +template< typename F, typename P > AsyncCall< F, P > *asyncCall( F f, P p ) { + return new AsyncCall< F, P >( f, p ); +} + +inline static void adjustFontSize( QWidget *w, int off ) { + QFont f = w->font(); + f.setPointSize( f.pointSize() + off ); // a bit smaller font... + w->setFont( f ); + w->updateGeometry(); +} + +} + +#endif diff --git a/adept/libadept/view.cpp b/adept/libadept/view.cpp new file mode 100644 index 0000000..207277c --- /dev/null +++ b/adept/libadept/view.cpp @@ -0,0 +1,153 @@ +#include <apt-front/predicate/combinators.h> +#include <apt-front/predicate/factory.h> + +#include <adept/quickfilter.h> +#include <adept/statefilter.h> +#include <adept/tagfilter.h> + +#include <adept/packagedetails.h> +#include <adept/view.h> +#include <adept/filtersidebar.h> + +using namespace adept; + +View::View( QWidget *p, const char *n ) + : QSplitter( p, n ) +{ + setOrientation( Qt::Vertical ); + m_flist = new FilterList( this ); + m_bottom = new QSplitter( this ); + m_bottom->setOrientation( Qt::Horizontal ); + m_lister = new Lister( m_bottom ); + m_flist->plugLister( m_lister ); + m_sidebar = new FilterSidebar( m_bottom ); + + connect( m_lister, SIGNAL( cardinalityChanged( const Lister::Cardinality & ) ), + m_sidebar, SLOT( setCardinality( const Lister::Cardinality & ) ) ); + + m_flist->setHiddenPredicate( + predicate::adapt< entity::Entity >( + predicate::Package::member( &entity::Package::hasVersion ) ) ); + m_flist->appendPredicate( + predicate::adapt< entity::Entity >( + StateFilter< entity::Package >() ) ); + m_flist->appendPredicate( + predicate::adapt< entity::Entity >( + TagFilter< entity::Package >() ) ); + m_flist->appendPredicate( + predicate::adapt< entity::Entity >( + QuickFilter< entity::Package >() ) ); + + m_lister->setRangeProvider( this ); + + QTimer::singleShot( 0, this, SLOT( delayed() ) ); +} + +Lister::Range View::listerRange() { + component::Packages &cp = cache::Global::get().packages(); + return cp.sorted(); + // return range( cp.packagesBegin(), cp.packagesEnd() ); +} + +void View::hideTags() { + QValueList< int > szl; + szl.append( 0 ); szl.append( 1 ); + setSizes( szl ); +} + +void View::hideFilters() { + QValueList< int > szl; + szl.append( 1 ); szl.append( 0 ); + m_bottom->setSizes( szl ); +} + +predicate::Predicate< entity::Entity > View::previewPredicate() +{ + return predicate::adapt< entity::Entity >( + (not predicate::Package::member( &entity::Package::markedKeep )) + or predicate::Package::member( &entity::Package::isBroken ) + or predicate::Package::member( &entity::Package::willBreak ) ); +} + +void View::setUpgradeMode() +{ + setPreviewMode(); + filterList()->setHiddenPredicate( + previewPredicate() or predicate::adapt< entity::Entity >( + predicate::Package::member( &entity::Package::isUpgradable ) ) ); +} + +void View::setPreviewMode() +{ + filterList()->setHiddenPredicate( previewPredicate() ); + hideFilters(); + hideTags(); +} + +void View::delayed() +{ + // cleanRebuild(); +} + +Browser::Browser( QWidget *p, const char *n ) + : QWidgetStack( p, n ), m_currentValid( false ) +{ + m_current = entity::Entity(); + addWidget( m_view = new View( this ) ); + addWidget( m_details = new PackageDetails( this ) ); + connect( m_view->lister(), SIGNAL( detailsRequested( Lister::Entity ) ), + this, SLOT( show( Lister::Entity ) ) ); + connect( m_details, SIGNAL( showList() ), + this, SLOT( showList() ) ); + connect( m_details, SIGNAL( back() ), + this, SLOT( back() ) ); + connect( m_details, SIGNAL( forward() ), + this, SLOT( forward() ) ); + connect( m_details, SIGNAL( detailsRequested( Lister::Entity ) ), + this, SLOT( show( Lister::Entity ) ) ); +} + +void Browser::showList() +{ + raiseWidget( m_view ); +} + +void Browser::back() +{ + m_forward.push_back( m_current ); + m_current = m_back.back(); + m_back.pop_back(); + doShow( m_current ); +} + +void Browser::forward() +{ + m_back.push_back( m_current ); + m_current = m_forward.back(); + m_forward.pop_back(); + doShow( m_current ); +} + +void Browser::doShow( Lister::Entity e ) +{ + m_details->setHasForward( !m_forward.empty() ); + m_details->setHasBack( !m_back.empty() ); + raiseWidget( m_details ); + m_details->setPackage( downcast< entity::Package >( e ) ); +} + +void Browser::show( Lister::Entity e ) +{ + m_forward.clear(); + if ( m_currentValid ) + m_back.push_back( m_current ); + m_currentValid = true; + m_current = e.stable(); + doShow( e ); +} + +/* Kolik existencialistu je potreba k zasroubovani zarovky? + Dva. Jeden sroubuje zarovku, a druhy premysli jak zarovka + sama o sobe predstavuje jednotlivy zarivy bod v subjektivni + realite v podsveti nekonecne absurdity dosahujici neuprimny + vesmir nicoty. */ diff --git a/adept/libadept/view.h b/adept/libadept/view.h new file mode 100644 index 0000000..ea6c6f5 --- /dev/null +++ b/adept/libadept/view.h @@ -0,0 +1,66 @@ +// -*- C++ -*- + +#include <deque> + +#include <qsplitter.h> +#include <qwidgetstack.h> + +#include <adept/lister.h> +#include <adept/filterlist.h> + +#ifndef EPT_VIEW_H +#define EPT_VIEW_H + +class QSplitter; + +namespace adept { + +class FilterSidebar; +class PackageDetails; + +class View: public QSplitter, public Lister::RangeProvider { + Q_OBJECT +public: + View( QWidget *p = 0, const char *n = 0 ); + FilterList *filterList() { return m_flist; } + Lister *lister() { return m_lister; } + virtual Lister::Range listerRange(); +public slots: + void cleanRebuild() { m_lister->cleanRebuild(); } + void hideFilters(); + void hideTags(); + void setPreviewMode(); + void setUpgradeMode(); +protected slots: + void delayed(); +protected: + predicate::Predicate< entity::Entity > previewPredicate(); + QSplitter *m_bottom; + FilterList *m_flist; + Lister *m_lister; + FilterSidebar *m_sidebar; +}; + +class Browser : public QWidgetStack { + Q_OBJECT +public: + Browser( QWidget *p = 0, const char *n = 0 ); + View *searchView() const { return m_view; } +public slots: + void forward(); + void back(); + void show( Lister::Entity e ); + void showList(); + void doShow( Lister::Entity e ); +protected: + typedef std::deque< Lister::Entity > Deque; + Deque m_forward, m_back; + entity::Entity m_current; + View *m_view; + PackageDetails *m_details; + bool m_currentValid; +}; + +} + +#endif diff --git a/adept/manager/Makefile.am b/adept/manager/Makefile.am new file mode 100644 index 0000000..a7b8a0f --- /dev/null +++ b/adept/manager/Makefile.am @@ -0,0 +1,20 @@ +bin_PROGRAMS = adept_manager +noinst_HEADERS = app.h +adept_manager_SOURCES = main.cpp app.cpp +adept_manager_LDADD = ../adept/libadept.la -lapt-front $(LIBEPT_LIBS) $(LIBTAGCOLL2_LIBS) $(LIBWIBBLE_LIBS) $(LIB_KIO) $(LIB_KDEUI) ../kubuntu_upgrader/libkubuntuupgradewizard.la +adept_manager_LDFLAGS = -L/usr/lib/debug +INCLUDES = $(all_includes) $(LIBAPT_FRONT_CFLAGS) $(LIBEPT_CFLAGS) $(LIBTAGCOLL2_CFLAGS) $(LIBWIBBLE_CFLAGS) -I$(srcdir)/.. -I.. +KDE_CXXFLAGS = $(USE_EXCEPTIONS) -DQT_NO_ASCII_CAST -DQT_NO_CAST_ASCII +METASOURCES = AUTO +KDE_ICON = AUTO + +rcdir = $(kde_datadir)/adept_manager +rc_DATA = adept_managerui.rc + +#shelldesktopdir = $(kde_appsdir)/System +xdg_apps_DATA = adept_manager.desktop + +messages: rc.cpp + $(EXTRACTRC) `find . -name \*.ui -o -name \*.rc` > rc.cpp + $(EXTRACTRC) `find . -name "*.rc"` >> rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/adept.pot diff --git a/adept/manager/adept_manager.desktop b/adept/manager/adept_manager.desktop new file mode 100644 index 0000000..6e7e311 --- /dev/null +++ b/adept/manager/adept_manager.desktop @@ -0,0 +1,43 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Adept Manager +Name[ca]=Gestor Adept +Name[ga]=Bainisteoir Adept +Name[ja]=Adept マネージャ +Name[pt]=Gestor do Adept +Name[sv]=Adept-hantering +GenericName=Manage Packages +GenericName[ca]=Gestiona de paquets +GenericName[ga]=Bainistigh Pacáistí +GenericName[ja]=パッケージを管理 +GenericName[pt]=Gestão de Pacotes +GenericName[sv]=Hantera paket +Exec=/opt/kde3/bin/adept_manager +Categories=Qt;KDE;System; +Icon=adept_manager +Type=Application +X-KDE-SubstituteUID=true +Comment=Manage installed and available software +Comment[bg]=Управление на инсталиран и наличен софтуер +Comment[ca]=Gestiona el programari instal·lat i disponible +Comment[cs]=Správa nainstalovaného a dostupného softwaru +Comment[da]=Håndtér installeret og tilgængelig software +Comment[de]=Verwaltet installierte und verfügbare Software +Comment[el]=Διαχείριση εγκατεστημένου και διαθέσιμου λογισμικού +Comment[es]=Administrar el software instalado y disponible +Comment[et]=Paigaldatud ja saadaoleva tarkvara haldamine +Comment[fr]=Gestion des logiciels disponibles et installés +Comment[ga]=Bainistigh bogearraí atá suiteáilte agus ar fáil +Comment[gl]=Xestiona o software instalado e disponíbel +Comment[it]=Gestisce il software installato e disponibile +Comment[ja]=インストール済み及び利用可能なソフトウェアを管理 +Comment[ka]=დაყენებული და ხელმისაწვდომი პროგრამების მართვა +Comment[lt]=Įdiegtų ir prieinamų programų tvarkymas +Comment[nl]=Beheren van geïnstalleerde en beschikbare software software +Comment[pt]=Gerir o 'software' instalado e disponível +Comment[sk]=Manažuje inštalovaný a dostupný software +Comment[sr]=Управља инсталираним и доступним програмима +Comment[sr@Latn]=Upravlja instaliranim i dostupnim programima +Comment[sv]=Hantera installerad och tillgänglig programvara +Comment[xx]=xxManage installed and available softwarexx +Terminal=false diff --git a/adept/manager/adept_managerui.rc b/adept/manager/adept_managerui.rc new file mode 100644 index 0000000..add78d4 --- /dev/null +++ b/adept/manager/adept_managerui.rc @@ -0,0 +1,38 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="6" name="adept"> + <MenuBar> + <Menu name="file" noMerge="1"> + <text>&Adept</text> + <Action name="update" /> + <Action name="sourceseditor" /> + <Action name="commit" /> + <Separator /> + <Action name="upgrade" /> + <Action name="dist-upgrade" /> + <Separator /> + <Action name="file_quit" /> + </Menu> + <Menu name="view" noMerge="1"> + <text>&View</text> + <Action name="packagelist" /> + <Action name="download_out" /> + <Action name="commit_out" /> + </Menu> + <Menu name="edit" noMerge="1"> + <text>&Edit</text> + <Action name="edit_undo" /> + <Action name="edit_redo" /> + </Menu> + </MenuBar> + + <ToolBar name="mainToolBar" noMerge="1"> + <Action name="update" /> + <Action name="preview" /> + <Action name="commit" /> + <Separator /> + <Action name="dist-upgrade" /> + <Separator/> + <Action name="edit_undo"/> + <Action name="edit_redo"/> + </ToolBar> +</kpartgui> diff --git a/adept/manager/app.cpp b/adept/manager/app.cpp new file mode 100644 index 0000000..832016e --- /dev/null +++ b/adept/manager/app.cpp @@ -0,0 +1,450 @@ +#define KUBUNTU + +#include <qvbox.h> +#include <qlabel.h> +#include <qwidgetstack.h> +#include <qsplitter.h> +#include <qtimer.h> +#include <qfile.h> + +#include <klocale.h> +#include <kmessagebox.h> +#include <kaction.h> +#include <kactionclasses.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kparts/part.h> +#include <kstatusbar.h> +#include <kprocess.h> + +// bleeeh +#include <apt-pkg/init.h> +#include <cassert> + +#include <apt-front/manager.h> +#include <apt-front/init.h> +#include <apt-front/cache/entity/package.h> +#include <apt-front/cache/component/state.h> +#include <apt-front/cache/component/history.h> +#include <apt-front/predicate/factory.h> + +#include <adept/acqprogresswidget.h> +#include <adept/progress.h> +#include <adept/utils.h> + +#ifdef KUBUNTU +#include <kubuntu_upgrader/upgradewizard.h> +#endif + +#include "app.h" + +using namespace aptFront; +using namespace aptFront::cache; +using namespace adept; + +TestApp::TestApp() { + kdDebug() << "ctor running" << endl; + setAcceptReadOnly( true ); + + setupActions(); + setupGUI(); + + m_rebuilds = 0; + m_stack = new QWidgetStack( this ); + + m_stack->addWidget( m_loading = new QLabel( i18n( "Loading, please wait..." ), m_stack ) ); + m_loading->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter ); + + Application::setStatusBar( statusBar() ); + + setCentralWidget( m_stack ); + + QTimer::singleShot( + 0, this, + SLOT( delayed() ) ); + + kdDebug() << "ctor done" << endl; + +#ifdef KUBUNTU + m_upgradeButtonAdded = false; +#endif +} + +void TestApp::guardLister( Lister *l ) +{ + connect( l, SIGNAL( rebuildStarted() ), + this, SLOT( rebuildStarted() ) ); + connect( l, SIGNAL( rebuildFinished() ), + this, SLOT( rebuildFinished() ) ); +} + +void TestApp::delayed() { + initialize(); + + observeComponent< component::State >(); + + m_stack->addWidget( m_list = new adept::Browser( m_stack ) ); + guardLister( m_list->searchView()->lister() ); + + m_stack->addWidget( m_sources = new adept::SourcesEditor( + _config->FindFile( + "Dir::Etc::sourcelist").c_str(), + this ) ); + + connect ( m_sources, SIGNAL( close() ), + this, SLOT( closeSources() ) ); + + // set up preview widget + m_stack->addWidget( m_preview = new adept::Browser( m_stack ) ); + + m_preview->searchView()->setPreviewMode(); + guardLister( m_preview->searchView()->lister() ); + + m_stack->addWidget( m_progress = new adept::AcqProgressWidget( m_stack ) ); + m_stack->addWidget( m_commitProgress = new adept::CommitProgress( m_stack ) ); + + m_stack->raiseWidget( m_list ); + + addMode( Sources, m_sourcesAction, m_sources ); + addMode( Preview, m_previewAction, m_preview ); + addMode( Download, m_progressAction, m_progress ); + addMode( Commit, m_commitProgressAction, m_commitProgress ); + + m_list->searchView()->lister()->cleanRebuild(); + m_preview->searchView()->lister()->cleanRebuild(); + setActionsEnabled( true ); + statusBar()->clear(); + notifyPostChange( 0 ); +} + +void TestApp::setupActions() +{ + (new KAction( + i18n( "Fetch Updates" ), u8( "adept_update" ), + 0, this, SLOT( update() ), actionCollection(), + "update" ))->setEnabled( false ); + + (new KAction( + i18n( "Reload Cache" ), u8( "adept_reload" ), + 0, this, SLOT( reload() ), actionCollection(), + "reload" ))->setEnabled( false ); + + m_upgrade = new KAction( + i18n( "Safe Upgrade" ), u8( "adept_upgrade" ), + 0, this, SLOT( upgrade() ), actionCollection(), + "upgrade" ); + m_distUpgrade = new KAction( + i18n( "Full Upgrade" ), u8( "adept_distupgrade" ), + 0, this, SLOT( distUpgrade() ), actionCollection(), + "dist-upgrade" ); + m_commit = new KAction( + i18n( "Apply Changes" ), u8( "adept_commit" ), + 0, this, SLOT( commit() ), actionCollection(), + "commit" ); + + m_sourcesAction = new KToggleAction( + i18n( "Manage Repositories" ), u8( "adept_sourceseditor" ), + 0, this, SLOT( toggleSources() ), actionCollection(), + "sourceseditor" ); + m_previewAction = new KToggleAction( + i18n( "Preview Changes" ), u8( "adept_preview" ), + 0, this, SLOT( togglePreview() ), actionCollection(), + "preview" ); + + m_progressAction = new KToggleAction( + i18n( "Show Last Download" ), u8( "adept_download_out" ), + 0, this, SLOT( toggleDownload() ), actionCollection(), + "download_out" ); + + m_commitProgressAction = new KToggleAction( + i18n( "Show Last DPkg Run" ), u8( "adept_commit_out" ), + 0, this, SLOT( toggleCommit() ), actionCollection(), + "commit_out" ); + + m_listAction = new KToggleAction( + i18n( "Show Package List" ), u8( "adept_packagelist" ), + 0, this, SLOT( closeModes() ), actionCollection(), + "packagelist" ); + + m_sourcesAction->setEnabled( true ); + m_progressAction->setEnabled( false ); + m_previewAction->setEnabled( false ); + m_commitProgressAction->setEnabled( false ); + m_listAction->setEnabled( false ); + + m_modesClosed = m_listAction; + m_listAction->setChecked( true ); + + m_undo = KStdAction::undo( this, SLOT( undo() ), actionCollection() ); + m_redo = KStdAction::redo( this, SLOT( redo() ), actionCollection() ); + + m_distUpgrade->setEnabled( false ); + m_upgrade->setEnabled( false ); + + m_commit->setEnabled( false ); + KStdAction::quit( this, SLOT( close() ), actionCollection() ); + setHistoryEnabled( false ); + createStandardStatusBarAction(); +} + +void TestApp::setHistoryEnabled( bool e ) { + if ( e && history() ) { + m_undo->setEnabled( history()->canUndo() ); + m_redo->setEnabled( history()->canRedo() ); + } else { + m_undo->setEnabled( false ); + m_redo->setEnabled( false ); + } +} + +void TestApp::setActionsEnabled( bool e ) +{ + m_actionsEnabled = e; + updateActionState(); +} + +void TestApp::updateActionState() +{ + bool e = m_actionsEnabled; + bool w = cache::Global::get().writeable(); + component::State &s = cache::Global::get().state(); + KActionPtrList a = actionCollection()->actions(); + /* View menus seem to be BROKEN HERE?! */ + for (KActionPtrList::iterator i = a.begin(); i != a.end(); ++i) { + if ( u8( (*i)->name() ) == u8( "update" ) ) { + (*i)->setEnabled( e && w ); + } else if ( u8( (*i)->name() ) == u8( "preview" ) ) { + (*i)->setEnabled( e ); + } else { + (*i)->setEnabled(e && w); + } + } + setHistoryEnabled( e ); + m_commit->setEnabled( e && w && s.changed() ); + m_upgrade->setEnabled( e && w && s.upgradableCount() ); + m_distUpgrade->setEnabled( e && w && s.upgradableCount() ); +} + +template< typename T, typename In > +void TestApp::aptAction( In b, In e ) { + const KAction *a = dynamic_cast<const KAction *>( sender() ); // HACK + typename T::Vector v = T::list(); + for (typename T::Vector::iterator i = v.begin(); i != v.end(); ++i) { + if( a->name() == i->name() ) { + (*i)( b, e ); + return; + } + } +} + +void TestApp::notifyPostRebuild( component::Base *b ) +{ + Application::notifyPostRebuild( b ); + notifyPostChange( b ); +} + +void TestApp::notifyPreChange( component::Base *b ) +{ + Application::notifyPreChange( b ); + checkpoint(); +} + +void TestApp::notifyPostChange( component::Base *b ) +{ + Application::notifyPostChange( b ); + updateActionState(); +} + +void TestApp::closeEvent( QCloseEvent *e ) { + cache::component::State &s = cache::Global::get().state(); + if (s.changed()) { + if (KMessageBox::warningYesNo( + this, i18n( "You have done changes that were left uncommited. " + "Are you sure you want to exit? " ), + i18n( "Uncommited changes, really quit?" ) ) == KMessageBox::Yes) + e->accept(); + } else + e->accept(); +} + +void TestApp::foregroundClosed() +{ + m_stack->raiseWidget( m_list ); +} + +void TestApp::update() { + closeModes(); + setActionsEnabled( false ); + aptFront::Manager m; + m.setProgressCallback( m_progress->callback() ); + m.setUpdateInterval( 100000 ); + try { + m_stack->raiseWidget( m_progress ); + m.update(); + } catch ( exception::OperationCancelled ) { // ignore + } catch (...) { + KMessageBox::sorry( this, + i18n( "There was an error downloading updates. " ), + i18n( "Could not fetch updates" ) ); + } + kdDebug() << "closing progress widget" << endl; + m_stack->raiseWidget( m_list ); + setActionsEnabled( true ); + notifyPostChange( 0 ); +#ifdef KUBUNTU + wizard = new UpgradeWizard(this, 0, 1); + if( !m_upgradeButtonAdded && wizard->checkForDistUpgrade(true) ) { + KToolBar* tool = toolBar(); + tool->insertButton(QString("2uparrow"), 12345, SIGNAL(released()), this, SLOT(releaseUpgrade()), true, i18n("Version Upgrade")); + m_upgradeButtonAdded = true; + } else { + wizard->close(); + } +#endif +} + +#ifdef KUBUNTU +void TestApp::releaseUpgrade() { + wizard->show(); +} +#endif + +#ifdef KUBUNTU +void TestApp::addVersionUpgrade(QString url, bool develVersion) { + wizard = new UpgradeWizard(this, 0, 1); + bool show = wizard->checkForDistUpgrade(false, url, develVersion); + if (show || develVersion) { + KToolBar* tool = toolBar(); + tool->insertButton(QString("2uparrow"), 12345, SIGNAL(released()), this, SLOT(releaseUpgrade()), true, i18n("Version Upgrade")); + m_upgradeButtonAdded = true; + } +} +#endif + +void TestApp::reload() { + cache().reopen(); +} + +void TestApp::commit() { + closeModes(); + setActionsEnabled( false ); + + aptFront::Manager m; + m.setProgressCallback( m_progress->callback() ); + m.setUpdateInterval( 100000 ); + try { + m_stack->raiseWidget( m_progress ); + m.download(); + m_stack->raiseWidget( m_commitProgress ); + m.commit(); + } catch ( exception::OperationCancelled ) { + } catch (...) { + KMessageBox::sorry( + this, i18n( "There was an error commiting changes. " + "Possibly there was a problem downloading some " + "packages or the commit would break packages. " ), + i18n( "Could not commit changes" ) ); + // FIXME: this should be handled by libapt-front + cache::Global::get().reopen(); + } + m_stack->raiseWidget( m_list ); + setActionsEnabled( true ); + notifyPostChange( 0 ); +} + +void TestApp::upgrade() { + closeModes(); + cache::Global::get().state().upgrade(); +} + +void TestApp::distUpgrade() { + closeModes(); + cache::Global::get().state().distUpgrade(); +} + +void TestApp::togglePreview() { + if ( modeActive( Preview ) ) + closeModes(); + else + openPreview(); +} + +void TestApp::toggleSources() { + QFile file(QString("/usr/bin/software-properties-kde")); + if (file.exists()) { + softwarePropertiesProcess = new KProcess(this); + + *softwarePropertiesProcess << "/usr/bin/software-properties-kde" << "--no-update"; + QApplication::connect(softwarePropertiesProcess, SIGNAL(processExited(KProcess *)), + this, SLOT(softwarePropertiesExited(KProcess *))); + softwarePropertiesProcess->start(); + } else { + kdDebug() << " no software-properties-kde exists" << endl; + if ( modeActive( Sources ) ) + closeModes(); + else + openSources(); + } +} + +void TestApp::softwarePropertiesExited(KProcess *) { + if (softwarePropertiesProcess->exitStatus() == 1) { + update(); + } +} + +void TestApp::toggleDownload() { + toggleMode( Download ); +} + +void TestApp::toggleCommit() { + toggleMode( Commit ); +} + +void TestApp::toggleMode( Mode m ) { + if ( modeActive( m ) ) + closeModes(); + else + openMode( m ); +} + +void TestApp::openPreview() { + if ( openMode( Preview ) ) + m_preview->searchView()->lister()->scheduleRebuild(); +} + +void TestApp::closePreview() { + if ( closeMode( Preview ) ) + m_list->searchView()->lister()->scheduleRebuild(); +} + +void TestApp::openSources() { + if ( openMode( Sources ) ) + m_sources->reset(); +} + +void TestApp::closeSources() { + closeMode( Sources ); +} + +bool TestApp::closeMode ( Mode m ) { + if ( modeActive( m ) ) { + m_stack->raiseWidget( m_list ); + modeAction( m )->setChecked( false ); + return true; + } + return false; +} + +bool TestApp::openMode( Mode m ) { + if ( !modeActive( m ) ) { + closeModes(); + m_modesClosed->setChecked( false ); + kdDebug() << "openMode widget: " << modeWidget( m ) << endl; + m_stack->raiseWidget( modeWidget( m ) ); + return true; + } + return false; +} + +#include "app.moc" diff --git a/adept/manager/app.h b/adept/manager/app.h new file mode 100644 index 0000000..0fc1927 --- /dev/null +++ b/adept/manager/app.h @@ -0,0 +1,162 @@ +/* -*- C++ -*- */ +#ifndef TESTUI_APP_H +#define TESTUI_APP_H + +#define KUBUNTU + +#include <kmainwindow.h> +#include <kprocess.h> +#include <kparts/part.h> +#include <kactionclasses.h> +#include <apt-front/cache/observer.h> +#include <apt-front/cache/component/state.h> +#include <apt-front/cache/component/history.h> +#include <adept/view.h> +#include <adept/commitprogress.h> +#include <adept/sourceseditor.h> +#include <adept/application.h> + +#ifdef KUBUNTU +#include <kubuntu_upgrader/upgradewizard.h> +#endif + +class QVBox; +class QWidgetStack; +class QSplitter; +class KAction; +namespace adept { +class AcqProgressWidget; +} + +using namespace aptFront; +using namespace adept; + +class TestApp : public KMainWindow, Application { + Q_OBJECT +public: + enum Mode { Default, Sources, Preview, Download, Commit }; + void setupActions(); + ExtTerminalInterface *terminal(); + TestApp(); +#ifdef KUBUNTU + void addVersionUpgrade(QString url, bool develVersion=false); +#endif +protected slots: + void delayed(); // initialisation + + void setActionsEnabled( bool ); + void setHistoryEnabled( bool ); + + void update(); // actions + void upgrade(); + void distUpgrade(); +#ifdef KUBUNTU + void releaseUpgrade(); +#endif + void commit(); + + void reload(); // debugging + + void undo() { Application::undo(); } + void redo() { Application::redo(); } + void checkpoint() { Application::checkpoint(); } + + void foregroundClosed(); + + void togglePreview(); + void toggleSources(); + void softwarePropertiesExited(KProcess *); + void toggleDownload(); + void toggleCommit(); + + void closePreview(); + void closeSources(); + + void openPreview(); + void openSources(); + + bool modeActive( Mode m ) { + // return modeAction( m )->isChecked(); + return modeWidget( m ) == m_stack->visibleWidget(); + } + + void closeModes() { + closePreview(); + closeSources(); + closeMode( Download ); + closeMode( Commit ); + m_modesClosed->setChecked( true ); + } + + void rebuildStarted() { + if ( !m_rebuilds ) setActionsEnabled( false ); + m_rebuilds ++; + } + + void rebuildFinished() { + m_rebuilds --; + if ( !m_rebuilds ) setActionsEnabled( true ); + } + +protected: + void updateActionState(); + void guardLister( adept::Lister * ); + void addMode( Mode m, KToggleAction *a, QWidget *w ) { + m_modeActionMap[ m ] = a; + m_modeWidgetMap[ m ] = w; + a->setChecked( false ); + } + + KToggleAction *modeAction( Mode m ) { + return m_modeActionMap[ m ]; + } + + QWidget *modeWidget( Mode m ) { + return m_modeWidgetMap[ m ]; + } + + bool openMode( Mode ); + bool closeMode( Mode ); + void toggleMode( Mode ); + + friend class WaitForLister; + virtual void closeEvent( QCloseEvent * ); + virtual void notifyPostChange( cache::component::Base * ); + virtual void notifyPostRebuild( cache::component::Base * ); + virtual void notifyPreChange( cache::component::Base * ); + + QWidgetStack *m_stack; + QLabel *m_loading; + + // stacked widgets + adept::AcqProgressWidget *m_progress; + adept::Browser *m_list, *m_preview; + adept::SourcesEditor *m_sources; + adept::CommitProgress *m_commitProgress; + + // other stuff + std::vector<KAction *> m_actions; + QMap< QString, QString > m_icons; + KAction *m_undo, *m_redo; + + int m_rebuilds; + bool m_actionsEnabled; + + KAction *m_commit, *m_upgrade, *m_distUpgrade; + KToggleAction *m_sourcesAction, *m_commitProgressAction, *m_listAction, + *m_previewAction, *m_progressAction; + std::map< Mode, KToggleAction * > m_modeActionMap; + std::map< Mode, QWidget * > m_modeWidgetMap; + KToggleAction *m_modesClosed; +private: + template<typename T> void plugAptActions(); + // template<typename T, typename In> void updateAptActions( In b, In e ); + template<typename T, typename In> void aptAction( In b, In e ); + KProcess* softwarePropertiesProcess; +#ifdef KUBUNTU + UpgradeWizard* wizard; + bool m_upgradeButtonAdded; +#endif +}; + +#endif diff --git a/adept/manager/hi128-app-adept_manager.png b/adept/manager/hi128-app-adept_manager.png Binary files differnew file mode 100644 index 0000000..ba3cb4b --- /dev/null +++ b/adept/manager/hi128-app-adept_manager.png diff --git a/adept/manager/hi16-app-adept_manager.png b/adept/manager/hi16-app-adept_manager.png Binary files differnew file mode 100644 index 0000000..80a35a1 --- /dev/null +++ b/adept/manager/hi16-app-adept_manager.png diff --git a/adept/manager/hi22-app-adept_manager.png b/adept/manager/hi22-app-adept_manager.png Binary files differnew file mode 100644 index 0000000..dc4392d --- /dev/null +++ b/adept/manager/hi22-app-adept_manager.png diff --git a/adept/manager/hi32-app-adept_manager.png b/adept/manager/hi32-app-adept_manager.png Binary files differnew file mode 100644 index 0000000..d1b4a61 --- /dev/null +++ b/adept/manager/hi32-app-adept_manager.png diff --git a/adept/manager/hi48-app-adept_manager.png b/adept/manager/hi48-app-adept_manager.png Binary files differnew file mode 100644 index 0000000..d76f679 --- /dev/null +++ b/adept/manager/hi48-app-adept_manager.png diff --git a/adept/manager/hi64-app-adept_manager.png b/adept/manager/hi64-app-adept_manager.png Binary files differnew file mode 100644 index 0000000..cabb87b --- /dev/null +++ b/adept/manager/hi64-app-adept_manager.png diff --git a/adept/manager/hisc-app-adept_manager.svgz b/adept/manager/hisc-app-adept_manager.svgz Binary files differnew file mode 100644 index 0000000..55ac033 --- /dev/null +++ b/adept/manager/hisc-app-adept_manager.svgz diff --git a/adept/manager/main.cpp b/adept/manager/main.cpp new file mode 100644 index 0000000..c6e1eba --- /dev/null +++ b/adept/manager/main.cpp @@ -0,0 +1,71 @@ +#include <stdlib.h> + +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#include <kuniqueapplication.h> + +#include "app.h" + +static KCmdLineOptions options[] = +{ + { "dist-upgrade", I18N_NOOP("add toolbar button to launch the version upgrade tool to the latest release"), 0}, + { "dist-upgrade-proposed", I18N_NOOP("add toolbar button to launch the version upgrade tool to proposed next release"), 0}, + { "dist-upgrade-devel", I18N_NOOP("add toolbar button to launch the version upgrade tool to development version"), 0}, + KCmdLineLastOption +}; + +int main(int argc, char *argv[]) +{ + + KLocale::setMainCatalogue("adept"); + + putenv( "QT_IM_MODULE=xim" ); + QString description = i18n("Adept Manager"); + + KAboutData aboutData( "adept_manager", + I18N_NOOP("Adept Manager"), + "2.1 Cruiser", + description.latin1(), + KAboutData::License_BSD, + I18N_NOOP("(c) 2005, 2006 Peter Rockai"), + 0, + "http://web.mornfall.net/adept.html"); + + aboutData.addAuthor ( "Peter Rockai", + I18N_NOOP("developer"), + "me at mornfall dot net", + "http://web.mornfall.net"); + + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication app; + + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + // if (args && args->isSet("xy")) ... + + /* KConfig* config = KGlobal::config(); + config->setGroup("General Settings"); + QString version = config->readEntry("Version"); */ + + KGlobal::locale()->insertCatalogue(QString::fromUtf8("libept")); + KGlobal::locale()->insertCatalogue(QString::fromUtf8("libapt-front")); + + TestApp *ta = new TestApp(); + + app.setMainWidget(ta); + +#ifdef KUBUNTU + if (args && args->isSet("dist-upgrade")) { + ta->addVersionUpgrade(QString("http://changelogs.ubuntu.com/meta-release")); + } else if (args && args->isSet("dist-upgrade-proposed")) { + ta->addVersionUpgrade(QString("http://changelogs.ubuntu.com/meta-release-proposed")); + } else if (args && args->isSet("dist-upgrade-devel")) { + ta->addVersionUpgrade(QString("http://changelogs.ubuntu.com/meta-release-development"), true); + } +#endif + + ta->show(); + + return app.exec(); +} diff --git a/adept/notifier/15adept-periodic-update b/adept/notifier/15adept-periodic-update new file mode 100644 index 0000000..d1922e3 --- /dev/null +++ b/adept/notifier/15adept-periodic-update @@ -0,0 +1,3 @@ +APT::Periodic::Update-Package-Lists "1"; +APT::Periodic::Download-Upgradeable-Packages "0"; +APT::Periodic::AutocleanInterval "0"; diff --git a/adept/notifier/Makefile.am b/adept/notifier/Makefile.am new file mode 100644 index 0000000..6b576be --- /dev/null +++ b/adept/notifier/Makefile.am @@ -0,0 +1,26 @@ + +bin_PROGRAMS = adept_notifier +#kdeinit_LTLIBRARIES = adept-notifier.la +noinst_HEADERS = app.h + +adept_notifier_SOURCES = app.cpp +adept_notifier_LDADD = ../adept/libadept.la $(LIBAPT_FRONT_LIBS) $(LIBEPT_LIBS) $(LIBTAGCOLL2_LIBS) $(LIB_KIO) $(LIBKDE_UI) +adept_notifier_LDFLAGS = -L/usr/lib/debug + +INCLUDES = $(all_includes) $(LIBAPT_FRONT_CFLAGS) $(LIBEPT_CFLAGS) $(LIBTAGCOLL2_CFLAGS) $(LIBWIBBLE_CFLAGS) -I$(srcdir)/.. -I.. +KDE_CXXFLAGS = $(USE_EXCEPTIONS) -DQT_NO_ASCII_CAST -DQT_NO_CAST_ASCII +METASOURCES = AUTO +KDE_ICON = AUTO + +rcdir = $(kde_datadir)/adept-notifier +#rc_DATA = adept-updaterui.rc + +#shelldesktopdir = $(kde_appsdir)/System +xdg_apps_DATA = adept_notifier.desktop +autostart_DATA = adept_notifier_auto.desktop +autostartdir = /etc/xdg/autostart + +messages: rc.cpp + $(EXTRACTRC) `find . -name \*.ui -o -name \*.rc` > rc.cpp + $(EXTRACTRC) `find . -name "*.rc"` >> rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/adept_notifier.pot diff --git a/adept/notifier/adept_notifier.desktop b/adept/notifier/adept_notifier.desktop new file mode 100644 index 0000000..453ef5f --- /dev/null +++ b/adept/notifier/adept_notifier.desktop @@ -0,0 +1,63 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Adept Notifier +Name[ca]=Notificador Adept +Name[da]=Adept underretninger +Name[de]=Adept Benachrichtigung +Name[el]=Ειδοποίηση ενημερώσεων του Adept +Name[es]=Notificador Adept +Name[fr]=Notificateur Adept +Name[ga]=Fógróir Adept +Name[gl]=Notificador de Adept +Name[it]=Notifica automatica Adept +Name[ka]=Adept შემტყობინებელი +Name[lt]=Adept informuoklis +Name[pt]=Notificador do Adept +Name[sk]=Adept upozornenie +Name[sv]=Adept uppdatering +Name[xx]=xxAdept Notifierxx +GenericName=Update Reminder +GenericName[bg]=Напомняне за обновяване +GenericName[ca]=Recordador d'actualitzacions +GenericName[cs]=Upozorňování na aktualizace +GenericName[da]=Opdateringspåmindelser +GenericName[de]=Aktualisierungsbenachrichtigung +GenericName[el]=Υπενθύμιση ενημέρωσης +GenericName[es]=Recordar actualización +GenericName[gl]=Recorda-lle a existéncia de Actualizazóns +GenericName[it]=Avviso aggiornamenti +GenericName[ja]=アップデートを通知 +GenericName[ka]=შემხსენებლის განახლება +GenericName[lt]=Atnaujinimų priminimai +GenericName[nl]=Updateherinnering +GenericName[pt]=Chamada de Atenção de Actualizações +GenericName[sk]=Pripomienka aktualizácie +GenericName[sv]=Uppdateringspåminnelse +GenericName[xx]=xxUpdate Reminderxx +Exec=adept_notifier -caption "%c" +TryExec=adept_notifier +Categories=Qt;KDE;System; +Icon=adept_notifier +Type=Application +X-KDE-SubstituteUID=false +Comment=Watch for updates +Comment[bg]=Следене за обновяване +Comment[ca]=Vigila les actualitzacions +Comment[cs]=Sledování aktualizací +Comment[da]=Overvåg opdateringer +Comment[de]=Überprüft Aktualisierungen +Comment[el]=Παρακολούθηση για ενημερώσεις +Comment[es]=Busca actualizaciones +Comment[ga]=Déan faire ar nuashonruithe +Comment[gl]=Comproba as actualizazóns +Comment[it]=Controlla la presenza di aggiornamenti +Comment[ja]=アップデートを監視 +Comment[ka]=განახლებების თვალთვალი +Comment[lt]=Atnaujinimų stebėjimas +Comment[nl]=Updates volgen +Comment[pt]=Pesquisar actualizações +Comment[sk]=Sledovať aktualizácie +Comment[sv]=Bevaka uppdateringar +Comment[xx]=xxWatch for updatesxx +Terminal=false +NoDisplay=true diff --git a/adept/notifier/adept_notifier_auto.desktop b/adept/notifier/adept_notifier_auto.desktop new file mode 100644 index 0000000..42c37ba --- /dev/null +++ b/adept/notifier/adept_notifier_auto.desktop @@ -0,0 +1,23 @@ +[Desktop Entry] +Encoding=UTF-8 +Exec=adept_notifier +Name=Adept Notifier +Name[ca]=Notificador Adept +Name[da]=Adept underretninger +Name[de]=Adept Benachrichtigung +Name[el]=Ειδοποίηση ενημερώσεων του Adept +Name[es]=Notificador Adept +Name[fr]=Notificateur Adept +Name[ga]=Fógróir Adept +Name[gl]=Notificador de Adept +Name[it]=Notifica automatica Adept +Name[ka]=Adept შემტყობინებელი +Name[lt]=Adept informuoklis +Name[pt]=Notificador do Adept +Name[sk]=Adept upozornenie +Name[sv]=Adept uppdatering +Name[xx]=xxAdept Notifierxx +X-KDE-autostart-after=panel +Type=Service +X-KDE-autostart-condition=adept_notifierrc:General:Autostart:true +OnlyShowIn=KDE; diff --git a/adept/notifier/app.cpp b/adept/notifier/app.cpp new file mode 100644 index 0000000..2ed8c2b --- /dev/null +++ b/adept/notifier/app.cpp @@ -0,0 +1,342 @@ +#include <unistd.h> +#include <sys/stat.h> +#include <qtooltip.h> +#include <qtimer.h> +#include <qfile.h> + +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kglobalaccel.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kiconloader.h> +#include <kaboutapplication.h> +#include <kaction.h> +#include <kpopupmenu.h> +#include <kconfig.h> +#include <kpassivepopup.h> +#include <kiconloader.h> + +#include <apt-front/init.h> +#include <apt-front/cache/cache.h> +#include <apt-front/cache/component/packages.h> +#include <apt-front/predicate/factory.h> + +#include <adept/utils.h> + +#include "app.h" + +using namespace aptFront; +using namespace cache; +using namespace utils; +using namespace adept; + +TrayWindow::TrayWindow(QWidget *parent, const char *name) + : KSystemTray(parent, name), m_updates( 0 ) +{ + setAvailableUpdates( m_updates ); + // actionCollection()->remove( actionCollection()->action( "quit" ) ); + m_quit = KStdAction::quit( this, SIGNAL( quitSelected() ), actionCollection() ); + m_about = KStdAction::aboutApp( this, SIGNAL( aboutSelected() ), actionCollection() ); + // setPixmap( loadIcon( u8( "adept_notifier_warning" ) ) ); +} + +void TrayWindow::contextMenuAboutToShow( KPopupMenu *r ) { + kdDebug() << "TrayWindow::contextMenu()" << endl; + r->clear(); + m_about->plug( r ); + m_quit->plug( r ); +} + +void TrayWindow::setAvailableUpdates( int n ) +{ + m_updates = n; + kdDebug() << "TrayWindow obtained " << n << endl; + + setPixmap( m_updates == 0 ? + loadIcon( u8( "adept_notifier_ok" ) ) : + loadIcon( u8( "adept_notifier_warning" ) ) ); + + if ( m_updates == 0 ) + hide(); + else + show(); + + QToolTip::remove(this); + QToolTip::add(this, n == 0 ? i18n( "No updates needed." ) + : i18n( "There is %n updated package available", + "There are %n updated packages available", n ) ); +} + +void TrayWindow::mouseReleaseEvent(QMouseEvent *ev) +{ + if (ev->button() == QMouseEvent::LeftButton) + emit clicked(); + KSystemTray::mouseReleaseEvent(ev); +} + +void ApportTrayWindow::mousePressEvent(QMouseEvent *ev) +{ + emit clicked(); + hide(); +} + +void RebootTrayWindow::mousePressEvent(QMouseEvent *ev) +{ + emit clicked(); +} + +NotifierApp::NotifierApp(bool allowStyles, bool GUIenabled) + : KUniqueApplication(allowStyles, GUIenabled), + m_tray( 0 ) +{ + sharedConfig()->setGroup( "General" ); + m_okAutostart = sharedConfig()->readBoolEntry( "Autostart", true ); + m_timer = new QTimer( this ); + m_tray = new TrayWindow( 0, 0 ); + m_tray->show(); + m_rebootRequired = false; + m_rebootShown = false; + + aptFront::init(); + + fileUpdated( "/var/cache/apt/pkglist.bin", m_updateStamp ); + // fileUpdated( "/var/lib/apt/periodic/update-stamp", m_updateStamp ); + fileUpdated( "/var/lib/dpkg/status", m_statusStamp ); + + m_tray->setAvailableUpdates( upgradable() ); + + connect( m_tray, SIGNAL( clicked() ), this, SLOT( clicked() ) ); + // connect( m_tray, SIGNAL( quitSelected() ), this, SLOT( quit() ) ); + connect( m_tray, SIGNAL( quitSelected() ), this, SLOT( askQuit() ) ); + connect( m_tray, SIGNAL( aboutSelected() ), this, SLOT( about() ) ); + connect( m_timer, SIGNAL( timeout() ), this, SLOT( checkUpdates() ) ); + m_timer->start( 1000*5 ); // 5 secs now, used to be 60 + if ( !m_okAutostart ) { + int r = KMessageBox::questionYesNo( + m_tray, i18n( "You disabled automatic startup of Adept Notifier last time " + "you quit the application. " + "Do you want to start Adept Notifier next time you log in?" ), + i18n( "Automatic Startup" ), + KGuiItem( i18n( "Start" ) ), KGuiItem( i18n( "Don't Start" ) ), + u8( "enableAutostart" ) ); + if ( r == KMessageBox::Yes ) { + sharedConfig()->setGroup( "General" ); + sharedConfig()->writeEntry( "Autostart", true ); + m_okAutostart = true; + } + } + + // if apport crash handler it installed, watch for crash reports appearing and run + // the apport frontend when they do + bool runApport = sharedConfig()->readBoolEntry( "Apport", true ); + if ( QFile::exists(QString("/usr/share/apport/apport-qt")) && runApport ) { + m_dirWatch = new KDirWatch(this); + m_dirWatch->addDir(QString("/var/crash")); + connect( m_dirWatch, SIGNAL( dirty(const QString&) ), this, SLOT( crashWatcher() ) ); + + KProcess *proc = new KProcess; + *proc << "/usr/share/apport/apport-checkreports"; + connect( proc, SIGNAL(processExited(KProcess*)), this, SLOT(apportCheckExited(KProcess*)) ); + proc->start(KProcess::Block); + + if (m_crashes) { + ApportTrayWindow* crashApplet = new ApportTrayWindow; + crashApplet->setPixmap( crashApplet->loadIcon(u8("apport")) ); + QString crashMessage = i18n("An application has crashed on your " + "system (now or in the past).\n" + "Click to " + "display details. " + ); + QToolTip::add(crashApplet, crashMessage); + connect( crashApplet, SIGNAL(clicked()), this, SLOT(crashWatcher()) ); + crashApplet->show(); + QPixmap icon = BarIcon(u8("apport")); + KPassivePopup::message(i18n("Crash Handler"), crashMessage, icon, crashApplet); + } + } + // if reboot-required is installed watch for reboot-required and dpkg-run-stamp + if ( QFile::exists(QString("/usr/share/update-notifier/notify-reboot-required")) ) { + m_rebootDirWatch = new KDirWatch(this); + m_rebootDirWatch->addFile(QString("/var/run/reboot-required")); + m_rebootDirWatch->addFile(QString("/var/lib/update-notifier/dpkg-run-stamp")); + connect( m_rebootDirWatch, SIGNAL( dirty(const QString&) ), this, SLOT( rebootWatcher(const QString&) ) ); + + } +} + +void NotifierApp::crashWatcher() { + // find out if there are system crash reports first, if there are run it as root + KProcess *proc = new KProcess; + *proc << "/usr/share/apport/apport-checkreports"; + *proc << "--system"; + connect( proc, SIGNAL(processExited(KProcess*)), this, SLOT(apportCheckExited(KProcess*)) ); + proc->start(KProcess::Block); + + if (m_crashes) { + KProcess *proc2 = new KProcess; + *proc2 << "kdesu" << "/usr/share/apport/apport-qt"; + proc2->start(KProcess::DontCare); + } else { + KShellProcess *proc2 = new KShellProcess; + *proc2 << "sleep 1; /usr/share/apport/apport-qt"; //needs a seconds delay else we're too fast for apport + proc2->start(KProcess::DontCare); + } +} + +void NotifierApp::apportCheckExited(KProcess* proc) { + if (proc->exitStatus() == 0) { + m_crashes = true; + } else { + m_crashes = false; + } +} + +void NotifierApp::rebootWatcher(const QString& path) { + kdDebug() << "NotifierApp::rebootWatcher: " << path << endl; + + if (path == QString("/var/run/reboot-required")) { + m_rebootRequired = true; + } + + if (path == QString("/var/lib/update-notifier/dpkg-run-stamp") && m_rebootRequired && !m_rebootShown) { + + RebootTrayWindow* rebootApplet = new RebootTrayWindow; + rebootApplet->setPixmap( rebootApplet->loadIcon(u8("reload")) ); + + QString rebootMessage = i18n("In order to complete the update your system needs to be restarted."); + QToolTip::add(rebootApplet, rebootMessage); + connect( rebootApplet, SIGNAL(clicked()), this, SLOT(rebootClicked()) ); + rebootApplet->show(); + QPixmap icon = BarIcon(u8("reload")); + KPassivePopup::message(i18n("Reboot Required"), rebootMessage, icon, rebootApplet); + m_rebootShown = true; + } + +} + +void NotifierApp::rebootClicked() { + kdDebug() << "NotifierApp::rebootClicked" << endl; + if (KMessageBox::questionYesNo(0, QString("In order to complete the update your system needs to be restarted."), QString("Restart Require")) == KMessageBox::Yes) { + kdDebug() << "NotifierApp::rebootClicked yes!" << endl; + KProcess *proc = new KProcess; + *proc << "/usr/bin/dcop"; + *proc << "ksmserver" << "ksmserver" << "logout" << "0" << "1" << "2"; // 0 1 2 == ShutdownConfirmNo ShutdownTypeReboot ShutdownModeForceNow + proc->start(); + } +} + +void NotifierApp::askQuit() { + if ( m_okAutostart ) { + int r = KMessageBox::questionYesNoCancel( + m_tray, i18n( "Do you want to start Adept Notifier next time you log in?" ), + i18n( "Automatic Startup" ), + KGuiItem( i18n( "Start" ) ), KGuiItem( i18n( "Don't Start" ) ) ); + if ( r == KMessageBox::Cancel ) + return; + if ( r == KMessageBox::No ) { + sharedConfig()->setGroup( "General" ); + sharedConfig()->writeEntry( "Autostart", false ); + } + } + exit( 0 ); + +} + +bool NotifierApp::fileUpdated( const char *f, time_t &stamp ) { + time_t old = stamp; + struct stat s; + ::stat( f, &s ); + stamp = s.st_mtime; + if ( stamp > old ) + return true; + return false; +} + +int NotifierApp::upgradable() { + try { + kdDebug() << "checking cache for upgradable packages..." << endl; + cache::Cache &c = cache::Global::get(); + c.open( Cache::OpenReadOnly + | Cache::OpenPackages + | Cache::OpenState ); + + kdDebug() << "cache opened, listing..." << endl; + Range< entity::Package > r = range( c.packages().packagesBegin(), + c.packages().packagesEnd() ); + kdDebug() << "looking for upgradable packages..." << endl; + Range< entity::Package > fr = filteredRange( + r, predicate::Package::member( &entity::Package::isUpgradable ) ); + VectorRange< entity::Package > vr = VectorRange< entity::Package >(); + fr.output( vr ); + kdDebug() << "found " << vr.size() << " upgradable package(s)" << endl; + int ret = vr.size(); + c.close(); + return ret; + } catch ( exception::Error e ) { + kdDebug() << "error checking cache for upgradable packages..." << endl; + kdDebug() << "what: " << e.message() << endl; + } catch ( std::exception e ) { + kdDebug() << "exception checking cache for upgradable packages..." << endl; + kdDebug() << "what: " << e.what() << endl; + // XXX error handling + } + return true; // we don't know, so assume true (safe) +} + +void NotifierApp::checkUpdates() { + // kdDebug() << "checking updates status" << endl; + if ( // fileUpdated( "/var/lib/apt/periodic/update-stamp", m_updateStamp ) + fileUpdated( "/var/cache/apt/pkgcache.bin", m_updateStamp ) + || fileUpdated( "/var/lib/dpkg/status", m_statusStamp ) ) + m_tray->setAvailableUpdates( upgradable() ); +} + +void NotifierApp::about() { + KAboutApplication *a = new KAboutApplication( m_tray, "", true ); + a->exec(); + delete a; +} + +NotifierApp::~NotifierApp() +{ + delete m_tray; +} + +void NotifierApp::clicked() +{ + if ( m_tray->updates() == 0 ) + return KMessageBox::information( + 0, i18n( "There are no known updates available." ), + i18n( "Nothing to do" ) ); + startServiceByDesktopName( u8( "adept_updater" ) ); +} + +/* void NotifierApp::menuActivated(int id) +{ + // implement help +} */ + +const char * DESCRIPTION = + I18N_NOOP("Adept update notifier utility"); + +/* extern "C" KDE_EXPORT */ +int main(int argc, char *argv[]) +{ + KAboutData about("adept_notifier", I18N_NOOP("Adept Notifier"), + "2.1 Cruiser", + DESCRIPTION, KAboutData::License_BSD, + "Copyright (C) 2005, 2006 Peter Rockai"); + KCmdLineArgs::init(argc, argv, &about); + NotifierApp::addCmdLineOptions(); + + if (!NotifierApp::start()) + return 0; + + NotifierApp app; + app.disableSessionManagement(); + app.exec(); + return 0; +} diff --git a/adept/notifier/app.h b/adept/notifier/app.h new file mode 100644 index 0000000..c543aaa --- /dev/null +++ b/adept/notifier/app.h @@ -0,0 +1,93 @@ +#ifndef EPT_NOTIFIER_H +#define EPT_NOTIFIER_H + +#include <sys/types.h> +#include <ksystemtray.h> +#include <kuniqueapplication.h> +#include <kdirwatch.h> +#include <kprocess.h> + +class QWidget; +class KAction; +// class KGlobalAccel; + +// the status indicator in system tray +class TrayWindow : public KSystemTray +{ + Q_OBJECT +public: + TrayWindow(QWidget *parent=0, const char *name=0); + void setAvailableUpdates( int n ); + int updates() { return m_updates; } + void contextMenuAboutToShow ( KPopupMenu * ); +signals: + void clicked(); + void aboutSelected(); +protected: + void mouseReleaseEvent( QMouseEvent * ); + int m_updates; + KAction *m_quit, *m_about; +}; + +// the apport indicator in system tray +// gets shown where the app is started and +// existing apport reports are found. +// clicking starts apport-qt +class ApportTrayWindow : public KSystemTray +{ + Q_OBJECT +signals: + void clicked(); +protected: + void mousePressEvent(QMouseEvent*); +}; + +// used for the reboot notifier +class RebootTrayWindow : public KSystemTray +{ + Q_OBJECT +signals: + void clicked(); +protected: + void mousePressEvent(QMouseEvent*); +}; + + + +// application watching the current status +// it will update the icon and run +class NotifierApp : public KUniqueApplication +{ + Q_OBJECT +public: + NotifierApp(bool allowStyles=true, bool GUIenabled=true); + ~NotifierApp(); + bool fileUpdated( const char *, time_t & ); + int upgradable(); + +protected slots: +// void menuActivated(int id); + void clicked(); + void checkUpdates(); + void askQuit(); + void about(); + // for apport + void crashWatcher(); + void apportCheckExited(KProcess*); + void rebootWatcher(const QString& path); + void rebootClicked(); + +protected: + TrayWindow *m_tray; + QTimer *m_timer; + time_t m_updateStamp, m_statusStamp; + bool m_okAutostart; + // for apport crash handler + KDirWatch* m_dirWatch; + KDirWatch* m_rebootDirWatch; + bool m_crashes; + bool m_rebootRequired; + bool m_rebootShown; //have we already shown the reboot notifier? +}; + +#endif diff --git a/adept/tests/libcapture/celem-test.cpp b/adept/tests/libcapture/celem-test.cpp new file mode 100644 index 0000000..ada22e3 --- /dev/null +++ b/adept/tests/libcapture/celem-test.cpp @@ -0,0 +1,34 @@ +#include <test-util.h> +#include <libcapture/celem.h> +#include <libcapture/pkgmanager.h> +#include <string> + +namespace tut { + + using namespace std; + using namespace capture; + + struct celem_shar { + }; + + typedef test_group<celem_shar> tg; + typedef tg::object to; + tg celem_tg ("celem"); + template<> template<> + void to::test<1> () + { + cacheInit (); + PkgCElemPtr a = cElem (PkgManager::cache () -> FindPkg ("postfix")); + ensure (a -> id () == string ("postfix")); + cerr << "a -> id () = " << a -> id () << endl; + ensure (a -> Name () == string ("postfix")); + cerr << "a -> Name () = " << a -> id () << endl; + VerCElemPtr b = a -> VersionList (); + cerr << "b -> id () = " << b -> id () << endl; + pkgCache::PkgIterator bp = (PkgManager::cache () -> FindPkg + ("postfix")); + string bver = bp . VersionList () . VerStr (); + ensure (bver == b -> id ()); + ensure (bver == b -> VerStr ()); + } +}; diff --git a/adept/tests/libcapture/grouper-test.cpp b/adept/tests/libcapture/grouper-test.cpp new file mode 100644 index 0000000..c454f78 --- /dev/null +++ b/adept/tests/libcapture/grouper-test.cpp @@ -0,0 +1,44 @@ +#include <tut.h> +#define protected public +#include <libcapture/grouper.h> +#include <libcapture/tree.h> +#include <libcapture/treenode.h> +#include <libcapture/treefactory.h> +#include <string> + +namespace tut { + + using namespace std; + using namespace capture; + + struct grouper_shar { + }; + + typedef test_group<grouper_shar> tg; + typedef tg::object to; + tg grouper_tg ("grouper"); +#define IT(x) dynamic_cast <GrouperFactory *> (c -> m_vec [x] . second) + template<> template<> + void to::test<1> () + { + Param::Map a; + GrouperChain *c; + GrouperTNode *n0, *n1, *n2, *n3; + c = new GrouperChain ("test"); + n0 = c -> addFactory ("SectGrouper", "sect"); + ensure (IT (0)); ensure (IT (0) == n0); + n1 = c -> addFactory ("EndGrouper", "end"); + ensure (IT (1)); ensure (IT (1) == n1); + n2 = c -> addFactory ("PkgExistFilter", "exist", a, Grouper::Custom, 1); + ensure (IT (2)); + ensure (IT (0) == n0); + ensure (IT (1) == n2); + ensure (IT (2) == n1); + n3 = c -> addFactory ("PkgNameFilter", "name", a, Grouper::BeforeLast); + ensure (IT (3)); + ensure (IT (0) == n0); + ensure (IT (1) == n2); + ensure (IT (2) == n3); + ensure (IT (3) == n1); + } +}; diff --git a/adept/tests/libcapture/pkgcache-test.cpp b/adept/tests/libcapture/pkgcache-test.cpp new file mode 100644 index 0000000..662aaed --- /dev/null +++ b/adept/tests/libcapture/pkgcache-test.cpp @@ -0,0 +1,71 @@ +#include <test-util.h> + +#include <libcapture/pkgcache.h> +#include <libcapture/pkgmanager.h> +#include <apt-pkg/configuration.h> +#include <iostream> + +namespace tut { + + using namespace std; + using namespace capture; + + struct pkgcache_shar { + }; + + typedef test_group<pkgcache_shar> tg; + typedef tg::object to; + tg pkgcache_tg ("pkgcache"); + template<> template<> + void to::test<1> () + { + cacheInit (true); + pkgCache::PkgIterator P; + // P = (PkgManager::cache ()) -> FindPkg ("amavis-ng"); + // PkgManager::cache () -> setExtState (P, true, 500); + // PkgManager::cache () -> updateAWanted (true); + P = (PkgManager::cache ()) -> FindPkg ("k3b"); + PkgManager::cache () -> setExtState (P, true, 500); + PkgManager::cache () -> updateAWanted (); + P = (PkgManager::cache ()) -> FindPkg ("kapture"); + PkgManager::cache () -> setExtState (P, true, 500); + PkgManager::cache () -> updateAWanted (); + /* P = (PkgManager::cache ()) -> FindPkg ("apt-listchanges"); + PkgManager::cache () -> setExtState (P, true, 900); + PkgManager::cache () -> updateAWanted (true); + P = (PkgManager::cache ()) -> FindPkg ("exim"); + PkgManager::cache () -> setExtState (P, true, 600); + PkgManager::cache () -> updateAWanted (true); + P = (PkgManager::cache ()) -> FindPkg ("harden"); + PkgManager::cache () -> setExtState (P, true, 700); + PkgManager::cache () -> updateAWanted (true); */ + /* P = (PkgManager::cache ()) -> FindPkg ("rmail"); + PkgManager::cache () -> setExtState (P, true, 200); */ + + // PkgManager::cache () -> updateAWanted (0); + // PkgManager::cache () -> saveExtState ("pkgcache-test.out"); + /* PkgManager::cache () -> updateAWanted (1); + PkgManager::cache () -> saveExtState ("pkgcache-test-1.out"); + PkgManager::cache () -> updateAWanted (2); + PkgManager::cache () -> saveExtState ("pkgcache-test-2.out"); */ + cout << "WANTED PACKAGES:" << endl; + PkgCache::ExtState *s; + for (pkgCache::PkgIterator mP = PkgManager::cache() -> PkgBegin (); ! mP . end (); mP ++) { + s = PkgManager::cache() -> extState (mP); + if (s -> a_wanted_pri > s -> a_unwanted_pri) { + cout << mP . Name () + << ": a_wanted_pri = " << s -> a_wanted_pri + << ", a_unwanted_pri = " << s -> a_unwanted_pri << endl; + } + } + cout << "UNWANTED PACKAGES:" << endl; + for (pkgCache::PkgIterator mP = PkgManager::cache() -> PkgBegin (); ! mP . end (); mP ++) { + s = PkgManager::cache() -> extState (mP); + if (s -> a_unwanted_pri > s -> a_wanted_pri) { + cout << mP . Name () + << ": a_wanted_pri = " << s -> a_wanted_pri + << ", a_unwanted_pri = " << s -> a_unwanted_pri << endl; + } + } + } +} diff --git a/adept/tests/libcapture/stl_util-test.cpp b/adept/tests/libcapture/stl_util-test.cpp new file mode 100644 index 0000000..a083db8 --- /dev/null +++ b/adept/tests/libcapture/stl_util-test.cpp @@ -0,0 +1,56 @@ +#include "stl_util.h" +#include <iostream> +#include <tut.h> + +namespace tut { + + using namespace std; + using namespace capture; + + struct stl_util_shar { + }; + + typedef test_group<stl_util_shar> tg; + typedef tg::object to; + tg stl_util_tg ("stl_util"); + + template<> template<> + void to::test<1> () + { + argmap test; + test["test1"] = "test2"; + test["fjioj @,,ping"] = "jfdiosqj @@,,"; + test[",,"] = "#@@@"; + string out = argmap2string( test ); + argmap test2 = string2argmap( out ); + ensure( test2.size() == 3 ); + ensure( test2["test1"] == "test2" ); + ensure( test2["fjioj @,,ping"] == "jfdiosqj @@,," ); + ensure( test2[",,"] == "#@@@" ); + } + template<> template<> + void to::test<2> () + { + list <string> test; + test . push_back (string ("test, #1")); + test . push_back (string ("test, #2")); + string joinedf2 = join( test, "," ); + test . push_back ( joinedf2 ); + list<string> testret = explode (join (test, ","), ","); + ensure( test.size() == testret.size() ); + list<string>::iterator i, j; + i = test.begin(); + j = testret.begin(); + for ( ; i != test.end(); ++i, ++j ) + ensure( *i == *j ); + + string joinedf3 = join( test, "," ); + test.push_back( joinedf3 ); + string str = join (test, "::"); + testret = explode (str, "::"); + i = test.begin(); + j = testret.begin(); + for ( ; i != test.end(); ++i, ++j ) + ensure( *i == *j ); + } +} diff --git a/adept/tests/libcapture/tree-test.cpp b/adept/tests/libcapture/tree-test.cpp new file mode 100644 index 0000000..0e2f8d5 --- /dev/null +++ b/adept/tests/libcapture/tree-test.cpp @@ -0,0 +1,86 @@ +// #define protected public +// #define private public +#include <libcapture/tree.h> +#include <libcapture/treenode.h> +#include <libcapture/treefactory.h> + +#include <tut.h> + +namespace tut { + + using namespace std; + using namespace capture; + + struct tree_shar { + }; + + typedef test_group<tree_shar> tg; + typedef tg::object to; + tg tree_tg ("tree"); + + class STF: public TreeFactory + { + public: + TreePkgNode *makePkgNode (TreeNode *parent, pkgCache::PkgIterator P) + { return new TreePkgNode (parent, P); } + TreeBranchNode *makeBranchNode (TreeNode *parent, string id, string name) + { return new TreeBranchNode (parent, id, name); } + TreeGroupNode *makeGroupNode (TreeNode *parent, pkgTagSection s) + { return new TreeGroupNode (parent, s); } + TreeBranchNode *makeRoot () { return new TreeBranchNode (0, "ROOT"); } + TreeDepNode *makeDepNode (TreeNode *parent, pkgCache::DepIterator) { return 0; } + TreeVerNode *makeVerNode (TreeNode *parent, pkgCache::VerIterator) { return 0; } + }; + + /* class TestProd: public NodeProducer { + public: + Tree *t; + void getNodes (TreeFactory *f, NodeConsumer *c) + { + TreeNode *a, *b; + a = t -> top (); + // c -> consumeNode (a = f -> makeBNode (t -> top (), "blah1")); + c -> consumeNode (f -> makePkgNode (a, pkgCache::PkgIterator ())); + c -> consumeNode (f -> makePkgNode (a, pkgCache::PkgIterator ())); + c -> consumeNode (f -> makePkgNode (a, pkgCache::PkgIterator ())); + // c -> consumeNode (b = f -> makeBNode (t -> top (), "blah2")); + // c -> consumeNode (f -> makePkg (b, pkgCache::PkgIterator ())); + // c -> consumeNode (f -> makePkg (b, pkgCache::PkgIterator ())); + } + }; */ + template<> template<> + void to::test<1> () + { + TreeFactory *f = new STF; + TestProd *p = new TestProd; + Tree *t = new Tree; + GrouperChain *c = new GrouperChain ("grouperchain"); + c -> addFactory ("EndGrouper", "end"); + t -> setGrouper (c); + t -> setProducer (p); + t -> setTreeFact (f); + p -> t = t; + t -> rebuild (); + + TreeNode *A, *B, *C; + ensure (t -> top ()); + A = t -> top () -> firstChild (); + ensure (A); + B = A -> nextSibling (); + ensure (B); + for (C = B; C -> nextSibling (); C = C -> nextSibling ()); + ensure (C); + ensure (A -> nextSibling () == B); + ensure (B -> nextSibling () == C); + t -> refresh (); + ensure (t -> top ()); + A = t -> top () -> firstChild (); + ensure (A); + B = A -> nextSibling (); + ensure (B); + for (C = B; C -> nextSibling (); C = C -> nextSibling ()); + ensure (C); + ensure (A -> nextSibling () == B); + ensure (B -> nextSibling () == C); + } +}; diff --git a/adept/tests/tut-main.cpp b/adept/tests/tut-main.cpp new file mode 100644 index 0000000..5c278a1 --- /dev/null +++ b/adept/tests/tut-main.cpp @@ -0,0 +1,61 @@ +#include <tut.h> +#include <tut_reporter.h> +#include <iostream> + +namespace tut +{ + test_runner_singleton runner; +} + +int main(int argc,const char* argv[]) +{ + tut::reporter visi; + + if( argc < 2 || argc > 3 ) + { + std::cout << "TUT example test application." << std::endl; + std::cout << "Usage: example [regression] | [list] | [ group] [test]" << std::endl; + std::cout << " List all groups: example list" << std::endl; + std::cout << " Run all tests: example regression" << std::endl; + std::cout << " Run one group: example std::auto_ptr" << std::endl; + std::cout << " Run one test: example std::auto_ptr 3" << std::endl;; + } + + std::cout << "\nFAILURE and EXCEPTION in these tests are FAKE ;)\n\n"; + + tut::runner.get().set_callback(&visi); + + try + { + if( argc == 1 || (argc == 2 && std::string(argv[1]) == "regression") ) + { + tut::runner.get().run_tests(); + } + else if( argc == 2 && std::string(argv[1]) == "list" ) + { + std::cout << "registered test groups:" << std::endl; + tut::groupnames gl = tut::runner.get().list_groups(); + tut::groupnames::const_iterator i = gl.begin(); + tut::groupnames::const_iterator e = gl.end(); + while( i != e ) + { + std::cout << " " << *i << std::endl; + ++i; + } + } + else if( argc == 2 && std::string(argv[1]) != "regression" ) + { + tut::runner.get().run_tests(argv[1]); + } + else if( argc == 3 ) + { + tut::runner.get().run_test(argv[1],::atoi(argv[2])); + } + } + catch( const std::exception& ex ) + { + std::cerr << "tut raised ex: " << ex.what() << std::endl; + } + + return 0; +} diff --git a/adept/tests/tut.h b/adept/tests/tut.h new file mode 100644 index 0000000..dec471a --- /dev/null +++ b/adept/tests/tut.h @@ -0,0 +1,872 @@ +#ifndef TUT_H_GUARD +#define TUT_H_GUARD + +#include <iostream> +#include <map> +#include <vector> +#include <string> +#include <sstream> +#include <stdexcept> +#include <typeinfo> + +#if defined(TUT_USE_SEH) +#include <windows.h> +#include <winbase.h> +#endif + +/** + * Template Unit Tests Framework for C++. + * http://tut.dozen.ru + * + * @author dozen, tut@dozen.ru + */ +namespace tut +{ + /** + * Exception to be throwed when attempted to execute + * missed test by number. + */ + struct no_such_test : public std::logic_error + { + no_such_test() : std::logic_error("no such test"){}; + }; + + /** + * No such test and passed test number is higher than + * any test number in current group. Used in one-by-one + * test running when upper bound is not known. + */ + struct beyond_last_test : public no_such_test + { + beyond_last_test(){}; + }; + + /** + * Group not found exception. + */ + struct no_such_group : public std::logic_error + { + no_such_group(const std::string& grp) : + std::logic_error(grp){}; + }; + + /** + * Internal exception to be throwed when + * no more tests left in group or journal. + */ + struct no_more_tests + { + no_more_tests(){}; + }; + + /** + * Exception to be throwed when ensure() fails or fail() called. + */ + class failure : public std::logic_error + { + public: + failure(const std::string& msg) : std::logic_error(msg){}; + }; + + /** + * Exception to be throwed when test desctructor throwed an exception. + */ + class warning : public std::logic_error + { + public: + warning(const std::string& msg) : std::logic_error(msg){}; + }; + + /** + * Exception to be throwed when test issued SEH (Win32) + */ + class seh : public std::logic_error + { + public: + seh(const std::string& msg) : std::logic_error(msg){}; + }; + + /** + * Return type of runned test/test group. + * + * For test: contains result of test and, possible, message + * for failure or exception. + */ + struct test_result + { + /** + * Test group name. + */ + std::string group; + + /** + * Test number in group. + */ + int test; + + /** + * ok - test finished successfully + * fail - test failed with ensure() or fail() methods + * ex - test throwed an exceptions + * warn - test finished successfully, but test destructor throwed + * term - test forced test application to terminate abnormally + */ + typedef enum { ok, fail, ex, warn, term } result_type; + result_type result; + + /** + * Exception message for failed test. + */ + std::string message; + std::string exception_typeid; + + /** + * Default constructor. + */ + test_result() + : test(0),result(ok) + { + } + + /** + * Constructor. + */ + test_result( const std::string& grp,int pos,result_type res) + : group(grp),test(pos),result(res) + { + } + + /** + * Constructor with exception. + */ + test_result( const std::string& grp,int pos, + result_type res, + const std::exception& ex) + : group(grp),test(pos),result(res), + message(ex.what()),exception_typeid(typeid(ex).name()) + { + } + }; + + /** + * Interface. + * Test group operations. + */ + struct group_base + { + virtual ~group_base(){}; + + // execute tests iteratively + virtual void rewind() = 0; + virtual test_result run_next() = 0; + + // execute one test + virtual test_result run_test(int n) = 0; + }; + + /** + * Test runner callback interface. + * Can be implemented by caller to update + * tests results in real-time. User can implement + * any of callback methods, and leave unused + * in default implementation. + */ + struct callback + { + /** + * Virtual destructor is a must for subclassed types. + */ + virtual ~callback(){}; + + /** + * Called when new test run started. + */ + virtual void run_started(){}; + + /** + * Called when a test finished. + * @param tr Test results. + */ + virtual void test_completed(const test_result& /*tr*/){}; + + /** + * Called when all tests in run completed. + */ + virtual void run_completed(){}; + }; + + /** + * Typedef for runner::list_groups() + */ + typedef std::vector<std::string> groupnames; + + /** + * Test runner. + */ + class test_runner + { + protected: + typedef std::map<std::string,group_base*> groups; + typedef groups::iterator iterator; + typedef groups::const_iterator const_iterator; + groups groups_; + + callback default_callback_; + callback* callback_; + + public: + /** + * Constructor + */ + test_runner() : callback_(&default_callback_) + { + } + + /** + * Stores another group for getting by name. + */ + void register_group(const std::string& name,group_base* gr) + { + if( gr == 0 ) + { + throw std::invalid_argument("group shall be non-null"); + } + + groups::iterator found = groups_.find(name); + if( found != groups_.end() ) + { + std::string msg("attempt to add already existent group "+name); + // this exception terminates application so we use cerr also + std::cerr << msg << std::endl; + throw std::logic_error(msg); + } + + groups_[name] = gr; + } + + /** + * Stores callback object. + */ + void set_callback(callback* cb) + { + callback_ = cb==0? &default_callback_:cb; + } + + /** + * Returns callback object. + */ + callback& get_callback() const + { + return *callback_; + } + + /** + * Returns list of known test groups. + */ + const groupnames list_groups() const + { + groupnames ret; + const_iterator i = groups_.begin(); + const_iterator e = groups_.end(); + while( i != e ) + { + ret.push_back(i->first); + ++i; + } + return ret; + } + + /** + * Runs all tests in all groups. + * @param callback Callback object if exists; null otherwise + */ + void run_tests() const + { + callback_->run_started(); + + const_iterator i = groups_.begin(); + const_iterator e = groups_.end(); + while( i != e ) + { + try + { + // iterate all tests + i->second->rewind(); + for( ;; ) + { + test_result tr = i->second->run_next(); + callback_->test_completed(tr); + } + } + catch( const no_more_tests& ) + { + // ok + } + + ++i; + } + + callback_->run_completed(); + } + + /** + * Runs all tests in specified group. + */ + void run_tests(const std::string& group_name) const + { + callback_->run_started(); + + const_iterator i = groups_.find(group_name); + if( i == groups_.end() ) + { + throw no_such_group(group_name); + } + + try + { + // iterate all tests + i->second->rewind(); + for(;;) + { + test_result tr = i->second->run_next(); + callback_->test_completed(tr); + } + } + catch( const no_more_tests& ) + { + // ok + } + + callback_->run_completed(); + } + + /** + * Runs one test in specified group. + */ + test_result run_test(const std::string& group_name,int n) const + { + callback_->run_started(); + + const_iterator i = groups_.find(group_name); + if( i == groups_.end() ) + { + throw no_such_group(group_name); + } + + try + { + test_result tr = i->second->run_test(n); + callback_->test_completed(tr); + callback_->run_completed(); + return tr; + } + catch( const beyond_last_test& ) + { + callback_->run_completed(); + throw; + } + catch( const no_such_test& ) + { + callback_->run_completed(); + throw; + } + } + }; + + /** + * Singleton for test_runner implementation. + * Instance with name runner_singleton shall be implemented + * by user. + */ + class test_runner_singleton + { + public: + static test_runner& get() + { + static test_runner tr; + return tr; + } + }; + extern test_runner_singleton runner; + + /** + * Test object. Contains data test run upon and default test method + * implementation. Inherited from Data to allow tests to + * access test data as members. + */ + template <class Data> + class test_object : public Data + { + public: + /** + * Default constructor + */ + test_object(){}; + + /** + * The flag is set to true by default (dummy) test. + * Used to detect usused test numbers and avoid unnecessary + * test object creation which may be time-consuming depending + * on operations described in Data::Data() and Data::~Data(). + * TODO: replace with throwing special exception from default test. + */ + bool called_method_was_a_dummy_test_; + + /** + * Default do-nothing test. + */ + template <int n> + void test() + { + called_method_was_a_dummy_test_ = true; + } + }; + + namespace + { + /** + * Tests provided condition. + * Throws if false. + */ + void ensure(bool cond) + { + if( !cond ) throw failure(""); + } + + /** + * Tests provided condition. + * Throws if false. + */ + void ensure(const char* msg,bool cond) + { + if( !cond ) throw failure(msg); + } + + /** + * Tests two objects for being equal. + * Throws if false. + * + * NB: both T and Q must have operator << defined somewhere, or + * client code will not compile at all! + */ + template <class T,class Q> + void ensure_equals(const char* msg,const Q& actual,const T& expected) + { + if( expected != actual ) + { + std::stringstream ss; + ss << (msg?msg:"") << (msg?": ":"") << "expected " << expected << " actual " << actual; + throw failure(ss.str().c_str()); + } + } + + template <class T,class Q> + void ensure_equals(const Q& actual,const T& expected) + { + ensure_equals<>(0,actual,expected); + } + + /** + * Tests two objects for being at most in given distance one from another. + * Borders are excluded. + * Throws if false. + * + * NB: T must have operator << defined somewhere, or + * client code will not compile at all! Also, T shall have + * operators + and -, and be comparable. + */ + template <class T> + void ensure_distance(const char* msg,const T& actual,const T& expected,const T& distance) + { + if( expected-distance >= actual || expected+distance <= actual ) + { + std::stringstream ss; + ss << (msg?msg:"") << (msg?": ":"") << "expected [" << expected-distance << ";" + << expected+distance << "] actual " << actual; + throw failure(ss.str().c_str()); + } + } + + template <class T> + void ensure_distance(const T& actual,const T& expected,const T& distance) + { + ensure_distance<>(0,actual,expected,distance); + } + + /** + * Unconditionally fails with message. + */ + void fail(const char* msg="") + { + throw failure(msg); + } + } + + /** + * Walks through test tree and stores address of each + * test method in group. Instantiation stops at 0. + */ + template <class Test,class Group,int n> + struct tests_registerer + { + static void reg(Group& group) + { + group.reg(n,&Test::template test<n>); + tests_registerer<Test,Group,n-1>::reg(group); + } + }; + + template<class Test,class Group> + struct tests_registerer<Test,Group,0> + { + static void reg(Group&){}; + }; + + /** + * Test group; used to recreate test object instance for + * each new test since we have to have reinitialized + * Data base class. + */ + template <class Data,int MaxTestsInGroup = 50> + class test_group : public group_base + { + const char* name_; + + typedef void (test_object<Data>::*testmethod)(); + typedef std::map<int,testmethod> tests; + typedef typename tests::iterator tests_iterator; + typedef typename tests::const_iterator tests_const_iterator; + typedef typename tests::const_reverse_iterator + tests_const_reverse_iterator; + typedef typename tests::size_type size_type; + + tests tests_; + tests_iterator current_test_; + + /** + * Exception-in-destructor-safe smart-pointer class. + */ + template <class T> + class safe_holder + { + T* p_; + bool permit_throw_in_dtor; + + safe_holder(const safe_holder&); + safe_holder& operator = (const safe_holder&); + + public: + safe_holder() : p_(0),permit_throw_in_dtor(false) + { + } + + ~safe_holder() + { + release(); + } + + T* operator -> () const { return p_; }; + T* get() const { return p_; }; + + /** + * Tell ptr it can throw from destructor. Right way is to + * use std::uncaught_exception(), but some compilers lack + * correct implementation of the function. + */ + void permit_throw(){ permit_throw_in_dtor = true; } + + /** + * Specially treats exceptions in test object destructor; + * if test itself failed, exceptions in destructor + * are ignored; if test was successful and destructor failed, + * warning exception throwed. + */ + void release() + { + try + { + if( delete_obj() == false ) + { + throw warning("destructor of test object raised an SEH exception"); + } + } + catch( const std::exception& ex ) + { + if( permit_throw_in_dtor ) + { + std::string msg = "destructor of test object raised exception: "; + msg += ex.what(); + throw warning(msg); + } + } + catch( ... ) + { + if( permit_throw_in_dtor ) + { + throw warning("destructor of test object raised an exception"); + } + } + } + + /** + * Re-init holder to get brand new object. + */ + void reset() + { + release(); + permit_throw_in_dtor = false; + p_ = new T(); + } + + bool delete_obj() + { +#if defined(TUT_USE_SEH) + __try + { +#endif + T* p = p_; + p_ = 0; + delete p; +#if defined(TUT_USE_SEH) + } + __except(handle_seh_(::GetExceptionCode())) + { + if( permit_throw_in_dtor ) + { + return false; + } + } +#endif + return true; + } + }; + + public: + typedef test_object<Data> object; + + /** + * Creates and registers test group with specified name. + */ + test_group(const char* name) + : name_(name) + { + // register itself + runner.get().register_group(name_,this); + + // register all tests + tests_registerer<object,test_group,MaxTestsInGroup>::reg(*this); + }; + + /** + * This constructor is used in self-test run only. + */ + test_group(const char* name,test_runner& another_runner) + : name_(name) + { + // register itself + another_runner.register_group(name_,this); + + // register all tests + tests_registerer<test_object<Data>, + test_group,MaxTestsInGroup>::reg(*this); + }; + + /** + * Registers test method under given number. + */ + void reg(int n,testmethod tm) + { + tests_[n] = tm; + } + + /** + * Reset test position before first test. + */ + void rewind() + { + current_test_ = tests_.begin(); + } + + /** + * Runs next test. + */ + test_result run_next() + { + if( current_test_ == tests_.end() ) + { + throw no_more_tests(); + } + + // find next user-specialized test + safe_holder<object> obj; + while( current_test_ != tests_.end() ) + { + try + { + return run_test_(current_test_++,obj); + } + catch( const no_such_test& ) + { + continue; + } + } + + throw no_more_tests(); + } + + /** + * Runs one test by position. + */ + test_result run_test(int n) + { + // beyond tests is special case to discover upper limit + if( tests_.rbegin() == tests_.rend() ) throw beyond_last_test(); + if( tests_.rbegin()->first < n ) throw beyond_last_test(); + + // withing scope; check if given test exists + tests_iterator ti = tests_.find(n); + if( ti == tests_.end() ) throw no_such_test(); + + safe_holder<object> obj; + return run_test_(ti,obj); + } + + private: + /** + * VC allows only one exception handling type per function, + * so I have to split the method + */ + test_result run_test_(const tests_iterator& ti,safe_holder<object>& obj) + { + try + { + if( run_test_seh_(ti->second,obj) == false ) + throw seh("seh"); + } + catch(const no_such_test&) + { + throw; + } + catch(const warning& ex) + { + // test ok, but destructor failed + test_result tr(name_,ti->first,test_result::warn,ex); + return tr; + } + catch(const failure& ex) + { + // test failed because of ensure() or similar method + test_result tr(name_,ti->first,test_result::fail,ex); + return tr; + } + catch(const seh& ex) + { + // test failed with sigsegv, divide by zero, etc + test_result tr(name_,ti->first,test_result::term,ex); + return tr; + } + catch(const std::exception& ex) + { + // test failed with std::exception + test_result tr(name_,ti->first,test_result::ex,ex); + return tr; + } + catch(...) + { + // test failed with unknown exception + test_result tr(name_,ti->first,test_result::ex); + return tr; + } + + // test passed + test_result tr(name_,ti->first,test_result::ok); + return tr; + } + + /** + * Runs one under SEH if platform supports it. + */ + bool run_test_seh_(testmethod tm,safe_holder<object>& obj) + { +#if defined(TUT_USE_SEH) + __try + { +#endif + if( obj.get() == 0 ) obj.reset(); + obj->called_method_was_a_dummy_test_ = false; + +#if defined(TUT_USE_SEH) + __try + { +#endif + (obj.get()->*tm)(); +#if defined(TUT_USE_SEH) + } + __except(handle_seh_(::GetExceptionCode())) + { + // throw seh("SEH"); + return false; + } +#endif + + if( obj->called_method_was_a_dummy_test_ ) + { + // do not call obj.release(); reuse object + throw no_such_test(); + } + + obj.permit_throw(); + obj.release(); +#if defined(TUT_USE_SEH) + } + __except(handle_seh_(::GetExceptionCode())) + { + // throw seh("SEH"); + return false; + } +#endif + return true; + } + }; + + +#if defined(TUT_USE_SEH) + /** + * Decides should we execute handler or ignore SE. + */ + inline int handle_seh_(DWORD excode) + { + switch(excode) + { + case EXCEPTION_ACCESS_VIOLATION: + case EXCEPTION_DATATYPE_MISALIGNMENT: + case EXCEPTION_BREAKPOINT: + case EXCEPTION_SINGLE_STEP: + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + case EXCEPTION_FLT_DENORMAL_OPERAND: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_INEXACT_RESULT: + case EXCEPTION_FLT_INVALID_OPERATION: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_STACK_CHECK: + case EXCEPTION_FLT_UNDERFLOW: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_OVERFLOW: + case EXCEPTION_PRIV_INSTRUCTION: + case EXCEPTION_IN_PAGE_ERROR: + case EXCEPTION_ILLEGAL_INSTRUCTION: + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + case EXCEPTION_STACK_OVERFLOW: + case EXCEPTION_INVALID_DISPOSITION: + case EXCEPTION_GUARD_PAGE: + case EXCEPTION_INVALID_HANDLE: + return EXCEPTION_EXECUTE_HANDLER; + }; + + return EXCEPTION_CONTINUE_SEARCH; + } +#endif +} + +#endif + diff --git a/adept/tests/tut_reporter.h b/adept/tests/tut_reporter.h new file mode 100644 index 0000000..941d653 --- /dev/null +++ b/adept/tests/tut_reporter.h @@ -0,0 +1,182 @@ +#ifndef TUT_REPORTER +#define TUT_REPORTER + +#include <tut.h> + +/** + * Template Unit Tests Framework for C++. + * http://tut.dozen.ru + * + * @author dozen, tut@dozen.ru + */ +namespace +{ + std::ostream& operator << (std::ostream& os,const tut::test_result& tr) + { + switch(tr.result) + { + case tut::test_result::ok: + os << '.'; + break; + + case tut::test_result::fail: + os << '[' << tr.test << "=F]"; + break; + + case tut::test_result::ex: + os << '[' << tr.test << "=X]"; + break; + + case tut::test_result::warn: + os << '[' << tr.test << "=W]"; + break; + + case tut::test_result::term: + os << '[' << tr.test << "=T]"; + break; + } + + return os; + } +} + +namespace tut +{ + /** + * Default TUT callback handler. + */ + class reporter : public tut::callback + { + std::string current_group; + typedef std::vector<tut::test_result> not_passed_list; + not_passed_list not_passed; + std::ostream& os; + + public: + int ok_count; + int exceptions_count; + int failures_count; + int terminations_count; + int warnings_count; + + reporter() : os(std::cout) + { + init(); + } + + reporter(std::ostream& out) : os(out) + { + init(); + } + + void run_started() + { + init(); + } + + void test_completed(const tut::test_result& tr) + { + if( tr.group != current_group ) + { + os << std::endl << tr.group << ": " << std::flush; + current_group = tr.group; + } + + os << tr << std::flush; + if( tr.result == tut::test_result::ok ) ok_count++; + else if( tr.result == tut::test_result::ex ) exceptions_count++; + else if( tr.result == tut::test_result::fail ) failures_count++; + else if( tr.result == tut::test_result::warn ) warnings_count++; + else terminations_count++; + + if( tr.result != tut::test_result::ok ) + { + not_passed.push_back(tr); + } + } + + void run_completed() + { + os << std::endl; + + if( not_passed.size() > 0 ) + { + not_passed_list::const_iterator i = not_passed.begin(); + while( i != not_passed.end() ) + { + tut::test_result tr = *i; + + os << std::endl; + + os << "---> " << "test: " << tr.group << ", test<" << tr.test << ">" << std::endl; + + os << " problem: "; + switch(tr.result) + { + case test_result::fail: + os << "assertion failed" << std::endl; + break; + case test_result::ex: + os << "unexpected exception" << std::endl; + if( tr.exception_typeid != "" ) + { + os << " exception typeid: " + << tr.exception_typeid << std::endl; + } + break; + case test_result::term: + os << "would be terminated" << std::endl; + break; + case test_result::warn: + os << "test passed, but cleanup code (destructor) raised an exception" << std::endl; + break; + default: break; + } + + if( tr.message != "" ) + { + if( tr.result == test_result::fail ) + { + os << " failed assertion: \"" << tr.message << "\"" << std::endl; + } + else + { + os << " message: \"" << tr.message << "\"" << std::endl; + } + } + + ++i; + } + } + + os << std::endl; + + os << "tests summary:"; + if( terminations_count > 0 ) os << " terminations:" << terminations_count; + if( exceptions_count > 0 ) os << " exceptions:" << exceptions_count; + if( failures_count > 0 ) os << " failures:" << failures_count; + if( warnings_count > 0 ) os << " warnings:" << warnings_count; + os << " ok:" << ok_count; + os << std::endl; + } + + bool all_ok() const + { + return not_passed.size() == 0; + } + + private: + void init() + { + ok_count = 0; + exceptions_count = 0; + failures_count = 0; + terminations_count = 0; + warnings_count = 0; + + not_passed.clear(); + } + }; +}; + +#endif diff --git a/adept/updater/Makefile.am b/adept/updater/Makefile.am new file mode 100644 index 0000000..83afaae --- /dev/null +++ b/adept/updater/Makefile.am @@ -0,0 +1,21 @@ + +bin_PROGRAMS = adept_updater +noinst_HEADERS = app.h +adept_updater_SOURCES = main.cpp app.cpp +adept_updater_LDADD = ../adept/libadept.la $(LIBAPT_FRONT_LIBS) $(LIBEPT_LIBS) $(LIBTAGCOLL2_LIBS) $(LIBWIBBLE_LIBS) $(LIB_KIO) $(LIBKDE_UI) ../kubuntu_upgrader/libkubuntuupgradewizard.la +adept_updater_LDFLAGS = -L/usr/lib/debug +INCLUDES = $(all_includes) $(LIBAPT_FRONT_CFLAGS) $(LIBEPT_CFLAGS) $(LIBTAGCOLL2_CFLAGS) $(LIBWIBBLE_CFLAGS) -I$(srcdir)/.. -I.. +KDE_CXXFLAGS = $(USE_EXCEPTIONS) -DQT_NO_ASCII_CAST -DQT_NO_CAST_ASCII +METASOURCES = AUTO +KDE_ICON = AUTO + +rcdir = $(kde_datadir)/adept_updater +rc_DATA = adept_updaterui.rc + +#shelldesktopdir = $(kde_appsdir)/System +xdg_apps_DATA = adept_updater.desktop + +messages: rc.cpp + $(EXTRACTRC) `find . -name \*.ui -o -name \*.rc` > rc.cpp + $(EXTRACTRC) `find . -name "*.rc"` >> rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/adept_updater.pot diff --git a/adept/updater/adept_updater.desktop b/adept/updater/adept_updater.desktop new file mode 100644 index 0000000..8dae4d6 --- /dev/null +++ b/adept/updater/adept_updater.desktop @@ -0,0 +1,69 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Adept Updater +Name[bg]=Обновяване на Adept +Name[ca]=Actualitzador Adept +Name[da]=Adept-opdatering +Name[el]=Ανανεωτής Adept +Name[es]=Actualizador experto +Name[et]=Adepti uuendaja +Name[fr]=Mise à jour Adept +Name[ga]=Nuashonróir Adept +Name[gl]=Actualizador de Adept +Name[it]=Aggiornamento Adept +Name[ka]=Adept განმაახლებელი +Name[lt]=Adept atnaujinimai +Name[pt]=Actualizador do Adept +Name[sk]=Adept aktualizácia +Name[sv]=Adept-uppdaterare +Name[xx]=xxAdept Updaterxx +GenericName=System Update Wizard +GenericName[bg]=Обновяване на Adept +GenericName[ca]=Assistent d'actualització del sistema +GenericName[cs]=Průvodce aktualizací systému +GenericName[da]=Systemopdateringsguide +GenericName[de]=Systemaktualisierungsassistent +GenericName[el]=Μάγος ενημέρωσης συστήματος +GenericName[es]=Asistente de actualización del sistema +GenericName[et]=Süsteemi uuendamine nõustaja +GenericName[fr]=Assistant de mise à jour du système +GenericName[gl]=Asistente de Actualizazón do Sistema +GenericName[it]=Procedura guidata aggiornamento sistema +GenericName[ja]=システムアップデートウィザード +GenericName[ka]=სისტემის განახლების ოსტატი +GenericName[lt]=Sistemos atnaujinimo vediklis +GenericName[nl]=Systeem-update-assistent +GenericName[pt]=Assistente de Actualização do Sistema +GenericName[sk]=Sprievodca systémovou aktualizáciou +GenericName[sv]=Systemuppdateringsguide +GenericName[xx]=xxSystem Update Wizardxx +Exec=/opt/kde3/bin/adept_updater +Categories=Qt;KDE;System; +Icon=adept_updater +Type=Application +X-KDE-SubstituteUID=true +Comment=Update installed software +Comment[bg]=Обновяване на инсталиран софтуер +Comment[ca]=Actualitza el programari instal·lat +Comment[cs]=Aktualizace nainstalovaného softwaru +Comment[da]=Opdatér installeret programmel +Comment[de]=Aktualisiert installierte Software +Comment[el]=Ενημέρωση εγκατεστημένου λογισμικού +Comment[es]=Actualizar el software instalado +Comment[et]=Paigaldatud tarkvara uuendamine +Comment[fr]=Mise à jour des logiciels installés +Comment[ga]=Nuashonraigh bogearraí suiteáilte +Comment[gl]=Actualiza o software instalado +Comment[it]=Aggiorna il software installato +Comment[ja]=インストール済みのソフトウェアをアップデート +Comment[ka]=დაყენებული პროგრამების განახლება +Comment[lt]=Įdiegtų programų atnaujinimas +Comment[nl]=Geïnstalleerde software bijwerken +Comment[pt]=Actualiza o 'software' instalado +Comment[sk]=Aktualizácia inštalovaného softwaru +Comment[sr]=Ажурира инсталиране програме +Comment[sr@Latn]=Ažurira instalirane programe +Comment[sv]=Uppdatera installerad programvara +Comment[xx]=xxUpdate installed softwarexx +Terminal=false +NoDisplay=true diff --git a/adept/updater/adept_updaterui.rc b/adept/updater/adept_updaterui.rc new file mode 100644 index 0000000..083b9e8 --- /dev/null +++ b/adept/updater/adept_updaterui.rc @@ -0,0 +1,16 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="6" name="adept-updater"> + <MenuBar> + <Menu name="file" noMerge="1"> + <text>&Adept</text> + <Action name="file_quit" /> + </Menu> + <Menu name="edit" noMerge="1"> + <text>&Edit</text> + <Action name="edit_undo" /> + <Action name="edit_redo" /> + </Menu> + </MenuBar> + <ToolBar name="mainToolBar" noMerge="1"> + </ToolBar> +</kpartgui> diff --git a/adept/updater/app.cpp b/adept/updater/app.cpp new file mode 100644 index 0000000..c16424b --- /dev/null +++ b/adept/updater/app.cpp @@ -0,0 +1,275 @@ +#define KUBUNTU + +#include <qvbox.h> +#include <qlabel.h> +#include <qsplitter.h> +#include <qtimer.h> +#include <qwidgetstack.h> + +#include <kpushbutton.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kaction.h> +#include <kactionclasses.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kparts/part.h> +#include <ktrader.h> +#include <klibloader.h> +#include <kstatusbar.h> + +#include <apt-pkg/packagemanager.h> +#include <apt-front/manager.h> +#include <apt-front/init.h> +#include <apt-front/cache/entity/package.h> +#include <apt-front/cache/component/state.h> +#include <apt-front/cache/component/history.h> +#include <apt-front/predicate/factory.h> + +#include <adept/acqprogresswidget.h> +#include <adept/progress.h> +#include <adept/utils.h> + +#ifdef KUBUNTU +#include <kubuntu_upgrader/upgradewizard.h> +#endif + +#include "app.h" + +using namespace aptFront; +using namespace aptFront::cache; +using namespace adept; + +void WaitForLister::waiting() +{ + kdDebug() << "WaitForLister::waiting()" << endl; + if (app->m_list->searchView()->lister()->busy()) + QTimer::singleShot( 100, this, SLOT( waiting() ) ); + else { + QTimer::singleShot( 0, app, slot ); + deleteLater(); + } +} + +TestApp::TestApp() +{ + m_all = new QVBox( this ); + m_stack = new QWidgetStack( m_all ); + + m_stack->addWidget( m_loading = new QLabel( i18n( "Loading, please wait..." ), m_stack ) ); + m_loading->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter ); + + m_buttons = new QHBox( m_all ); + QLabel *space = new QLabel( m_buttons ); // spacing + m_next = new KPushButton( i18n( "Next" ), m_buttons ); + m_quit = new KPushButton( i18n( "Quit" ), m_buttons ); + m_next->setEnabled( false ); + m_quit->setEnabled( false ); + + m_buttons->setSpacing( 2 ); + m_buttons->setMargin( 2 ); + QSizePolicy buttons( QSizePolicy::Preferred, QSizePolicy::Fixed, false ); + m_buttons->setSizePolicy( buttons ); + m_next->setSizePolicy( buttons ); + m_quit->setSizePolicy( buttons ); + space->setSizePolicy( QSizePolicy( + QSizePolicy::Expanding, + QSizePolicy::Fixed, false ) ); + + setStandardToolBarMenuEnabled( false ); + createStandardStatusBarAction(); + setupActions(); + setupGUI( Keys|StatusBar|Save|Create ); + delete toolBar(); + + Application::setStatusBar( statusBar() ); + + QTimer::singleShot( + 0, this, + SLOT( delayed() ) ); + + setCentralWidget( m_all ); + setMinimumSize( 400, 300 ); +} + +void TestApp::delayed() +{ + initialize(); + observeComponent< component::State >(); + + m_stack->addWidget( m_list = new adept::Browser( m_stack ) ); + m_stack->addWidget( m_bye = new QLabel( i18n( "Update Complete" ), + m_stack ) ); + m_stack->addWidget( m_start = new QLabel( i18n( "Welcome to Adept Updater" ), + m_stack ) ); + m_bye->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter ); + m_start->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter ); + + m_list->searchView()->setUpgradeMode(); + + m_stack->addWidget( m_progress = new adept::AcqProgressWidget( m_stack ) ); + m_stack->addWidget( m_commitProgress = new CommitProgress( m_stack ) ); + + m_stack->raiseWidget( m_start ); + + statusBar()->clear(); + notifyPostChange(0); + start(); +} + +void TestApp::setupActions() +{ + KStdAction::quit( kapp, SLOT( quit() ), actionCollection() ); + m_undo = KStdAction::undo( this, SLOT( undo() ), actionCollection() ); + m_redo = KStdAction::redo( this, SLOT( redo() ), actionCollection() ); + setHistoryEnabled( false ); + createStandardStatusBarAction(); +} + +void TestApp::setHistoryEnabled( bool e ) { + if (e && history() ) { + m_undo->setEnabled( history()->canUndo() ); + m_redo->setEnabled( history()->canRedo() ); + } else { + m_undo->setEnabled( false ); + m_redo->setEnabled( false ); + } +} + +void TestApp::notifyPreChange( component::Base *b ) +{ + Application::notifyPreChange( b ); + checkpoint(); +} + +void TestApp::notifyPostChange( component::Base *b ) +{ + Application::notifyPostChange( b ); + m_list->searchView()->lister()->scheduleRebuild(); // rebuild on change... +} + +void TestApp::setNext( QString s, const char *slot, QString q, const char *quits ) { + disconnect( m_next, SIGNAL( clicked() ), 0, 0 ); + m_next->setText( s ); + m_next->setEnabled( slot ); + if ( slot ) + connect( m_next, SIGNAL( clicked() ), this, slot ); + + disconnect( m_quit, SIGNAL( clicked() ), 0, 0 ); + m_quit->setEnabled( quits ); + m_quit->setText( q ); + if ( quits ) + connect( m_quit, SIGNAL( clicked() ), this, quits ); +} + +void TestApp::disableNext() { + setNext( i18n( "Next" ), 0 ); +} + +void TestApp::disableButtons() { + disableNext(); + m_quit->setEnabled( false ); +} + +void TestApp::start() { +// disableNext(); + update(); +// setNext( i18n( "Fetch List of Updates" ), SLOT( update() ), +// i18n( "Skip Fetching List" ), SLOT( postUpdate() ) ); +} + +void TestApp::update() { + kdDebug() << "TestApp::update" << endl; + disableButtons(); + + aptFront::Manager m; + m.setProgressCallback( m_progress->callback() ); + m.setUpdateInterval( 100000 ); + kdDebug() << "manager set up" << endl; + try { + m_stack->raiseWidget( m_progress ); + m.update(); + } catch ( exception::OperationCancelled ) { + } catch ( ... ) { + KMessageBox::sorry( + this, i18n( "There was an error downloading updates. " ), + i18n( "Could not fetch updates" ) ); + } + postUpdate(); +} + +void TestApp::postUpdate() { + cache::Global::get().state().distUpgrade(); + if ( cache::Global::get().state().upgradableCount() > 0 ) { + m_list->searchView()->lister()->scheduleRebuild(); + m_stack->raiseWidget( m_list ); + setHistoryEnabled( true ); + setNext( i18n( "Apply Updates" ), SLOT( commit() ) ); + } else { + m_bye->setText( i18n( "Nothing to Update" ) ); + m_stack->raiseWidget( m_bye ); + disableNext(); + // setNext( i18n( "Nothing to do, Quit" ), SLOT( close() ) ); + m_quit->setText( i18n( "Quit" ) ); + m_quit->setEnabled( true ); +#ifdef KUBUNTU + wizard = new UpgradeWizard(this, 0, 1); + if( wizard->checkForDistUpgrade() ) { + m_bye->setText(i18n("A new distribution version is available! Click next if you wish to upgrade now.")); //FIXME improve text + setNext( i18n( "Version Upgrade" ), SLOT( releaseUpgrade() ) ); + } else { + wizard->close(); + } +#endif + } +} + +void TestApp::commit() { + kdDebug() << "TestApp::commit" << endl; + disableButtons(); + setHistoryEnabled( false ); + if (m_list->searchView()->lister()->busy()) { + new WaitForLister( this, SLOT( commit() ) ); + return; + } + + aptFront::Manager m; + m.setProgressCallback( m_progress->callback() ); + m.setUpdateInterval( 100000 ); + try { + m_stack->raiseWidget( m_progress ); + m.download(); + m_stack->raiseWidget( m_commitProgress ); + m.commit(); + } catch ( exception::OperationCancelled ) { + } catch ( ... ) { + KMessageBox::sorry( + this, i18n( "There was an error commiting changes. " + "Possibly there was a problem downloading some " + "packages or the commit would break packages. " ), + i18n( "Could not commit changes" ) ); + } + + m_stack->raiseWidget( m_bye ); + disableNext(); +#ifdef KUBUNTU + wizard = new UpgradeWizard(this, 0, 1); + if( wizard->checkForDistUpgrade() ) { + m_bye->setText(i18n("A new distribution version is available! Click next if you wish to upgrade now.")); //FIXME improve text + setNext( i18n( "Version Upgrade" ), SLOT( releaseUpgrade() ) ); + } else { + wizard->close(); + } +#endif + m_quit->setText( i18n( "Quit" ) ); + m_quit->setEnabled( true ); + notifyPostChange( 0 ); +} + +#ifdef KUBUNTU +void TestApp::releaseUpgrade() { + wizard->show(); +} +#endif + +#include "app.moc" diff --git a/adept/updater/app.h b/adept/updater/app.h new file mode 100644 index 0000000..a51986c --- /dev/null +++ b/adept/updater/app.h @@ -0,0 +1,105 @@ +/* -*- C++ -*- */ +#ifndef TESTUI_APP_H +#define TESTUI_APP_H + +#define KUBUNTU + +#include <kmainwindow.h> +#include <kparts/part.h> +#include <kactionclasses.h> +#include <apt-front/cache/observer.h> +#include <apt-front/cache/component/state.h> +#include <apt-front/cache/component/history.h> +#include <adept/view.h> +#include <adept/commitprogress.h> +#include <adept/application.h> + +#ifdef KUBUNTU +#include <kubuntu_upgrader/upgradewizard.h> +#endif + +class QVBox; +class QWidgetStack; +class QSplitter; +class KAction; +class KPushButton; +namespace adept { +class AcqProgressWidget; +} + +using namespace aptFront; +using namespace adept; + +class TestApp : public KMainWindow, Application { + Q_OBJECT +public: + void setupActions(); + ExtTerminalInterface *terminal(); + TestApp(); +protected slots: + void start(); + void update(); + void postUpdate(); + void commit(); + + void delayed(); + + void undo() { Application::undo(); } + void redo() { Application::redo(); } + void checkpoint() { Application::checkpoint(); } + + void setHistoryEnabled( bool ); + + void disableNext(); + void disableButtons(); + void setNext( QString str, const char *slot, + QString qstr = i18n( "Forget Changes and Quit" ), + const char *qslot = SLOT( close() ) ); +#ifdef KUBUNTU + void releaseUpgrade(); +#endif +protected: + friend class WaitForLister; + + virtual void notifyPostChange( cache::component::Base * ); + virtual void notifyPreChange( cache::component::Base * ); + + QWidgetStack *m_stack; + QVBox *m_all; + QHBox *m_buttons; + QLabel *m_start, *m_bye, *m_loading; + KPushButton *m_next, *m_quit; + + // stacked widgets + adept::AcqProgressWidget *m_progress; + adept::CommitProgress *m_commitProgress; + adept::Browser *m_list; + + // other stuff + std::vector<KAction *> m_actions; + QMap< QString, QString > m_icons; + KAction *m_undo, *m_redo; + cache::component::History< cache::component::State > *m_history; + +#ifdef KUBUNTU + UpgradeWizard* wizard; +#endif +}; + +class WaitForLister : public QObject { + Q_OBJECT +public: + WaitForLister( TestApp *a, const char *s ) + : app( a ), slot( s ) + { + waiting(); + } +protected slots: + void waiting(); +protected: + TestApp *app; + const char *slot; + +}; + +#endif diff --git a/adept/updater/hi128-app-adept_updater.png b/adept/updater/hi128-app-adept_updater.png Binary files differnew file mode 100644 index 0000000..a68965f --- /dev/null +++ b/adept/updater/hi128-app-adept_updater.png diff --git a/adept/updater/hi16-app-adept_updater.png b/adept/updater/hi16-app-adept_updater.png Binary files differnew file mode 100644 index 0000000..4952024 --- /dev/null +++ b/adept/updater/hi16-app-adept_updater.png diff --git a/adept/updater/hi22-app-adept_updater.png b/adept/updater/hi22-app-adept_updater.png Binary files differnew file mode 100644 index 0000000..3b3880c --- /dev/null +++ b/adept/updater/hi22-app-adept_updater.png diff --git a/adept/updater/hi32-app-adept_updater.png b/adept/updater/hi32-app-adept_updater.png Binary files differnew file mode 100644 index 0000000..ee196a8 --- /dev/null +++ b/adept/updater/hi32-app-adept_updater.png diff --git a/adept/updater/hi48-app-adept_updater.png b/adept/updater/hi48-app-adept_updater.png Binary files differnew file mode 100644 index 0000000..5abac9b --- /dev/null +++ b/adept/updater/hi48-app-adept_updater.png diff --git a/adept/updater/hi64-app-adept_updater.png b/adept/updater/hi64-app-adept_updater.png Binary files differnew file mode 100644 index 0000000..20766d9 --- /dev/null +++ b/adept/updater/hi64-app-adept_updater.png diff --git a/adept/updater/hisc-app-adept_updater.svgz b/adept/updater/hisc-app-adept_updater.svgz Binary files differnew file mode 100644 index 0000000..2c6fab6 --- /dev/null +++ b/adept/updater/hisc-app-adept_updater.svgz diff --git a/adept/updater/main.cpp b/adept/updater/main.cpp new file mode 100644 index 0000000..a86ee9b --- /dev/null +++ b/adept/updater/main.cpp @@ -0,0 +1,56 @@ +// KDE includes + +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#include <kuniqueapplication.h> + +#include "app.h" + +static KCmdLineOptions options[] = +{ + KCmdLineLastOption +}; + +int main(int argc, char *argv[]) +{ + + KLocale::setMainCatalogue("adept_updater"); + + putenv( "QT_IM_MODULE=xim" ); + QString description = i18n("Adept Updater"); + + KAboutData aboutData( "adept_updater", + I18N_NOOP("Adept Updater"), + "2.1 Cruiser", + description.latin1(), + KAboutData::License_BSD, + I18N_NOOP("(c) 2005, 2006 Peter Rockai"), + 0, + "http://web.mornfall.net/adept.html"); + + aboutData.addAuthor ( "Peter Rockai", + I18N_NOOP("developer"), + "me at mornfall dot net", + "http://web.mornfall.net"); + + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication app; + + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + // if (args && args->isSet("xy")) ... + + /* KConfig* config = KGlobal::config(); + config->setGroup("General Settings"); + QString version = config->readEntry("Version"); */ + + KGlobal::locale()->insertCatalogue(QString::fromUtf8("libept")); + + TestApp *ta = new TestApp(); + + app.setMainWidget(ta); + ta->show(); + + return app.exec(); +} |