summaryrefslogtreecommitdiff
path: root/noncore/unsupported/oipkg/packagemanager.cpp
Unidiff
Diffstat (limited to 'noncore/unsupported/oipkg/packagemanager.cpp') (more/less context) (show 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 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20#include "packagemanager.h"
21#include "pkdesc.h"
22#include "pkfind.h"
23#include "pksettings.h"
24
25#include <qpe/process.h>
26#include <qpe/resource.h>
27#include <qpe/stringutil.h>
28#include <qpe/qpeapplication.h>
29#include <qpe/qcopenvelope_qws.h>
30#include <qpe/applnk.h>
31
32#include <qprogressbar.h>
33#include <qcombobox.h>
34#include <qdict.h>
35#include <qfile.h>
36#include <qlineedit.h>
37#include <qpushbutton.h>
38#include <qlistview.h>
39#include <qlistbox.h>
40#include <qmessagebox.h>
41#include <qpainter.h>
42#include <qpixmap.h>
43#include <qregexp.h>
44#include <qtextstream.h>
45#include <qtextview.h>
46#include <qtoolbutton.h>
47
48#include <stdlib.h>
49
50static QPixmap *pm_uninstalled=0;
51static QPixmap *pm_installed=0;
52static QPixmap *pm_uninstall=0;
53static QPixmap *pm_install=0;
54
55
56class PackageItem : public QCheckListItem {
57 bool installed;
58public:
59 PackageItem(QListView* lv, const QString& name, const QString& desc, const QString& size, bool inst ) :
60 QCheckListItem(lv,name,CheckBox), installed(inst)
61 {
62 setText(1,desc);
63 setText(2,size);
64 }
65
66 void paintCell( QPainter *p, const QColorGroup & cg,
67 int column, int width, int alignment )
68 {
69 if ( !p )
70 return;
71
72 p->fillRect( 0, 0, width, height(),
73 isSelected()? cg.highlight() : cg.base() );
74
75 if ( column != 0 ) {
76 // The rest is text
77 QListViewItem::paintCell( p, cg, column, width, alignment );
78 return;
79 }
80
81 QListView *lv = listView();
82 if ( !lv )
83 return;
84 int marg = lv->itemMargin();
85 int r = marg;
86
87 QPixmap pm = statePixmap();
88 p->drawPixmap(marg,(height()-pm.height())/2,pm);
89 r += pm.width()+1;
90
91 p->translate( r, 0 );
92 QListViewItem::paintCell( p, cg, column, width - r, alignment );
93 }
94
95 void paintFocus( QPainter *p, const QColorGroup & cg,
96 const QRect & r )
97 {
98 // Skip QCheckListItem
99 // (makes you wonder what we're getting from QCheckListItem)
100 QListViewItem::paintFocus(p,cg,r);
101 }
102
103 QPixmap statePixmap() const
104 {
105 if ( !isOn() ) {
106 if ( !installed )
107 return *pm_uninstalled;
108 else
109 return *pm_installed;
110 } else {
111 if ( !installed )
112 return *pm_install;
113 else
114 return *pm_uninstall;
115 }
116 }
117
118 QString name() const { return text(0); }
119 QString description() const { return text(1); }
120 bool isInstalled() const { return installed; }
121
122 QString key( int column, bool ascending ) const
123 {
124 if ( column == 2 ) {
125 QString t = text(2);
126 double bytes=t.toDouble();
127 if ( t.contains('M') ) bytes*=1024*1024;
128 else if ( t.contains('K') || t.contains('k') ) bytes*=1024;
129 if ( !ascending ) bytes=999999999-bytes;
130 return QString().sprintf("%09d",(int)bytes);
131 } else {
132 return QListViewItem::key(column,ascending);
133 }
134 }
135};
136
137/*
138 * Constructs a PackageManager which is a child of 'parent', with the
139 * name 'name' and widget flags set to 'f'
140 */
141PackageManager::PackageManager( QWidget* parent, const char* name, WFlags fl )
142 : PackageManagerBase( parent, name, fl )
143{
144 settings = new PackageManagerSettings(this,0,TRUE);
145 connect( settings->newserver, SIGNAL(clicked()), this, SLOT(newServer()) );
146 connect( settings->removeserver, SIGNAL(clicked()), this, SLOT(removeServer()) );
147 connect( settings->servers, SIGNAL(highlighted(int)), this, SLOT(editServer(int)) );
148 connect( doit, SIGNAL(clicked()), this, SLOT(doIt()) );
149 settings->servername->setEnabled(FALSE);
150 settings->serverurl->setEnabled(FALSE);
151 serverurl.setAutoDelete(TRUE);
152
153 if (!pm_uninstalled) {
154 pm_uninstalled = new QPixmap(Resource::loadPixmap("uninstalled"));
155 pm_installed = new QPixmap(Resource::loadPixmap("installed"));
156 pm_install = new QPixmap(Resource::loadPixmap("install"));
157 pm_uninstall = new QPixmap(Resource::loadPixmap("uninstall"));
158 }
159
160 QFontMetrics fm = fontMetrics();
161 int w0 = fm.width(PackageManagerBase::tr("Package"))+30;
162 int w2 = fm.width("00000")+4;
163 list->setColumnWidth(0,w0);
164 list->setColumnWidth(1,228-w2-w0); // ### screen-biased
165 list->setColumnWidth(2,w2);
166 list->setColumnWidthMode(0,QListView::Manual);
167 list->setColumnWidthMode(1,QListView::Manual);
168 list->setColumnWidthMode(2,QListView::Manual);
169 list->setSelectionMode( QListView::Multi );
170 details = 0;
171 ipkg_old = 0;
172 readSettings();
173 updatePackageList();
174 progress->hide();
175}
176
177
178/*
179 * Destroys the object and frees any allocated resources
180 */
181PackageManager::~PackageManager()
182{
183 // no need to delete child widgets, Qt does it all for us
184}
185
186void PackageManager::newServer()
187{
188 int i = settings->servers->count();
189 if ( settings->servername->isEnabled() || settings->serverurl->text().isEmpty() ) {
190 serverurl.insert(i,new QString("http://"));
191 settings->servers->insertItem(tr("New"));
192 } else {
193 // allows one-level undo
194 serverurl.insert(i,new QString(settings->serverurl->text()));
195 settings->servers->insertItem(settings->servername->text());
196 }
197 settings->servers->setSelected(i,TRUE);
198 editServer(i);
199}
200
201void PackageManager::editServer(int i)
202{
203 if ( settings->servername->isEnabled() ) {
204 disconnect( settings->servername, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&)) );
205 disconnect( settings->serverurl, SIGNAL(textChanged(const QString&)), this, SLOT(urlChanged(const QString&)) );
206 } else {
207 settings->servername->setEnabled(TRUE);
208 settings->serverurl->setEnabled(TRUE);
209 }
210
211 settings->servername->setText( settings->servers->text(i) );
212 settings->serverurl->setText( *serverurl[i] );
213
214 editedserver = i;
215
216 connect( settings->servername, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&)) );
217 connect( settings->serverurl, SIGNAL(textChanged(const QString&)), this, SLOT(urlChanged(const QString&)) );
218}
219
220void PackageManager::removeServer()
221{
222 disconnect( settings->servername, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&)) );
223 disconnect( settings->serverurl, SIGNAL(textChanged(const QString&)), this, SLOT(urlChanged(const QString&)) );
224 settings->servername->setText(settings->servers->text(editedserver));
225 settings->serverurl->setText(*serverurl[editedserver]);
226 disconnect( settings->servers, SIGNAL(highlighted(int)), this, SLOT(editServer(int)) );
227 settings->servers->removeItem(editedserver);
228 connect( settings->servers, SIGNAL(highlighted(int)), this, SLOT(editServer(int)) );
229 settings->servername->setEnabled(FALSE);
230 settings->serverurl->setEnabled(FALSE);
231}
232
233void PackageManager::nameChanged(const QString& t)
234{
235 disconnect( settings->servers, SIGNAL(highlighted(int)), this, SLOT(editServer(int)) );
236 settings->servers->changeItem( t, editedserver );
237 connect( settings->servers, SIGNAL(highlighted(int)), this, SLOT(editServer(int)) );
238}
239
240void PackageManager::urlChanged(const QString& t)
241{
242 serverurl.replace(editedserver, new QString(t));
243}
244
245static void selectComboItem(QComboBox *cb, const QString s)
246{
247 for (int i=0; i<cb->count(); i++) {
248 if ( cb->text(i) == s ) {
249 cb->setCurrentItem(i);
250 return;
251 }
252 }
253}
254
255void PackageManager::updatePackageList()
256{
257 disconnect(section,SIGNAL(activated(int)),this,SLOT(updatePackageList()));
258 disconnect(subsection,SIGNAL(activated(int)),this,SLOT(updatePackageList()));
259
260 list->clear();
261 QString cursection = section->currentText();
262 QString cursubsection = subsection->currentText();
263 QString all=tr("All");
264 if ( cursection == all ) cursection=QString::null;
265 if ( cursubsection == all ) cursubsection=QString::null;
266 section->clear();
267 subsection->clear();
268
269 QDict<void> sections;
270 QDict<void> subsections;
271 QDict<void> installed;
272
273 QRegExp separatorRegExp( ":[\t ]+" );
274
275 QString status = ipkgStatusOutput();
276 if ( !status.isEmpty() ) {
277 QStringList lines = QStringList::split('\n',status,TRUE);
278 QString name;
279 QString status;
280 for (QStringList::Iterator it = lines.begin(); it!=lines.end(); ++it) {
281 QString line = *it;
282 if ( line.length()<=1 ) {
283 // EOR
284 if ( !name.isEmpty() ) {
285 if ( status.contains(" installed") )
286 installed.replace(name,(void*)1);
287 name="";
288 }
289 status="";
290 } else if ( line[0] == ' ' || line[0] == '\t' ) {
291 // continuation
292 } else {
293 int sep = line.find(separatorRegExp);
294 if ( sep >= 0 ) {
295 QString tag = line.left(sep);
296 if ( tag == "Package" ) {
297 name = line.mid(sep+2).simplifyWhiteSpace();
298 } else if ( tag == "Status" ) {
299 status = line.mid(sep+1);
300 }
301 }
302 }
303 }
304 }
305
306 QString info = ipkgInfoOutput();
307 if ( !info.isEmpty() ) {
308 QStringList lines = QStringList::split('\n',info,TRUE);
309 QString description_short;
310 QString name;
311 QString size;
312 QString sec;
313 for (QStringList::Iterator it = lines.begin(); it!=lines.end(); ++it) {
314 QString line = *it;
315 if ( line.length()<=1 ) {
316 // EOR
317 if ( !name.isEmpty() ) {
318 int sl = sec.find('/');
319 QString s = sl < 0 ? sec : sec.left(sl);
320 QString ss = sl < 0 ? QString::null : sec.mid(sl+1);
321 sections.replace(s,(void*)1);
322 if ( cursection.isNull()
323 || cursection == s
324 && (cursubsection.isNull() || cursubsection == ss) )
325 {
326 if ( !cursection.isNull() && !ss.isNull() )
327 subsections.replace(ss,(void*)1);
328 description_short[0] = description_short[0].upper();
329 if ( description_short.left(4) == "The " )
330 description_short = description_short.mid(4);
331 if ( description_short.left(2) == "A " )
332 description_short = description_short.mid(2);
333 description_short[0] = description_short[0].upper();
334 new PackageItem(list,name,description_short,size,
335 installed.find(name));
336 }
337 installed.remove( name );
338 }
339 name="";
340 size="";
341 sec="main";
342 } else if ( line[0] == ' ' || line[0] == '\t' ) {
343 // continuation
344 } else {
345 int sep = line.find(separatorRegExp);
346 if ( sep >= 0 ) {
347 QString tag = line.left(sep);
348 if ( tag == "Package" ) {
349 name = line.mid(sep+2).simplifyWhiteSpace();
350 } else if ( tag == "Description" ) {
351 description_short = line.mid(sep+2).simplifyWhiteSpace();
352 } else if ( tag == "Installed-Size" ) {
353 size = line.mid(sep+2).simplifyWhiteSpace();
354 } else if ( tag == "Section" ) {
355 sec = line.mid(sep+2).simplifyWhiteSpace();
356 }
357 }
358 }
359 }
360 if ( installed.count() && cursection.isNull() ) {
361 // we have some packages without description
362 QDictIterator<void> it( installed );
363 for( ; it.current(); ++it )
364 new PackageItem( list, it.currentKey(), "", "?" , TRUE );
365 }
366
367 QStringList s;
368 QDictIterator<void> it( sections );
369 for( ; it.current(); ++it )
370 s.append(it.currentKey());
371 s.sort();
372 section->insertItem(all);
373 section->insertStringList(s);
374 selectComboItem(section,cursection.isNull()?all:cursection);
375 if ( cursection.isNull() ) {
376 subsection->setEnabled(FALSE);
377 } else {
378 subsection->setEnabled(TRUE);
379 QStringList s;
380 QDictIterator<void> it( subsections );
381 for( ; it.current(); ++it )
382 s.append(it.currentKey());
383 s.sort();
384 subsection->insertItem(all);
385 subsection->insertStringList(s);
386 selectComboItem(subsection,cursubsection.isNull()?all:cursubsection);
387 }
388 } else {
389 new QListViewItem(list,"ERROR");
390 }
391
392 connect(section,SIGNAL(activated(int)),SLOT(updatePackageList()));
393 connect(subsection,SIGNAL(activated(int)),this,SLOT(updatePackageList()));
394}
395
396PackageItem* PackageManager::current() const
397{
398 return (PackageItem*)list->currentItem();
399}
400
401/*
402 * public slot
403 */
404void PackageManager::doCurrentDetails(bool multi)
405{
406 PackageItem* pit = current();
407 if ( pit ) {
408 if ( !details ) {
409 details = new PackageDetails;
410 connect( details->install, SIGNAL(clicked()),
411 this, SLOT(installCurrent()));
412 connect( details->remove, SIGNAL(clicked()),
413 this, SLOT(removeCurrent()));
414 details->description->setTextFormat(RichText);
415 }
416 if ( multi ) {
417 disconnect( details->ignore, SIGNAL(clicked()),
418 details, SLOT(close()));
419 connect( details->ignore, SIGNAL(clicked()),
420 this, SLOT(doNextDetails()));
421 } else {
422 disconnect( details->ignore, SIGNAL(clicked()),
423 this, SLOT(doNextDetails()));
424 connect( details->ignore, SIGNAL(clicked()),
425 details, SLOT(close()));
426 }
427 pit->setSelected(FALSE);
428 details->setCaption("Package: " + pit->name());
429 details->description->setText(fullDetails(pit->name()));
430 details->install->setEnabled(!pit->isInstalled());
431 details->remove->setEnabled(pit->isInstalled());
432 details->showMaximized();
433 }
434}
435
436void PackageManager::doDetails()
437{
438 doCurrentDetails(FALSE);
439}
440
441void PackageManager::doNextDetails()
442{
443 QListViewItem* i = list->firstChild();
444 for ( ; i; i = i->nextSibling() ) {
445 if ( i->isSelected() )
446 break;
447 }
448 list->setCurrentItem(i);
449 if ( i ) {
450 doCurrentDetails(TRUE);
451 } else if ( details )
452 details->close();
453}
454
455QString PackageManager::fullDetails(const QString& pk)
456{
457 QString status;
458 Process ipkg_status(QStringList() << "ipkg" << "info" << pk);
459 if ( ipkg_status.exec("",status) ) {
460 QStringList lines = QStringList::split('\n',status,TRUE);
461 QString description;
462 for (QStringList::Iterator it = lines.begin(); it!=lines.end(); ++it) {
463 QString line = *it;
464 if ( line == " ." ) {
465 description.append("<p>");
466 } else if ( line[0] == ' ' || line[0] == '\t' ) {
467 // continuation
468 description.append(" ");
469 description.append(Qtopia::escapeString(line));
470 } else {
471 int sep = line.find(QRegExp(":[\t ]+"));
472 if ( sep >= 0 ) {
473 QString tag = line.left(sep);
474 description.append("<br>");
475 description.append("<b>");
476 description.append(Qtopia::escapeString(tag));
477 description.append(":</b> ");
478 description.append(Qtopia::escapeString(line.mid(sep+2)));
479 } else {
480 description.append(" ");
481 description.append(Qtopia::escapeString(line));
482 }
483 }
484 }
485 return description;
486 }
487
488 return QString::null;
489}
490
491void PackageManager::installCurrent()
492{
493 current()->setOn(TRUE);
494 details->close();
495}
496
497void PackageManager::removeCurrent()
498{
499 current()->setOn(TRUE);
500 details->close();
501}
502
503bool PackageManager::readIpkgConfig(const QString& conffile)
504{
505 QFile conf(conffile);
506 if ( conf.open(IO_ReadOnly) ) {
507 QTextStream s(&conf);
508 settings->servers->clear();
509 serverurl.clear();
510 ipkg_old=0;
511 int currentserver=0;
512 while ( !s.atEnd() ) {
513 QString l = s.readLine();
514 QStringList token = QStringList::split(' ', l);
515 if ( token[0] == "src" || token[0] == "#src" ) {
516 currentserver=settings->servers->count();
517 serverurl.insert(settings->servers->count(),new QString(token[2]));
518 int a = token[0] == "src" ? 1 : 0;
519 int i = settings->servers->count();
520 settings->servers->insertItem(token[1]);
521 settings->servers->setSelected(i,a);
522 } else if ( token[0] == "dest" ) {
523 // needs UI
524 } else if ( token[0] == "option" ) {
525 // ### somehow need to use the settings from netsetup
526 // if ( token[1] == "http_proxy" )
527 // settings->http->setText(token[2]);
528 // else if ( token[1] == "ftp_proxy" )
529 // settings->ftp->setText(token[2]);
530 // else if ( token[1] == "proxy_username" )
531 // settings->username->setText(token[2]);
532 // else if ( token[1] == "proxy_password" )
533 // settings->password->setText(token[2]);
534 } else {
535 // Old style?
536 int eq = l.find('=');
537 if ( eq >= 0 ) {
538 QString v = l.mid(eq+1).stripWhiteSpace();
539 if ( v[0] == '"' || v[0] == '\'' ) {
540 int cl=v.find(v[0],1);
541 if ( cl >= 0 )
542 v = v.mid(1,cl-1);
543 }
544 if ( l.left(12) == "IPKG_SOURCE=" ) {
545 ipkg_old=1;
546 currentserver=settings->servers->count();
547 serverurl.insert(settings->servers->count(),new QString(v));
548 settings->servers->insertItem(v);
549 } else if ( l.left(13) == "#IPKG_SOURCE=" ) {
550 serverurl.insert(settings->servers->count(),new QString(v));
551 settings->servers->insertItem(v);
552 } else if ( l.left(10) == "IPKG_ROOT=" ) {
553 // ### no UI
554 // } else if ( l.left(20) == "IPKG_PROXY_USERNAME=" ) {
555 // settings->username->setText(v);
556 // } else if ( l.left(20) == "IPKG_PROXY_PASSWORD=" ) {
557 // settings->password->setText(v);
558 // } else if ( l.left(16) == "IPKG_PROXY_HTTP=" ) {
559 // settings->http->setText(v);
560 // } else if ( l.left(16) == "IPKG_PROXY_FTP=" ) {
561 // settings->ftp->setText(v);
562 }
563 }
564 }
565 }
566 if ( ipkg_old ) {
567 settings->servers->setSelectionMode(QListBox::Single);
568 settings->servers->setSelected(currentserver,TRUE);
569 }
570 return TRUE;
571 } else {
572 return FALSE;
573 }
574}
575
576/*
577 * public slot
578 */
579void PackageManager::doSettings()
580{
581 settings->showMaximized();
582 if ( settings->exec() ) {
583 writeSettings();
584 startRun();
585 runIpkg("update");
586 endRun();
587 updatePackageList();
588 } else {
589 readSettings();
590 }
591}
592
593void PackageManager::readSettings()
594{
595 // read from config file(s)
596 readIpkgConfig("/etc/ipkg.conf");
597}
598
599void PackageManager::writeSettings()
600{
601 QFile conf("/etc/ipkg.conf");
602 if ( conf.open(IO_WriteOnly) ) {
603 QTextStream s(&conf);
604 s << "# Written by Qtopia Package Manager\n";
605 if ( !ipkg_old ) {
606 for (int i=0; i<(int)settings->servers->count(); i++) {
607 QString url = serverurl[i] ? *serverurl[i] : QString("???");
608 if ( !settings->servers->isSelected(i) )
609 s << "#";
610 s << "src " << settings->servers->text(i) << " " << url << "\n";
611 }
612 s << "dest root /\n"; // ### need UI
613 // if ( !settings->username->text().isEmpty() )
614 // s << "option proxy_username " << settings->username->text() << "\n";
615 // if ( !settings->password->text().isEmpty() )
616 // s << "option proxy_password " << settings->password->text() << "\n";
617 // if ( !settings->http->text().isEmpty() )
618 // s << "option http_proxy " << settings->http->text() << "\n";
619 // if ( !settings->ftp->text().isEmpty() )
620 // s << "option ftp_proxy " << settings->ftp->text() << "\n";
621 } else {
622 // Old style
623 bool src_selected=FALSE;
624 for (int i=0; i<(int)settings->servers->count(); i++) {
625 if ( settings->servers->isSelected(i) ) {
626 src_selected=TRUE;
627 } else {
628 s << "#";
629 }
630 s << "IPKG_SOURCE=\"" << settings->servers->text(i) << "\"\n";
631 }
632 if ( !src_selected )
633 s << "IPKG_SOURCE=\"" << settings->servers->currentText() << "\"\n";
634 s << "IPKG_ROOT=/\n"
635 // << "IPKG_PROXY_USERNAME=\"" << settings->username->text() << "\"\n"
636 // << "IPKG_PROXY_PASSWORD=\"" << settings->password->text() << "\"\n"
637 // << "IPKG_PROXY_HTTP=\"" << settings->http->text() << "\"\n"
638 // << "IPKG_PROXY_FTP=\"" << settings->ftp->text() << "\"\n"
639 ;
640 }
641 conf.close();
642 }
643}
644
645/*
646 * public slot
647 */
648void PackageManager::doFind()
649{
650 Search s(this, 0, TRUE);
651 if ( s.exec() ) {
652 QString p = s.pattern->text();
653 if ( p.isEmpty() ) {
654 list->selectAll(FALSE);
655 } else {
656 selectPackages(findPackages(p));
657 doNextDetails();
658 }
659 }
660}
661
662void PackageManager::selectPackages( const QStringList& l )
663{
664 QDict<void> d;
665 for (QStringList::ConstIterator it = l.begin(); it != l.end(); ++it)
666 d.replace(*it,(void*)1);
667 QListViewItem* i;
668 for ( i = list->firstChild(); i; i = i->nextSibling() ) {
669 PackageItem* pit = (PackageItem*)i;
670 i->setSelected( d[pit->name()] );
671 }
672}
673
674QStringList PackageManager::findPackages( const QRegExp& r )
675{
676 QStringList matches;
677
678 QString info = ipkgInfoOutput();
679 if ( !info.isEmpty() ) {
680 QStringList lines = QStringList::split('\n',info,TRUE);
681 QRegExp re = r;
682 QString description="";
683 QString name;
684 for (QStringList::Iterator it = lines.begin(); it!=lines.end(); ++it) {
685 QString line = *it;
686 if ( line.length()<=1 ) {
687 // EOR
688 if ( re.match(description) >= 0 )
689 matches.append(name);
690 description="";
691 name="";
692 } else if ( line[0] == ' ' || line[0] == '\t' ) {
693 // continuation
694 description.append(" ");
695 description.append(Qtopia::escapeString(line));
696 } else {
697 int sep = line.find(QRegExp(":[\t ]+"));
698 if ( sep >= 0 ) {
699 QString tag = line.left(sep);
700 if ( tag == "Package" )
701 name = line.mid(sep+2).simplifyWhiteSpace();
702 if ( !description.isEmpty() )
703 description.append("<br>");
704 description.append("<b>");
705 description.append(Qtopia::escapeString(tag));
706 description.append(":</b> ");
707 description.append(Qtopia::escapeString(line.mid(sep+2)));
708 }
709 }
710 }
711 }
712
713 return matches;
714}
715
716/*
717 * public slot
718 */
719void PackageManager::doUpgrade()
720{
721 startMultiRun(2);
722 runIpkg("update");
723 runIpkg("upgrade");
724 updatePackageList();
725 endRun();
726}
727
728
729void PackageManager::doIt()
730{
731 bool ok = commitWithIpkg();
732 updatePackageList(); // things may have changed
733 if (!ok) qApp->beep();
734}
735
736bool PackageManager::commitWithIpkg()
737{
738 // A full implementation would do the following, but we'll just do
739 // it simply and non-interactively for now.
740 //
741 // setenv IPKG_CONF_DIR for a null $IPKG_CONF_DIR/ipkg.conf
742 // setenv IPKG_SOURCE, IPKG_ROOT, etc.
743 // run ipkg, processing interactivity as dialogs
744 // - "... (Y/I/N/O/D) [default=N] ?" -> ...
745 // - "[Press ENTER to continue]" (if D chosen above)
746 // - "The following packages are marked `Essential'... Install them now [Y/n] ?"
747 // - "The following packages...ready to be installed:... Install them now [Y/n] ?"
748 // return FALSE cancelled
749
750 QStringList to_remove, to_install;
751
752 for ( QListViewItem* i = list->firstChild(); i; i = i->nextSibling() ) {
753 PackageItem* pit = (PackageItem*)i;
754 if ( pit->isOn() ) {
755 if ( pit->isInstalled() )
756 to_remove.append(pit->name());
757 else
758 to_install.append(pit->name());
759 }
760 }
761
762 bool ok=TRUE;
763
764 int jobs = to_remove.count()+to_install.count();
765 if ( jobs ) {
766 startMultiRun(jobs);
767
768 if ( to_remove.count() ) {
769 for (QStringList::ConstIterator it=to_remove.begin(); it!=to_remove.end(); ++it) {
770 if ( runIpkg("remove " + *it) != 0 ) {
771 ok = FALSE;
772 }
773 }
774 }
775 if ( to_install.count() ) {
776 for (QStringList::ConstIterator it=to_install.begin(); it!=to_install.end(); ++it) {
777 if ( runIpkg("install " + *it) != 0 ) {
778 ok = FALSE;
779 }
780 }
781 }
782
783 // ##### If we looked in the list of files, we could send out accurate
784 // ##### messages. But we don't bother yet, and just do an "all".
785 QCopEnvelope e("QPE/System", "linkChanged(QString)");
786 QString lf = QString::null;
787 e << lf;
788
789#if QT_VERSION > 230 // a bug breaks this otherwise
790 if ( !ok )
791 QMessageBox::warning(this, "Error", "<p><tt>ipkg</tt> says something went wrong. Sorry.");
792#endif
793
794 endRun();
795 }
796
797 return ok;
798}
799
800QString PackageManager::ipkgStatusOutput()
801{
802 if ( cachedIpkgStatusOutput.isEmpty() ) {
803 Process ipkg_status( QStringList() << "ipkg" << "status" );
804 ipkg_status.exec( 0, cachedIpkgStatusOutput );
805 }
806 return QString::fromLocal8Bit( cachedIpkgStatusOutput );
807}
808
809QString PackageManager::ipkgInfoOutput()
810{
811 if ( cachedIpkgInfoOutput.isEmpty() ) {
812 Process ipkg_info( QStringList() << "ipkg" << "info" );
813 ipkg_info.exec( 0, cachedIpkgInfoOutput );
814 }
815 return QString::fromLocal8Bit( cachedIpkgInfoOutput );
816}
817
818void PackageManager::setCachedIpkgOutputDirty()
819{
820 cachedIpkgInfoOutput = cachedIpkgStatusOutput = QString::null;
821}
822
823void PackageManager::startMultiRun(int jobs)
824{
825 startRun();
826 progress->setTotalSteps(jobs);
827 progress->setProgress(0);
828}
829
830void PackageManager::startRun()
831{
832 progress->show();
833 doit->hide();
834}
835
836void PackageManager::endRun()
837{
838 doit->show();
839 progress->hide();
840}
841
842int PackageManager::runIpkg(const QString& args)
843{
844 if ( progress->progress() == -1 )
845 startMultiRun(1);
846 else
847 startRun();
848 QString cmd = "ipkg ";
849 if ( ipkg_old )
850 cmd += "</dev/null ";
851 else
852 cmd += "-force-defaults ";
853 int r = system((cmd+args).latin1());
854 progress->setProgress(progress->progress()+1);
855 setCachedIpkgOutputDirty();
856 endRun();
857 return r;
858}
859
860// simple hack to get support for ipkg mimetype
861void PackageManager::maybeInstall( const QString &ipk )
862{
863 int pos = ipk.findRev( "/" );
864 QString package = ipk.mid( pos + 1 );
865 pos = package.find ( "_" );
866 if ( pos != -1 )
867 package = package.left( pos );
868 switch ( QMessageBox::information( 0, tr( "Install Package" ),
869 tr("Are you sure you want to\ninstall package\n\n%1")
870 .arg(package), QMessageBox::Yes,
871 QMessageBox::No|QMessageBox::Default|QMessageBox::Escape, 0 ) ) {
872 case QMessageBox::Yes: {
873 startRun();
874 runIpkg("install " + ipk );
875 QCopEnvelope e("QPE/System", "linkChanged(QString)");
876 QString lf = QString::null;
877 e << lf;
878 endRun();
879 }
880 break;
881 case QMessageBox::No:
882 default:
883 // do nothing
884 break;
885 }
886}
887
888void PackageManager::setDocument(const QString& fileref)
889{
890 if ( fileref.isNull() )
891 return;
892 DocLnk doc( fileref );
893 if ( doc.file().isEmpty() )
894 return;
895 maybeInstall( doc.file() );
896 updatePackageList();
897}