summaryrefslogtreecommitdiff
path: root/noncore/unsupported/oipkg/packagemanager.cpp
Side-by-side diff
Diffstat (limited to 'noncore/unsupported/oipkg/packagemanager.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/unsupported/oipkg/packagemanager.cpp897
1 files changed, 897 insertions, 0 deletions
diff --git a/noncore/unsupported/oipkg/packagemanager.cpp b/noncore/unsupported/oipkg/packagemanager.cpp
new file mode 100644
index 0000000..f3da15d
--- a/dev/null
+++ b/noncore/unsupported/oipkg/packagemanager.cpp
@@ -0,0 +1,897 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#include "packagemanager.h"
+#include "pkdesc.h"
+#include "pkfind.h"
+#include "pksettings.h"
+
+#include <qpe/process.h>
+#include <qpe/resource.h>
+#include <qpe/stringutil.h>
+#include <qpe/qpeapplication.h>
+#include <qpe/qcopenvelope_qws.h>
+#include <qpe/applnk.h>
+
+#include <qprogressbar.h>
+#include <qcombobox.h>
+#include <qdict.h>
+#include <qfile.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qlistview.h>
+#include <qlistbox.h>
+#include <qmessagebox.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+#include <qtextview.h>
+#include <qtoolbutton.h>
+
+#include <stdlib.h>
+
+static QPixmap *pm_uninstalled=0;
+static QPixmap *pm_installed=0;
+static QPixmap *pm_uninstall=0;
+static QPixmap *pm_install=0;
+
+
+class PackageItem : public QCheckListItem {
+ bool installed;
+public:
+ PackageItem(QListView* lv, const QString& name, const QString& desc, const QString& size, bool inst ) :
+ QCheckListItem(lv,name,CheckBox), installed(inst)
+ {
+ setText(1,desc);
+ setText(2,size);
+ }
+
+ void paintCell( QPainter *p, const QColorGroup & cg,
+ int column, int width, int alignment )
+ {
+ if ( !p )
+ return;
+
+ p->fillRect( 0, 0, width, height(),
+ isSelected()? cg.highlight() : cg.base() );
+
+ if ( column != 0 ) {
+ // The rest is text
+ QListViewItem::paintCell( p, cg, column, width, alignment );
+ return;
+ }
+
+ QListView *lv = listView();
+ if ( !lv )
+ return;
+ int marg = lv->itemMargin();
+ int r = marg;
+
+ QPixmap pm = statePixmap();
+ p->drawPixmap(marg,(height()-pm.height())/2,pm);
+ r += pm.width()+1;
+
+ p->translate( r, 0 );
+ QListViewItem::paintCell( p, cg, column, width - r, alignment );
+ }
+
+ void paintFocus( QPainter *p, const QColorGroup & cg,
+ const QRect & r )
+ {
+ // Skip QCheckListItem
+ // (makes you wonder what we're getting from QCheckListItem)
+ QListViewItem::paintFocus(p,cg,r);
+ }
+
+ QPixmap statePixmap() const
+ {
+ if ( !isOn() ) {
+ if ( !installed )
+ return *pm_uninstalled;
+ else
+ return *pm_installed;
+ } else {
+ if ( !installed )
+ return *pm_install;
+ else
+ return *pm_uninstall;
+ }
+ }
+
+ QString name() const { return text(0); }
+ QString description() const { return text(1); }
+ bool isInstalled() const { return installed; }
+
+ QString key( int column, bool ascending ) const
+ {
+ if ( column == 2 ) {
+ QString t = text(2);
+ double bytes=t.toDouble();
+ if ( t.contains('M') ) bytes*=1024*1024;
+ else if ( t.contains('K') || t.contains('k') ) bytes*=1024;
+ if ( !ascending ) bytes=999999999-bytes;
+ return QString().sprintf("%09d",(int)bytes);
+ } else {
+ return QListViewItem::key(column,ascending);
+ }
+ }
+};
+
+/*
+ * Constructs a PackageManager which is a child of 'parent', with the
+ * name 'name' and widget flags set to 'f'
+ */
+PackageManager::PackageManager( QWidget* parent, const char* name, WFlags fl )
+ : PackageManagerBase( parent, name, fl )
+{
+ settings = new PackageManagerSettings(this,0,TRUE);
+ connect( settings->newserver, SIGNAL(clicked()), this, SLOT(newServer()) );
+ connect( settings->removeserver, SIGNAL(clicked()), this, SLOT(removeServer()) );
+ connect( settings->servers, SIGNAL(highlighted(int)), this, SLOT(editServer(int)) );
+ connect( doit, SIGNAL(clicked()), this, SLOT(doIt()) );
+ settings->servername->setEnabled(FALSE);
+ settings->serverurl->setEnabled(FALSE);
+ serverurl.setAutoDelete(TRUE);
+
+ if (!pm_uninstalled) {
+ pm_uninstalled = new QPixmap(Resource::loadPixmap("uninstalled"));
+ pm_installed = new QPixmap(Resource::loadPixmap("installed"));
+ pm_install = new QPixmap(Resource::loadPixmap("install"));
+ pm_uninstall = new QPixmap(Resource::loadPixmap("uninstall"));
+ }
+
+ QFontMetrics fm = fontMetrics();
+ int w0 = fm.width(PackageManagerBase::tr("Package"))+30;
+ int w2 = fm.width("00000")+4;
+ list->setColumnWidth(0,w0);
+ list->setColumnWidth(1,228-w2-w0); // ### screen-biased
+ list->setColumnWidth(2,w2);
+ list->setColumnWidthMode(0,QListView::Manual);
+ list->setColumnWidthMode(1,QListView::Manual);
+ list->setColumnWidthMode(2,QListView::Manual);
+ list->setSelectionMode( QListView::Multi );
+ details = 0;
+ ipkg_old = 0;
+ readSettings();
+ updatePackageList();
+ progress->hide();
+}
+
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+PackageManager::~PackageManager()
+{
+ // no need to delete child widgets, Qt does it all for us
+}
+
+void PackageManager::newServer()
+{
+ int i = settings->servers->count();
+ if ( settings->servername->isEnabled() || settings->serverurl->text().isEmpty() ) {
+ serverurl.insert(i,new QString("http://"));
+ settings->servers->insertItem(tr("New"));
+ } else {
+ // allows one-level undo
+ serverurl.insert(i,new QString(settings->serverurl->text()));
+ settings->servers->insertItem(settings->servername->text());
+ }
+ settings->servers->setSelected(i,TRUE);
+ editServer(i);
+}
+
+void PackageManager::editServer(int i)
+{
+ if ( settings->servername->isEnabled() ) {
+ disconnect( settings->servername, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&)) );
+ disconnect( settings->serverurl, SIGNAL(textChanged(const QString&)), this, SLOT(urlChanged(const QString&)) );
+ } else {
+ settings->servername->setEnabled(TRUE);
+ settings->serverurl->setEnabled(TRUE);
+ }
+
+ settings->servername->setText( settings->servers->text(i) );
+ settings->serverurl->setText( *serverurl[i] );
+
+ editedserver = i;
+
+ connect( settings->servername, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&)) );
+ connect( settings->serverurl, SIGNAL(textChanged(const QString&)), this, SLOT(urlChanged(const QString&)) );
+}
+
+void PackageManager::removeServer()
+{
+ disconnect( settings->servername, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&)) );
+ disconnect( settings->serverurl, SIGNAL(textChanged(const QString&)), this, SLOT(urlChanged(const QString&)) );
+ settings->servername->setText(settings->servers->text(editedserver));
+ settings->serverurl->setText(*serverurl[editedserver]);
+ disconnect( settings->servers, SIGNAL(highlighted(int)), this, SLOT(editServer(int)) );
+ settings->servers->removeItem(editedserver);
+ connect( settings->servers, SIGNAL(highlighted(int)), this, SLOT(editServer(int)) );
+ settings->servername->setEnabled(FALSE);
+ settings->serverurl->setEnabled(FALSE);
+}
+
+void PackageManager::nameChanged(const QString& t)
+{
+ disconnect( settings->servers, SIGNAL(highlighted(int)), this, SLOT(editServer(int)) );
+ settings->servers->changeItem( t, editedserver );
+ connect( settings->servers, SIGNAL(highlighted(int)), this, SLOT(editServer(int)) );
+}
+
+void PackageManager::urlChanged(const QString& t)
+{
+ serverurl.replace(editedserver, new QString(t));
+}
+
+static void selectComboItem(QComboBox *cb, const QString s)
+{
+ for (int i=0; i<cb->count(); i++) {
+ if ( cb->text(i) == s ) {
+ cb->setCurrentItem(i);
+ return;
+ }
+ }
+}
+
+void PackageManager::updatePackageList()
+{
+ disconnect(section,SIGNAL(activated(int)),this,SLOT(updatePackageList()));
+ disconnect(subsection,SIGNAL(activated(int)),this,SLOT(updatePackageList()));
+
+ list->clear();
+ QString cursection = section->currentText();
+ QString cursubsection = subsection->currentText();
+ QString all=tr("All");
+ if ( cursection == all ) cursection=QString::null;
+ if ( cursubsection == all ) cursubsection=QString::null;
+ section->clear();
+ subsection->clear();
+
+ QDict<void> sections;
+ QDict<void> subsections;
+ QDict<void> installed;
+
+ QRegExp separatorRegExp( ":[\t ]+" );
+
+ QString status = ipkgStatusOutput();
+ if ( !status.isEmpty() ) {
+ QStringList lines = QStringList::split('\n',status,TRUE);
+ QString name;
+ QString status;
+ for (QStringList::Iterator it = lines.begin(); it!=lines.end(); ++it) {
+ QString line = *it;
+ if ( line.length()<=1 ) {
+ // EOR
+ if ( !name.isEmpty() ) {
+ if ( status.contains(" installed") )
+ installed.replace(name,(void*)1);
+ name="";
+ }
+ status="";
+ } else if ( line[0] == ' ' || line[0] == '\t' ) {
+ // continuation
+ } else {
+ int sep = line.find(separatorRegExp);
+ if ( sep >= 0 ) {
+ QString tag = line.left(sep);
+ if ( tag == "Package" ) {
+ name = line.mid(sep+2).simplifyWhiteSpace();
+ } else if ( tag == "Status" ) {
+ status = line.mid(sep+1);
+ }
+ }
+ }
+ }
+ }
+
+ QString info = ipkgInfoOutput();
+ if ( !info.isEmpty() ) {
+ QStringList lines = QStringList::split('\n',info,TRUE);
+ QString description_short;
+ QString name;
+ QString size;
+ QString sec;
+ for (QStringList::Iterator it = lines.begin(); it!=lines.end(); ++it) {
+ QString line = *it;
+ if ( line.length()<=1 ) {
+ // EOR
+ if ( !name.isEmpty() ) {
+ int sl = sec.find('/');
+ QString s = sl < 0 ? sec : sec.left(sl);
+ QString ss = sl < 0 ? QString::null : sec.mid(sl+1);
+ sections.replace(s,(void*)1);
+ if ( cursection.isNull()
+ || cursection == s
+ && (cursubsection.isNull() || cursubsection == ss) )
+ {
+ if ( !cursection.isNull() && !ss.isNull() )
+ subsections.replace(ss,(void*)1);
+ description_short[0] = description_short[0].upper();
+ if ( description_short.left(4) == "The " )
+ description_short = description_short.mid(4);
+ if ( description_short.left(2) == "A " )
+ description_short = description_short.mid(2);
+ description_short[0] = description_short[0].upper();
+ new PackageItem(list,name,description_short,size,
+ installed.find(name));
+ }
+ installed.remove( name );
+ }
+ name="";
+ size="";
+ sec="main";
+ } else if ( line[0] == ' ' || line[0] == '\t' ) {
+ // continuation
+ } else {
+ int sep = line.find(separatorRegExp);
+ if ( sep >= 0 ) {
+ QString tag = line.left(sep);
+ if ( tag == "Package" ) {
+ name = line.mid(sep+2).simplifyWhiteSpace();
+ } else if ( tag == "Description" ) {
+ description_short = line.mid(sep+2).simplifyWhiteSpace();
+ } else if ( tag == "Installed-Size" ) {
+ size = line.mid(sep+2).simplifyWhiteSpace();
+ } else if ( tag == "Section" ) {
+ sec = line.mid(sep+2).simplifyWhiteSpace();
+ }
+ }
+ }
+ }
+ if ( installed.count() && cursection.isNull() ) {
+ // we have some packages without description
+ QDictIterator<void> it( installed );
+ for( ; it.current(); ++it )
+ new PackageItem( list, it.currentKey(), "", "?" , TRUE );
+ }
+
+ QStringList s;
+ QDictIterator<void> it( sections );
+ for( ; it.current(); ++it )
+ s.append(it.currentKey());
+ s.sort();
+ section->insertItem(all);
+ section->insertStringList(s);
+ selectComboItem(section,cursection.isNull()?all:cursection);
+ if ( cursection.isNull() ) {
+ subsection->setEnabled(FALSE);
+ } else {
+ subsection->setEnabled(TRUE);
+ QStringList s;
+ QDictIterator<void> it( subsections );
+ for( ; it.current(); ++it )
+ s.append(it.currentKey());
+ s.sort();
+ subsection->insertItem(all);
+ subsection->insertStringList(s);
+ selectComboItem(subsection,cursubsection.isNull()?all:cursubsection);
+ }
+ } else {
+ new QListViewItem(list,"ERROR");
+ }
+
+ connect(section,SIGNAL(activated(int)),SLOT(updatePackageList()));
+ connect(subsection,SIGNAL(activated(int)),this,SLOT(updatePackageList()));
+}
+
+PackageItem* PackageManager::current() const
+{
+ return (PackageItem*)list->currentItem();
+}
+
+/*
+ * public slot
+ */
+void PackageManager::doCurrentDetails(bool multi)
+{
+ PackageItem* pit = current();
+ if ( pit ) {
+ if ( !details ) {
+ details = new PackageDetails;
+ connect( details->install, SIGNAL(clicked()),
+ this, SLOT(installCurrent()));
+ connect( details->remove, SIGNAL(clicked()),
+ this, SLOT(removeCurrent()));
+ details->description->setTextFormat(RichText);
+ }
+ if ( multi ) {
+ disconnect( details->ignore, SIGNAL(clicked()),
+ details, SLOT(close()));
+ connect( details->ignore, SIGNAL(clicked()),
+ this, SLOT(doNextDetails()));
+ } else {
+ disconnect( details->ignore, SIGNAL(clicked()),
+ this, SLOT(doNextDetails()));
+ connect( details->ignore, SIGNAL(clicked()),
+ details, SLOT(close()));
+ }
+ pit->setSelected(FALSE);
+ details->setCaption("Package: " + pit->name());
+ details->description->setText(fullDetails(pit->name()));
+ details->install->setEnabled(!pit->isInstalled());
+ details->remove->setEnabled(pit->isInstalled());
+ details->showMaximized();
+ }
+}
+
+void PackageManager::doDetails()
+{
+ doCurrentDetails(FALSE);
+}
+
+void PackageManager::doNextDetails()
+{
+ QListViewItem* i = list->firstChild();
+ for ( ; i; i = i->nextSibling() ) {
+ if ( i->isSelected() )
+ break;
+ }
+ list->setCurrentItem(i);
+ if ( i ) {
+ doCurrentDetails(TRUE);
+ } else if ( details )
+ details->close();
+}
+
+QString PackageManager::fullDetails(const QString& pk)
+{
+ QString status;
+ Process ipkg_status(QStringList() << "ipkg" << "info" << pk);
+ if ( ipkg_status.exec("",status) ) {
+ QStringList lines = QStringList::split('\n',status,TRUE);
+ QString description;
+ for (QStringList::Iterator it = lines.begin(); it!=lines.end(); ++it) {
+ QString line = *it;
+ if ( line == " ." ) {
+ description.append("<p>");
+ } else if ( line[0] == ' ' || line[0] == '\t' ) {
+ // continuation
+ description.append(" ");
+ description.append(Qtopia::escapeString(line));
+ } else {
+ int sep = line.find(QRegExp(":[\t ]+"));
+ if ( sep >= 0 ) {
+ QString tag = line.left(sep);
+ description.append("<br>");
+ description.append("<b>");
+ description.append(Qtopia::escapeString(tag));
+ description.append(":</b> ");
+ description.append(Qtopia::escapeString(line.mid(sep+2)));
+ } else {
+ description.append(" ");
+ description.append(Qtopia::escapeString(line));
+ }
+ }
+ }
+ return description;
+ }
+
+ return QString::null;
+}
+
+void PackageManager::installCurrent()
+{
+ current()->setOn(TRUE);
+ details->close();
+}
+
+void PackageManager::removeCurrent()
+{
+ current()->setOn(TRUE);
+ details->close();
+}
+
+bool PackageManager::readIpkgConfig(const QString& conffile)
+{
+ QFile conf(conffile);
+ if ( conf.open(IO_ReadOnly) ) {
+ QTextStream s(&conf);
+ settings->servers->clear();
+ serverurl.clear();
+ ipkg_old=0;
+ int currentserver=0;
+ while ( !s.atEnd() ) {
+ QString l = s.readLine();
+ QStringList token = QStringList::split(' ', l);
+ if ( token[0] == "src" || token[0] == "#src" ) {
+ currentserver=settings->servers->count();
+ serverurl.insert(settings->servers->count(),new QString(token[2]));
+ int a = token[0] == "src" ? 1 : 0;
+ int i = settings->servers->count();
+ settings->servers->insertItem(token[1]);
+ settings->servers->setSelected(i,a);
+ } else if ( token[0] == "dest" ) {
+ // needs UI
+ } else if ( token[0] == "option" ) {
+ // ### somehow need to use the settings from netsetup
+// if ( token[1] == "http_proxy" )
+// settings->http->setText(token[2]);
+// else if ( token[1] == "ftp_proxy" )
+// settings->ftp->setText(token[2]);
+// else if ( token[1] == "proxy_username" )
+// settings->username->setText(token[2]);
+// else if ( token[1] == "proxy_password" )
+// settings->password->setText(token[2]);
+ } else {
+ // Old style?
+ int eq = l.find('=');
+ if ( eq >= 0 ) {
+ QString v = l.mid(eq+1).stripWhiteSpace();
+ if ( v[0] == '"' || v[0] == '\'' ) {
+ int cl=v.find(v[0],1);
+ if ( cl >= 0 )
+ v = v.mid(1,cl-1);
+ }
+ if ( l.left(12) == "IPKG_SOURCE=" ) {
+ ipkg_old=1;
+ currentserver=settings->servers->count();
+ serverurl.insert(settings->servers->count(),new QString(v));
+ settings->servers->insertItem(v);
+ } else if ( l.left(13) == "#IPKG_SOURCE=" ) {
+ serverurl.insert(settings->servers->count(),new QString(v));
+ settings->servers->insertItem(v);
+ } else if ( l.left(10) == "IPKG_ROOT=" ) {
+ // ### no UI
+// } else if ( l.left(20) == "IPKG_PROXY_USERNAME=" ) {
+// settings->username->setText(v);
+// } else if ( l.left(20) == "IPKG_PROXY_PASSWORD=" ) {
+// settings->password->setText(v);
+// } else if ( l.left(16) == "IPKG_PROXY_HTTP=" ) {
+// settings->http->setText(v);
+// } else if ( l.left(16) == "IPKG_PROXY_FTP=" ) {
+// settings->ftp->setText(v);
+ }
+ }
+ }
+ }
+ if ( ipkg_old ) {
+ settings->servers->setSelectionMode(QListBox::Single);
+ settings->servers->setSelected(currentserver,TRUE);
+ }
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/*
+ * public slot
+ */
+void PackageManager::doSettings()
+{
+ settings->showMaximized();
+ if ( settings->exec() ) {
+ writeSettings();
+ startRun();
+ runIpkg("update");
+ endRun();
+ updatePackageList();
+ } else {
+ readSettings();
+ }
+}
+
+void PackageManager::readSettings()
+{
+ // read from config file(s)
+ readIpkgConfig("/etc/ipkg.conf");
+}
+
+void PackageManager::writeSettings()
+{
+ QFile conf("/etc/ipkg.conf");
+ if ( conf.open(IO_WriteOnly) ) {
+ QTextStream s(&conf);
+ s << "# Written by Qtopia Package Manager\n";
+ if ( !ipkg_old ) {
+ for (int i=0; i<(int)settings->servers->count(); i++) {
+ QString url = serverurl[i] ? *serverurl[i] : QString("???");
+ if ( !settings->servers->isSelected(i) )
+ s << "#";
+ s << "src " << settings->servers->text(i) << " " << url << "\n";
+ }
+ s << "dest root /\n"; // ### need UI
+// if ( !settings->username->text().isEmpty() )
+// s << "option proxy_username " << settings->username->text() << "\n";
+// if ( !settings->password->text().isEmpty() )
+// s << "option proxy_password " << settings->password->text() << "\n";
+// if ( !settings->http->text().isEmpty() )
+// s << "option http_proxy " << settings->http->text() << "\n";
+// if ( !settings->ftp->text().isEmpty() )
+// s << "option ftp_proxy " << settings->ftp->text() << "\n";
+ } else {
+ // Old style
+ bool src_selected=FALSE;
+ for (int i=0; i<(int)settings->servers->count(); i++) {
+ if ( settings->servers->isSelected(i) ) {
+ src_selected=TRUE;
+ } else {
+ s << "#";
+ }
+ s << "IPKG_SOURCE=\"" << settings->servers->text(i) << "\"\n";
+ }
+ if ( !src_selected )
+ s << "IPKG_SOURCE=\"" << settings->servers->currentText() << "\"\n";
+ s << "IPKG_ROOT=/\n"
+// << "IPKG_PROXY_USERNAME=\"" << settings->username->text() << "\"\n"
+// << "IPKG_PROXY_PASSWORD=\"" << settings->password->text() << "\"\n"
+// << "IPKG_PROXY_HTTP=\"" << settings->http->text() << "\"\n"
+// << "IPKG_PROXY_FTP=\"" << settings->ftp->text() << "\"\n"
+ ;
+ }
+ conf.close();
+ }
+}
+
+/*
+ * public slot
+ */
+void PackageManager::doFind()
+{
+ Search s(this, 0, TRUE);
+ if ( s.exec() ) {
+ QString p = s.pattern->text();
+ if ( p.isEmpty() ) {
+ list->selectAll(FALSE);
+ } else {
+ selectPackages(findPackages(p));
+ doNextDetails();
+ }
+ }
+}
+
+void PackageManager::selectPackages( const QStringList& l )
+{
+ QDict<void> d;
+ for (QStringList::ConstIterator it = l.begin(); it != l.end(); ++it)
+ d.replace(*it,(void*)1);
+ QListViewItem* i;
+ for ( i = list->firstChild(); i; i = i->nextSibling() ) {
+ PackageItem* pit = (PackageItem*)i;
+ i->setSelected( d[pit->name()] );
+ }
+}
+
+QStringList PackageManager::findPackages( const QRegExp& r )
+{
+ QStringList matches;
+
+ QString info = ipkgInfoOutput();
+ if ( !info.isEmpty() ) {
+ QStringList lines = QStringList::split('\n',info,TRUE);
+ QRegExp re = r;
+ QString description="";
+ QString name;
+ for (QStringList::Iterator it = lines.begin(); it!=lines.end(); ++it) {
+ QString line = *it;
+ if ( line.length()<=1 ) {
+ // EOR
+ if ( re.match(description) >= 0 )
+ matches.append(name);
+ description="";
+ name="";
+ } else if ( line[0] == ' ' || line[0] == '\t' ) {
+ // continuation
+ description.append(" ");
+ description.append(Qtopia::escapeString(line));
+ } else {
+ int sep = line.find(QRegExp(":[\t ]+"));
+ if ( sep >= 0 ) {
+ QString tag = line.left(sep);
+ if ( tag == "Package" )
+ name = line.mid(sep+2).simplifyWhiteSpace();
+ if ( !description.isEmpty() )
+ description.append("<br>");
+ description.append("<b>");
+ description.append(Qtopia::escapeString(tag));
+ description.append(":</b> ");
+ description.append(Qtopia::escapeString(line.mid(sep+2)));
+ }
+ }
+ }
+ }
+
+ return matches;
+}
+
+/*
+ * public slot
+ */
+void PackageManager::doUpgrade()
+{
+ startMultiRun(2);
+ runIpkg("update");
+ runIpkg("upgrade");
+ updatePackageList();
+ endRun();
+}
+
+
+void PackageManager::doIt()
+{
+ bool ok = commitWithIpkg();
+ updatePackageList(); // things may have changed
+ if (!ok) qApp->beep();
+}
+
+bool PackageManager::commitWithIpkg()
+{
+ // A full implementation would do the following, but we'll just do
+ // it simply and non-interactively for now.
+ //
+ // setenv IPKG_CONF_DIR for a null $IPKG_CONF_DIR/ipkg.conf
+ // setenv IPKG_SOURCE, IPKG_ROOT, etc.
+ // run ipkg, processing interactivity as dialogs
+ // - "... (Y/I/N/O/D) [default=N] ?" -> ...
+ // - "[Press ENTER to continue]" (if D chosen above)
+ // - "The following packages are marked `Essential'... Install them now [Y/n] ?"
+ // - "The following packages...ready to be installed:... Install them now [Y/n] ?"
+ // return FALSE cancelled
+
+ QStringList to_remove, to_install;
+
+ for ( QListViewItem* i = list->firstChild(); i; i = i->nextSibling() ) {
+ PackageItem* pit = (PackageItem*)i;
+ if ( pit->isOn() ) {
+ if ( pit->isInstalled() )
+ to_remove.append(pit->name());
+ else
+ to_install.append(pit->name());
+ }
+ }
+
+ bool ok=TRUE;
+
+ int jobs = to_remove.count()+to_install.count();
+ if ( jobs ) {
+ startMultiRun(jobs);
+
+ if ( to_remove.count() ) {
+ for (QStringList::ConstIterator it=to_remove.begin(); it!=to_remove.end(); ++it) {
+ if ( runIpkg("remove " + *it) != 0 ) {
+ ok = FALSE;
+ }
+ }
+ }
+ if ( to_install.count() ) {
+ for (QStringList::ConstIterator it=to_install.begin(); it!=to_install.end(); ++it) {
+ if ( runIpkg("install " + *it) != 0 ) {
+ ok = FALSE;
+ }
+ }
+ }
+
+ // ##### If we looked in the list of files, we could send out accurate
+ // ##### messages. But we don't bother yet, and just do an "all".
+ QCopEnvelope e("QPE/System", "linkChanged(QString)");
+ QString lf = QString::null;
+ e << lf;
+
+#if QT_VERSION > 230 // a bug breaks this otherwise
+ if ( !ok )
+ QMessageBox::warning(this, "Error", "<p><tt>ipkg</tt> says something went wrong. Sorry.");
+#endif
+
+ endRun();
+ }
+
+ return ok;
+}
+
+QString PackageManager::ipkgStatusOutput()
+{
+ if ( cachedIpkgStatusOutput.isEmpty() ) {
+ Process ipkg_status( QStringList() << "ipkg" << "status" );
+ ipkg_status.exec( 0, cachedIpkgStatusOutput );
+ }
+ return QString::fromLocal8Bit( cachedIpkgStatusOutput );
+}
+
+QString PackageManager::ipkgInfoOutput()
+{
+ if ( cachedIpkgInfoOutput.isEmpty() ) {
+ Process ipkg_info( QStringList() << "ipkg" << "info" );
+ ipkg_info.exec( 0, cachedIpkgInfoOutput );
+ }
+ return QString::fromLocal8Bit( cachedIpkgInfoOutput );
+}
+
+void PackageManager::setCachedIpkgOutputDirty()
+{
+ cachedIpkgInfoOutput = cachedIpkgStatusOutput = QString::null;
+}
+
+void PackageManager::startMultiRun(int jobs)
+{
+ startRun();
+ progress->setTotalSteps(jobs);
+ progress->setProgress(0);
+}
+
+void PackageManager::startRun()
+{
+ progress->show();
+ doit->hide();
+}
+
+void PackageManager::endRun()
+{
+ doit->show();
+ progress->hide();
+}
+
+int PackageManager::runIpkg(const QString& args)
+{
+ if ( progress->progress() == -1 )
+ startMultiRun(1);
+ else
+ startRun();
+ QString cmd = "ipkg ";
+ if ( ipkg_old )
+ cmd += "</dev/null ";
+ else
+ cmd += "-force-defaults ";
+ int r = system((cmd+args).latin1());
+ progress->setProgress(progress->progress()+1);
+ setCachedIpkgOutputDirty();
+ endRun();
+ return r;
+}
+
+// simple hack to get support for ipkg mimetype
+void PackageManager::maybeInstall( const QString &ipk )
+{
+ int pos = ipk.findRev( "/" );
+ QString package = ipk.mid( pos + 1 );
+ pos = package.find ( "_" );
+ if ( pos != -1 )
+ package = package.left( pos );
+ switch ( QMessageBox::information( 0, tr( "Install Package" ),
+ tr("Are you sure you want to\ninstall package\n\n%1")
+ .arg(package), QMessageBox::Yes,
+ QMessageBox::No|QMessageBox::Default|QMessageBox::Escape, 0 ) ) {
+ case QMessageBox::Yes: {
+ startRun();
+ runIpkg("install " + ipk );
+ QCopEnvelope e("QPE/System", "linkChanged(QString)");
+ QString lf = QString::null;
+ e << lf;
+ endRun();
+ }
+ break;
+ case QMessageBox::No:
+ default:
+ // do nothing
+ break;
+ }
+}
+
+void PackageManager::setDocument(const QString& fileref)
+{
+ if ( fileref.isNull() )
+ return;
+ DocLnk doc( fileref );
+ if ( doc.file().isEmpty() )
+ return;
+ maybeInstall( doc.file() );
+ updatePackageList();
+}