source: src-qt4/pc-pkgmanager/mainWin.cpp @ a43929d

9.1-release9.2-releasereleng/10.0releng/10.0.1
Last change on this file since a43929d was a43929d, checked in by Kris Moore <kris@…>, 12 months ago

Add maintainer / weburl to fields we pull out of repo db

  • Property mode set to 100644
File size: 34.4 KB
Line 
1/****************************************************************************
2** ui.h extension file, included from the uic-generated form implementation.
3**
4** If you want to add, delete, or rename functions or slots, use
5** Qt Designer to update this file, preserving your code.
6**
7** You should not define a constructor or destructor in this file.
8** Instead, write your code in functions called init() and destroy().
9** These will automatically be called by the form's constructor and
10** destructor.
11*****************************************************************************/
12#include <fcntl.h>
13#include <QDateTime>
14#include <QDebug>
15#include <QDir>
16#include <QProcess>
17#include <QProgressDialog>
18#include <QSocketNotifier>
19#include <QString>
20#include <QTextStream>
21#include <pcbsd-utils.h>
22#include <pcbsd-ui.h>
23#include <QSettings>
24#include "mainWin.h"
25#include "../config.h"
26
27void mainWin::ProgramInit(QString ch)
28{
29  // Set any warden directories
30  lastError="";
31  wDir = ch;
32
33  //Grab the username
34  //username = QString::fromLocal8Bit(getenv("LOGNAME"));
35  connect(pushUpdatePkgs, SIGNAL(clicked()), this, SLOT(slotUpdatePkgsClicked()));
36  connect(pushClose, SIGNAL(clicked()), this, SLOT(slotCloseClicked()));
37  connect(buttonRescanPkgs, SIGNAL(clicked()), this, SLOT(slotRescanPkgsClicked()));
38  connect(pushPkgApply, SIGNAL( clicked() ), this, SLOT( slotApplyClicked() ) );
39  connect(action_Quit, SIGNAL( triggered(bool) ), this, SLOT( slotCloseClicked() ) );
40  connect(action_Basic, SIGNAL( triggered(bool) ), this, SLOT( slotViewChanged() ) );
41  connect(action_Advanced, SIGNAL( triggered(bool) ), this, SLOT( slotViewChanged() ) );
42
43  // Setup the action group
44  viewGroup = new QActionGroup(this);
45  viewGroup->addAction(action_Basic);
46  viewGroup->addAction(action_Advanced);
47
48  treeMetaPkgs->setContextMenuPolicy(Qt::CustomContextMenu);
49  connect(treeMetaPkgs, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(slotMetaRightClick()) );
50
51  QTimer::singleShot(200, this, SLOT(slotRescanPkgsClicked() ) );
52
53  QSettings settings("PC-BSD", "PackageManager");
54  QString curMode = settings.value("view/mode").toString();
55  if ( curMode == "Advanced" )
56  {
57     stackedPkgView->setCurrentIndex(1);
58     action_Basic->setChecked(false);
59     action_Advanced->setChecked(true);
60  }
61
62  // If we are running on a chroot, only do advanced mode
63  if ( !wDir.isEmpty() )
64  {
65     stackedPkgView->setCurrentIndex(1);
66     action_Advanced->setChecked(true);
67     menu_View->setEnabled(false);
68     menu_View->setVisible(false);
69  }
70
71  initMetaWidget();
72}
73
74void mainWin::slotViewChanged()
75{
76  QString mode;
77  if ( action_Basic->isChecked() ) {
78    stackedPkgView->setCurrentIndex(0);
79    mode="Basic";
80  } else {
81    mode="Advanced";
82    stackedPkgView->setCurrentIndex(1);
83  }
84
85  // Save the mode as the default at next open
86  QSettings settings("PC-BSD", "PackageManager");
87  settings.setValue("view/mode", mode);
88
89  // Changed view, lets refresh
90  initMetaWidget();
91}
92
93void mainWin::slotRescanPkgsClicked()
94{
95  // Check for pkg updates
96  checkMPKGUpdates();
97}
98
99void mainWin::slotApplyClicked() {
100  // Running in basic mode
101  if ( stackedPkgView->currentIndex() == 0 )
102  {
103     saveMetaPkgs();   
104  } else {
105     // Running in advanced mode
106     applyNGChanges();
107  }
108
109}
110
111void mainWin::checkMPKGUpdates() {
112
113  QString line, tmp, name, pkgname, pkgover, pkgnver;
114  QStringList up, listPkgs;
115  bool haveUpdates = false;
116  int totPkgs=0;
117  buttonRescanPkgs->setEnabled(false);
118  pushUpdatePkgs->setEnabled(false);
119  listViewUpdatesPkgs->clear();
120  groupUpdatesPkgs->setTitle(tr("Checking for updates"));
121
122  QProcess p;
123  if ( wDir.isEmpty() )
124     p.start(QString("pc-updatemanager"), QStringList() << "pkgcheck");
125  else
126     p.start(QString("chroot"), QStringList() << wDir << "pc-updatemanager" << "pkgcheck");
127  while(p.state() == QProcess::Starting || p.state() == QProcess::Running)
128     QCoreApplication::processEvents();
129
130  while (p.canReadLine()) {
131    line = p.readLine().simplified();
132    qDebug() << line;
133    if ( line.indexOf("Upgrading") != 0) {
134       continue;
135    }
136    tmp = line;
137    pkgname = tmp.section(" ", 1, 1);
138    pkgname.replace(":", "");
139    pkgover = tmp.section(" ", 2, 2);
140    pkgnver = tmp.section(" ", 4, 4);
141    QTreeWidgetItem *myItem = new QTreeWidgetItem(QStringList() << pkgname << pkgover << pkgnver);
142    listViewUpdatesPkgs->addTopLevelItem(myItem);
143    haveUpdates = true;
144    totPkgs++;
145  }
146
147  buttonRescanPkgs->setEnabled(true);
148  pushUpdatePkgs->setEnabled(haveUpdates);
149  if ( totPkgs > 0 ) {
150    tabUpdates->setTabText(1, tr("Package Updates (%1)").arg(totPkgs));
151    groupUpdatesPkgs->setTitle(tr("Available updates"));
152  } else {
153    tabUpdates->setTabText(1, tr("Package Updates"));
154    groupUpdatesPkgs->setTitle(tr("No available updates"));
155  }
156 
157}
158
159void mainWin::slotSingleInstance() {
160   this->hide();
161   this->showNormal();
162   this->activateWindow();
163   this->raise();
164}
165
166void mainWin::slotCloseClicked() {
167   close();
168}
169
170void mainWin::slotUpdatePkgsClicked() {
171  dPackages = false;
172  uPackages = false;
173
174  // Init the pkg process
175  prepPkgProcess();
176
177  // Create our runlist of package commands
178  QStringList pCmds;
179
180  if ( wDir.isEmpty() )
181    pCmds << "pc-updatemanager" << "pkgupdate";
182  else
183    pCmds << "chroot" << wDir << "pc-updatemanager" << "pkgupdate";
184
185  // Setup our runList
186  pkgCmdList << pCmds;
187
188  // Start the updating now
189  startPkgProcess();
190
191  textStatus->setText(tr("Starting package updates..."));
192
193}
194
195QString mainWin::getConflictDetailText() {
196
197  QStringList ConList = ConflictList.split(" ");
198  QStringList tmpDeps;
199  QString retText;
200
201  for (int i = 0; i < ConList.size(); ++i) {
202    QProcess p;
203    tmpDeps.clear();
204
205    if ( wDir.isEmpty() )
206      p.start("pkg", QStringList() << "rquery" << "%rn-%rv" << ConList.at(i));
207    else
208      p.start("chroot", QStringList() << wDir << "pkg" "rquery" << "%rn-%rv" << ConList.at(i) );
209
210    if(p.waitForFinished()) {
211      while (p.canReadLine()) {
212        tmpDeps << p.readLine().simplified();
213      }
214    }
215    retText+= ConList.at(i) + " " + tr("required by:") + "\n" + tmpDeps.join(" ");
216  }
217
218  return retText;
219}
220
221void mainWin::prepPkgProcess() {
222  pkgCmdList.clear();
223  textDisplayOut->clear();
224  pkgHasFailed=false;
225}
226
227void mainWin::startPkgProcess() {
228
229  if ( pkgCmdList.isEmpty() )
230    return;
231  if ( pkgCmdList.at(0).at(0).isEmpty() )
232     return; 
233
234  // Get the command name
235  QString cmd;
236  cmd = pkgCmdList.at(0).at(0);
237
238  // Get any optional flags
239  QStringList flags;
240  for (int i = 0; i < pkgCmdList.at(0).size(); ++i) {
241     if ( i == 0 )
242       continue;
243     flags << pkgCmdList.at(0).at(i);
244  } 
245
246  qDebug() << cmd + " " + flags.join(" ");
247 
248  // Setup the first process
249  uProc = new QProcess();
250  QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
251  env.insert("PCFETCHGUI", "YES");
252  uProc->setProcessEnvironment(env);
253  uProc->setProcessChannelMode(QProcess::MergedChannels);
254
255  // Connect the slots
256  connect( uProc, SIGNAL(readyReadStandardOutput()), this, SLOT(slotReadPkgOutput()) );
257  connect( uProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotPkgDone()) );
258
259  uProc->start(cmd, flags);
260
261  stackedTop->setCurrentIndex(1);
262
263  progressUpdate->setRange(0, 0 );
264  progressUpdate->setValue(0);
265
266}
267
268void mainWin::slotReadPkgOutput() {
269   QString line, tmp, cur, tot, fname;
270
271   while (uProc->canReadLine()) {
272     line = uProc->readLine().simplified();
273     qDebug() << line;
274
275     tmp = line;
276     tmp.truncate(50);
277
278     // Flags we can parse out and not show the user
279
280     // Check if we have crashed into a conflict and ask the user what to do
281     if ( line.indexOf("PKGCONFLICTS: ") == 0 ) {
282        tmp = line; 
283        tmp.replace("PKGCONFLICTS: ", "");
284        ConflictList = tmp;
285        continue;
286     }
287     if ( line.indexOf("PKGREPLY: ") == 0 ) {
288        QString ans;
289        tmp = line; 
290        tmp.replace("PKGREPLY: ", "");
291        QMessageBox msgBox;
292        msgBox.setText(tr("The following packages are causing conflicts with the selected changes and can be automatically removed. Continue?") + "\n" + ConflictList);
293        msgBox.setStandardButtons(QMessageBox::Yes|QMessageBox::No);
294        msgBox.setDetailedText(getConflictDetailText());
295        msgBox.setDefaultButton(QMessageBox::No);
296        if ( msgBox.exec() == QMessageBox::Yes) {
297          // We will try to fix conflicts
298          ans="yes";
299        } else {
300          // We will fail :(
301          QMessageBox::warning(this, tr("Package Conflicts"),
302          tr("You may need to manually fix the conflicts before trying again."),
303          QMessageBox::Ok,
304          QMessageBox::Ok);
305          ans="no";
306        }
307
308        QFile pkgTrig( tmp );
309        if ( pkgTrig.open( QIODevice::WriteOnly ) ) {
310           QTextStream streamTrig( &pkgTrig );
311           streamTrig << ans;
312           pkgTrig.close();
313        }
314        continue;
315     }
316
317     if ( line.indexOf("FETCH: ") == 0 ) { 
318        progressUpdate->setValue(progressUpdate->value() + 1); 
319        tmp = line; 
320        tmp = tmp.remove(0, tmp.lastIndexOf("/") + 1); 
321        progressUpdate->setRange(0, 0);
322        progressUpdate->setValue(0);
323        curFileText = tr("Downloading: %1").arg(tmp); 
324        textStatus->setText(tr("Downloading: %1").arg(tmp)); 
325        continue;
326     } 
327     if ( line.indexOf("FETCHDONE") == 0 )
328        continue;
329
330     if ( line.indexOf("SIZE: ") == 0 ) {
331          bool ok, ok2;
332          line.replace("SIZE: ", "");
333          line.replace("DOWNLOADED: ", "");
334          line.replace("SPEED: ", "");
335          line.section(" ", 0, 0).toInt(&ok);
336          line.section(" ", 1, 1).toInt(&ok2);
337   
338          if ( ok && ok2 ) {
339            QString unit;
340            int tot = line.section(" ", 0, 0).toInt(&ok);
341            int cur = line.section(" ", 1, 1).toInt(&ok2);
342            QString percent = QString::number( (float)(cur * 100)/tot );
343            QString speed = line.section(" ", 2, 3);
344
345            // Get the MB downloaded / total
346            if ( tot > 2048 ) {
347              unit="MB";
348              tot = tot / 1024;
349              cur = cur / 1024;
350            } else {
351              unit="KB";
352            }
353
354            QString ProgressString=QString("(%1" + unit + " of %2" + unit + " at %3)").arg(cur).arg(tot).arg(speed);
355            progressUpdate->setRange(0, tot);
356            progressUpdate->setValue(cur);
357            textStatus->setText(curFileText + " " + ProgressString); 
358         }
359         continue;
360     }
361
362
363     // Now show output on GUI
364     textDisplayOut->insertPlainText(line + "\n");
365     textDisplayOut->moveCursor(QTextCursor::End);
366
367
368     // Any other flags to look for?
369     /////////////////////////////////////////////////////
370     if ( line.indexOf("to be downloaded") != -1 ) {
371       textStatus->setText(tr("Downloading packages..."));
372       curUpdate = 0;
373       progressUpdate->setValue(0);
374       continue;
375     }
376     if ( line.indexOf("Checking integrity") == 0 ) {
377       textStatus->setText(line);
378       uPackages = true;
379       dPackages = false;
380       curUpdate = 0;
381       progressUpdate->setValue(0);
382     }
383     
384     if ( uPackages ) {
385       if ( line.indexOf("Upgrading") == 0 ) {
386         textStatus->setText(line);
387         curUpdate++;
388         progressUpdate->setValue(curUpdate);
389       }
390       continue;
391     }
392
393   } // end of while
394}
395
396void mainWin::slotPkgDone() {
397
398  if ( uProc->exitCode() != 0 )
399    pkgHasFailed=true;
400
401  // Run the next command on the stack if necessary
402  if (  pkgCmdList.size() > 1 ) {
403        pkgCmdList.removeAt(0); 
404        startPkgProcess();     
405        return;
406  }
407
408  // Nothing left to run! Lets wrap up
409  QFile sysTrig( SYSTRIGGER );
410  if ( sysTrig.open( QIODevice::WriteOnly ) ) {
411    QTextStream streamTrig( &sysTrig );
412     streamTrig << "INSTALLFINISHED: ";
413  }
414
415  if ( pkgHasFailed ) {
416    QFile file( "/tmp/pkg-output.log" );
417    if ( file.open( QIODevice::WriteOnly ) ) {
418       QTextStream stream( &file );
419       stream << textDisplayOut->toPlainText();
420       file.close();
421    }
422    QMessageBox::warning(this, tr("Failed!"), tr("The package commands failed. A copy of the output was saved to /tmp/pkg-output.log"));
423  } else
424    QMessageBox::warning(this, tr("Finished!"), tr("Package changes complete!" ));
425
426  // Clear out the old commands
427  pkgCmdList.clear();
428
429  // Switch back to our main display
430  stackedTop->setCurrentIndex(0);
431
432  // Re-init the meta-widget
433  initMetaWidget();
434
435}
436
437/*****************************************
438Code for package stuff
439******************************************/
440
441void mainWin::initMetaWidget()
442{
443  qDebug() << "Starting metaWidget...";
444
445  // Running in basic mode
446  if ( stackedPkgView->currentIndex() == 0 )
447  {
448    populateMetaPkgs();
449    // Connect our slots
450  } else {
451    // Running in advanced mode
452    populateNGPkgs();
453  }
454}
455
456void mainWin::populateNGPkgs()
457{
458  pushPkgApply->setEnabled(false);
459  treeNGPkgs->clear();
460  tmpPkgList.clear();
461  new QTreeWidgetItem(treeNGPkgs, QStringList() << tr("Loading... Please wait...") );
462
463  if ( ! pkgList.isEmpty() )
464        disconnect(treeNGPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), 0, 0);
465  pkgList.clear();
466  selPkgList.clear();
467
468  // Start the process to get meta-pkg info
469  getNGProc = new QProcess();
470  qDebug() << "Searching for pkgs...";
471  connect( getNGProc, SIGNAL(readyReadStandardOutput()), this, SLOT(slotGetNGPackageDataOutput()) );
472  connect( getNGProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotGetNGInstalledPkgs()) );
473  getNGProc->setProcessChannelMode(QProcess::MergedChannels);
474  if ( wDir.isEmpty() )
475    getNGProc->start(QString("pkg"), QStringList() << "rquery" << "-a" << "%o:::%n-%v:::%c:::%sh:::%m:::%w");
476  else
477    getNGProc->start(QString("chroot"), QStringList() << wDir << "pkg" << "rquery" << "-a" << "%o:::%n-%v:::%c:::%sh:::%m:::%w");
478
479}
480
481void mainWin::slotGetNGPackageDataOutput()
482{
483   while (getNGProc->canReadLine())
484     tmpPkgList << getNGProc->readLine().simplified();
485}
486
487void mainWin::slotGetNGInstalledDataOutput()
488{
489   while (getNGProc->canReadLine())
490     pkgList << getNGProc->readLine().simplified();
491}
492
493void mainWin::slotGetNGInstalledPkgs() {
494
495  qDebug() << "Building dependancy lists...";
496  QProcess p;
497  pkgDepList.clear();
498  if ( wDir.isEmpty() )
499    p.start("pkg", QStringList() << "rquery" << "-a" << "%n-%v:::%dn-%dv");
500  else
501    p.start("chroot", QStringList() << wDir << "pkg" << "rquery" << "-a" << "%n-%v:::%dn-%dv" );
502  while(p.state() == QProcess::Starting || p.state() == QProcess::Running) {
503      p.waitForFinished(200);
504      QCoreApplication::processEvents();
505  }
506  while (p.canReadLine()) {
507    pkgDepList << p.readLine().simplified();
508  }
509
510  qDebug() << "Building reverse dependancy lists...";
511  pkgRDepList.clear();
512  if ( wDir.isEmpty() )
513    p.start("pkg", QStringList() << "rquery" << "-a" << "%n-%v:::%rn-%rv");
514  else
515    p.start("chroot", QStringList() << wDir << "pkg" << "rquery" << "-a" << "%n-%v:::%rn-%rv" );
516  while(p.state() == QProcess::Starting || p.state() == QProcess::Running) {
517      p.waitForFinished(200);
518      QCoreApplication::processEvents();
519  }
520  while (p.canReadLine()) {
521    pkgRDepList << p.readLine().simplified();
522  }
523
524  getNGProc = new QProcess();
525  qDebug() << "Searching for installed pkgs...";
526  connect( getNGProc, SIGNAL(readyReadStandardOutput()), this, SLOT(slotGetNGInstalledDataOutput()) );
527  connect( getNGProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotFinishLoadingNGPkgs()) );
528  getNGProc->setProcessChannelMode(QProcess::MergedChannels);
529  if ( wDir.isEmpty() )
530    getNGProc->start(QString("pkg"), QStringList() << "info" << "-aq" );
531  else
532    getNGProc->start(QString("chroot"), QStringList() << wDir << "pkg" << "info" << "-aq");
533
534}
535
536void mainWin::slotFinishLoadingNGPkgs()
537{
538  treeNGPkgs->clear();
539
540  addNGItems();
541
542  pushPkgApply->setEnabled(false);
543
544  connect(treeNGPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotEnableApply()));
545}
546
547void mainWin::slotEnableApply()
548{
549  pushPkgApply->setEnabled(true);
550}
551
552void mainWin::addNGItems()
553{
554   QString curCat, cat, name, pkgname, desc, size, maint, weburl;
555
556   // We like to add alphabetically
557   tmpPkgList.sort();
558
559   QTreeWidgetItem *catItem;
560
561   // Lets start adding packages to the tree widget
562   for (int i = 0; i < tmpPkgList.size(); ++i) {
563        name = cat = tmpPkgList.at(i).section(":::", 0,0);
564        cat=cat.section("/", 0, 0);
565        name=name.section("/", 1, 1);
566        pkgname = tmpPkgList.at(i).section(":::", 1,1);
567        desc = tmpPkgList.at(i).section(":::", 2,2);
568        size = tmpPkgList.at(i).section(":::", 3,3);
569        maint = tmpPkgList.at(i).section(":::", 4,4);
570        weburl = tmpPkgList.at(i).section(":::", 5,5);
571
572        // Check if we need to add a top-level category
573        if ( cat != curCat )
574        {
575           qDebug() << "Adding cat: " + cat;
576           catItem = new QTreeWidgetItem(QStringList() << cat);
577           treeNGPkgs->addTopLevelItem(catItem);
578           curCat = cat;
579        }
580 
581        // Now lets create the item and attach to the category
582        QTreeWidgetItem *pkgItem = new QTreeWidgetItem();
583        pkgItem->setText(0, name + " (" + pkgname + ") - " + size );
584        pkgItem->setToolTip(0, desc);
585
586        if ( pkgList.indexOf(pkgname) != -1 ) {
587          pkgItem->setCheckState(0, Qt::Checked);
588          selPkgList << pkgname;
589        } else
590          pkgItem->setCheckState(0, Qt::Unchecked);
591 
592        catItem->addChild(pkgItem);
593   }
594
595}
596
597// Lets prompt user, and do it!
598void mainWin::applyNGChanges()
599{
600   QString tmp;
601   QStringList curPkgChecked;
602   QStringList newPkgs;
603   QStringList rmPkgs;
604
605   QTreeWidgetItemIterator it(treeNGPkgs);
606   while (*it) {
607         if ((*it)->checkState(0) == Qt::Checked) {
608           tmp = (*it)->text(0).section("(", 1, 1).section(")", 0, 0);
609           curPkgChecked << tmp;
610           if (pkgList.indexOf(tmp) == -1 ) 
611              newPkgs << tmp;
612         }
613         ++it;
614   }
615
616   for ( int i=0; i < pkgList.size(); ++i)
617      // Has this package been unchecked?
618      if (curPkgChecked.indexOf(pkgList.at(i)) == -1 )  {
619         // Make sure this is a package in the repo
620         // This filters out any custom packages the user may have loaded which may not exist in our repo
621         QRegExp rx("*" + pkgList.at(i) + "*");
622         rx.setPatternSyntax(QRegExp::Wildcard);
623         if ( tmpPkgList.indexOf(rx) != -1 )
624           rmPkgs << pkgList.at(i);
625      }
626
627   if ( rmPkgs.isEmpty() && newPkgs.isEmpty() ) {
628      QMessageBox::warning(this, tr("No changes"),
629        tr("No changes to make!"),
630        QMessageBox::Ok,
631        QMessageBox::Ok);
632      return;
633   }
634
635   qDebug() << "Added packages" << newPkgs;
636   qDebug() << "Removed packages" << rmPkgs;
637   pkgRemoveList = rmPkgs;
638   pkgAddList = newPkgs;
639
640   QString confirmText;
641
642   // Lets start creating our confirmation text
643   if ( ! rmPkgs.isEmpty() ) {
644      confirmText+=tr("The following packages will be removed:") + "\n"; 
645      confirmText+= "------------------------------------------\n";
646      confirmText+=rmPkgs.join("\n"); 
647      confirmText+= "\n\n" + tr("The following packages that require the above packages will also removed:") + "\n"; 
648      confirmText+= "------------------------------------------\n";
649      for ( int i=0; i < rmPkgs.size(); ++i) {
650         QRegExp rx(rmPkgs.at(i) + ":::*");
651         rx.setPatternSyntax(QRegExp::Wildcard);
652         QStringList rDeps = pkgRDepList.filter(rx);
653         for ( int r=0; r < rDeps.size(); ++r) {
654             QString pName = rDeps.at(r).section(":::", 1, 1); 
655             // Is this package installed?
656             if ( pkgList.indexOf(pName) != -1 )
657               confirmText+= pName + " ";
658         }
659      }
660   }
661
662   if ( ! newPkgs.isEmpty() ) {
663      if ( ! rmPkgs.isEmpty() )
664        confirmText+= "\n\n";
665      confirmText+=tr("The following packages will be installed:") + "\n"; 
666      confirmText+= "------------------------------------------\n";
667      confirmText+=newPkgs.join("\n"); 
668      confirmText+= "\n\n" + tr("The following dependances will also be installed:") + "\n"; 
669      confirmText+= "------------------------------------------\n";
670      for ( int i=0; i < newPkgs.size(); ++i) {
671         QRegExp rx(newPkgs.at(i) + ":::*");
672         rx.setPatternSyntax(QRegExp::Wildcard);
673         QStringList aDeps = pkgDepList.filter(rx);
674         for ( int r=0; r < aDeps.size(); ++r) {
675             QString pName = aDeps.at(r).section(":::", 1, 1); 
676             // Is this package installed?
677             if ( pkgList.indexOf(pName) == -1 )
678               confirmText+= pName + " ";
679         }
680      }
681   }
682
683   // Launch our AddPartitionDialog to add a new device
684   askUserConfirm = new dialogConfirm();
685   connect(askUserConfirm, SIGNAL(ok()),this, SLOT(slotStartNGChanges()) );
686   askUserConfirm->programInit(tr("Confirm package changes"));
687   askUserConfirm->setInfoText(QString(confirmText));
688   askUserConfirm->exec();
689
690}
691
692
693// Time to start doing our NG changes!
694void mainWin::slotStartNGChanges()
695{
696  // Init the pkg process
697  prepPkgProcess();
698
699  // Create our runlist of package commands
700  QStringList pCmds;
701 
702  if ( ! pkgRemoveList.isEmpty() ) {
703    if ( wDir.isEmpty() )
704      pCmds << "pkg" << "delete" << "-R" << "-y" << pkgRemoveList.join(" ");
705    else
706      pCmds << "chroot" << wDir << "pkg" << "delete" << "-R" << "-y" << pkgRemoveList.join(" ");
707    pkgCmdList << pCmds;
708  }
709         
710  pCmds.clear();
711
712  if ( ! pkgAddList.isEmpty() ) {
713    if ( wDir.isEmpty() )
714      pCmds << "pc-pkg" << "install" << "-y" << pkgAddList.join(" ");
715    else
716      pCmds << "chroot" << wDir << "pc-pkg" << "install" << "-y" << pkgAddList.join(" ");
717    pkgCmdList << pCmds;
718  }
719
720  // Lets kick it off now
721  startPkgProcess();
722}
723
724// Display found meta-pkg data
725void mainWin::populateMetaPkgs()
726{
727  pushPkgApply->setEnabled(false);
728  treeMetaPkgs->clear();
729  tmpMetaPkgList.clear();
730  new QTreeWidgetItem(treeMetaPkgs, QStringList() << tr("Loading... Please wait...") );
731
732  if ( ! metaPkgList.isEmpty() )
733        disconnect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), 0, 0);
734  metaPkgList.clear();
735
736  // Start the process to get meta-pkg info
737  getMetaProc = new QProcess();
738  qDebug() << "Searching for meta-pkgs...";
739  connect( getMetaProc, SIGNAL(readyReadStandardOutput()), this, SLOT(slotGetPackageDataOutput()) );
740  connect( getMetaProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotFinishLoadingMetaPkgs()) );
741  getMetaProc->setProcessChannelMode(QProcess::MergedChannels);
742  getMetaProc->start(QString("pc-metapkgmanager"), QStringList() << "list");
743
744}
745
746// Display found meta-pkg data
747void mainWin::slotFinishLoadingMetaPkgs()
748{
749
750  // Populate the metaPkgList
751  parseTmpMetaList();
752
753  treeMetaPkgs->clear();
754
755  addTreeItems(QString()); 
756
757  pushPkgApply->setEnabled(false);
758
759  connect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotDeskPkgsChanged(QTreeWidgetItem *, int)));
760}
761
762void mainWin::addTreeItems(QString parent)
763{
764  for (int z=0; z < metaPkgList.count(); ++z) {
765    if ( metaPkgList.at(z).at(3) != parent )
766      continue;
767
768    // Hide the "base-system" package, since we are installing it anyway
769    if (metaPkgList.at(z).at(0) == "base-system" )
770      return;
771
772    QTreeWidgetItem *deskItem = new QTreeWidgetItem(QStringList() << metaPkgList.at(z).at(0) );
773    deskItem->setIcon(0, QIcon(metaPkgList.at(z).at(2)));
774    deskItem->setToolTip(0, metaPkgList.at(z).at(1));
775    deskItem->setCheckState(0, Qt::Unchecked);
776
777    if ( metaPkgList.at(z).at(5) == "YES" )
778      deskItem->setCheckState(0, Qt::Checked);
779
780    if ( parent.isEmpty() ) {
781      treeMetaPkgs->addTopLevelItem(deskItem);
782    } else {
783      // Locate the parent to attach to
784      QTreeWidgetItemIterator it(treeMetaPkgs);
785      while (*it) {
786        if ((*it)->text(0) == parent ) {
787          (*it)->addChild(deskItem);
788          if ( metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::Unchecked)
789            (*it)->setCheckState(0, Qt::PartiallyChecked);
790          if ( metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::Checked)
791            (*it)->setCheckState(0, Qt::PartiallyChecked);
792          break;
793        }
794        it++;
795      }
796    }
797
798    // Now look for any possible children
799    addTreeItems(metaPkgList.at(z).at(0));   
800  }
801}
802
803// Check if a meta-pkg is installed
804bool mainWin::isMetaPkgInstalled(QString mPkg)
805{
806  QString tmp;
807  QProcess pcmp;
808  pcmp.start(QString("pc-metapkgmanager"), QStringList() << chrootArg1 << chrootArg2 << "status" << mPkg);
809  while ( pcmp.state() != QProcess::NotRunning ) {
810     pcmp.waitForFinished(50);
811     QCoreApplication::processEvents();
812  }
813
814  while (pcmp.canReadLine()) {
815     tmp = pcmp.readLine().simplified();
816     if ( tmp.indexOf("is installed") != -1 )
817     return true;
818  }
819
820  return false;
821}
822
823// Function which checks for our GUI package schema data
824void mainWin::slotGetPackageDataOutput()
825{
826  while (getMetaProc->canReadLine())
827        tmpMetaPkgList << getMetaProc->readLine().simplified();
828}
829
830// Parse the pc-metapkg saved output
831void mainWin::parseTmpMetaList()
832{
833  QString tmp, mName, mDesc, mIcon, mParent, mDesktop, mInstalled, mPkgFileList;
834  QStringList package;
835
836  for ( int i = 0 ; i < tmpMetaPkgList.size(); i++ )
837  {
838        QApplication::processEvents();
839
840        tmp = tmpMetaPkgList.at(i);
841
842        if ( tmp.indexOf("Meta Package: ") == 0) {
843                mName = tmp.replace("Meta Package: ", "");
844                continue;
845        }
846        if ( tmp.indexOf("Description: ") == 0) {
847                mDesc = tmp.replace("Description: ", "");
848                continue;
849        }
850        if ( tmp.indexOf("Icon: ") == 0) {
851                mIcon = tmp.replace("Icon: ", "");
852                mPkgFileList = mIcon;
853                mPkgFileList.replace("pkg-icon.png", "pkg-list");
854                continue;
855        }
856        if ( tmp.indexOf("Parent: ") == 0) {
857                mParent = tmp.replace("Parent: ", "");
858                continue;
859        }
860        if ( tmp.indexOf("Desktop: ") == 0) {
861                mDesktop = tmp.replace("Desktop: ", "");
862                continue;
863        }
864
865        // This is an empty category
866        if ( tmp.indexOf("Category Entry") == 0) {
867                // Now add this category to the string list
868                package.clear();
869                qDebug() << "Found Package" << mName << mDesc << mIcon << mParent << mDesktop;
870                mInstalled = "CATEGORY";
871                package << mName << mDesc << mIcon << mParent << mDesktop << mInstalled;
872                metaPkgList.append(package);
873                mName=""; mDesc=""; mIcon=""; mParent=""; mDesktop=""; mInstalled=""; mPkgFileList="";
874        }
875
876        // We have a Meta-Pkg
877        if ( tmp.indexOf("Required Packages:") == 0) {
878                // Now add this meta-pkg to the string list
879                package.clear();
880                qDebug() << "Found Package" << mName << mDesc << mIcon << mParent << mDesktop << mPkgFileList;
881
882                if ( isMetaPkgInstalled(mName) )
883                        mInstalled = "YES";
884                else
885                        mInstalled = "NO";
886
887                package << mName << mDesc << mIcon << mParent << mDesktop << mInstalled << mPkgFileList;
888                metaPkgList.append(package);
889                mName=""; mDesc=""; mIcon=""; mParent=""; mDesktop=""; mInstalled=""; mPkgFileList="";
890        }
891
892    }
893
894}
895
896void mainWin::saveMetaPkgs()
897{
898        if ( ! haveMetaPkgChanges() )
899                return;
900
901        addPkgs = getAddPkgs();
902        delPkgs = getDelPkgs(); 
903
904        startMetaChanges();
905
906}
907
908void mainWin::startMetaChanges()
909{
910
911  // Init the pkg process
912  prepPkgProcess();
913  // Create our runlist of package commands
914  QStringList pCmds;
915
916  if ( ! delPkgs.isEmpty() ) {
917    if ( wDir.isEmpty() )
918      pCmds << "pc-metapkgmanager" << "del" << delPkgs;
919    else 
920      pCmds << "chroot" << wDir << "pc-metapkgmanager" << "del" << delPkgs;
921    pkgCmdList << pCmds;
922  }
923 
924  pCmds.clear();
925
926  if ( ! addPkgs.isEmpty() ) {
927    if ( wDir.isEmpty() )
928      pCmds << "pc-metapkgmanager" << "add" << addPkgs;
929    else 
930      pCmds << "chroot" << wDir << "pc-metapkgmanager" << "add" << addPkgs;
931    pkgCmdList << pCmds;
932  }
933
934  // Lets kick it off now
935  startPkgProcess();
936}
937
938bool mainWin::haveAMetaDesktop()
939{
940        // If running in a chroot we can skip this check
941        if ( ! chrootArg1.isEmpty() )
942          return true;
943       
944        QTreeWidgetItemIterator it(treeMetaPkgs);
945        while (*it) {
946         if ( ((*it)->checkState(0) == Qt::Checked) || ((*it)->checkState(0) == Qt::PartiallyChecked) )
947           for (int z=0; z < metaPkgList.count(); ++z)
948             if ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(4) == "YES" )
949                return true;
950         ++it;
951        }
952
953        QMessageBox::warning(this, tr("No Desktop"),
954          tr("No desktops have been selected! Please choose at least one desktop before saving."),
955          QMessageBox::Ok,
956          QMessageBox::Ok);
957
958        return false;
959}
960
961bool mainWin::haveMetaPkgChanges()
962{
963        QTreeWidgetItemIterator it(treeMetaPkgs);
964        while (*it) {
965          for (int z=0; z < metaPkgList.count(); ++z)
966            // See if any packages status have changed
967            if ( ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::Unchecked ) \
968              || ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::PartiallyChecked ) \
969              || ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::Checked ) )
970                return true;
971         ++it;
972        }
973
974        return false;
975}
976
977QString mainWin::getAddPkgs()
978{
979        QString tmp;
980        QTreeWidgetItemIterator it(treeMetaPkgs);
981        while (*it) {
982          for (int z=0; z < metaPkgList.count(); ++z)
983            // See if any packages status have changed
984            if ( ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::Checked ) || \
985                 ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::PartiallyChecked ) )
986                if ( tmp.isEmpty() )
987                        tmp = (*it)->text(0);
988                else
989                        tmp = tmp + "," + (*it)->text(0);
990         ++it;
991        }
992
993        return tmp;
994}
995
996QString mainWin::getDelPkgs()
997{
998        QString tmp;
999        QTreeWidgetItemIterator it(treeMetaPkgs);
1000        while (*it) {
1001          for (int z=0; z < metaPkgList.count(); ++z)
1002            // See if any packages status have changed
1003            if ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::Unchecked )
1004                if ( tmp.isEmpty() )
1005                        tmp = (*it)->text(0);
1006                else
1007                        tmp = tmp + "," + (*it)->text(0);
1008         ++it;
1009        }
1010
1011        return tmp;
1012}
1013
1014
1015// Time to save meta-pkgs
1016void mainWin::slotApplyMetaChanges() {
1017    saveMetaPkgs();
1018}
1019
1020
1021
1022// The User changed the tree widget checked / unchecked stuff sanity check
1023void mainWin::slotDeskPkgsChanged(QTreeWidgetItem *aItem, int __unused)
1024{
1025        if (!aItem)
1026          return;
1027
1028        disconnect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), 0, 0);
1029
1030        if (aItem->childCount() == 0) {
1031                if (aItem->checkState(0) == Qt::Checked && aItem->parent() )
1032                        if ( allChildrenPkgsChecked(aItem->parent()->text(0)))
1033                                aItem->parent()->setCheckState(0, Qt::Checked); 
1034                        else
1035                                aItem->parent()->setCheckState(0, Qt::PartiallyChecked);       
1036                if (aItem->checkState(0) == Qt::Unchecked && aItem->parent() )
1037                        if ( ! allChildrenPkgsUnchecked(aItem->parent()->text(0)))
1038                                aItem->parent()->setCheckState(0, Qt::PartiallyChecked);       
1039
1040
1041        } else {
1042                if (aItem->checkState(0) == Qt::Checked )
1043                        checkAllChildrenPkgs(aItem->text(0));
1044                else
1045                        uncheckAllChildrenPkgs(aItem->text(0));
1046        }
1047       
1048
1049    connect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotDeskPkgsChanged(QTreeWidgetItem *, int)));
1050
1051        if ( haveMetaPkgChanges() )
1052                pushPkgApply->setEnabled(true);
1053        else
1054                pushPkgApply->setEnabled(false);
1055}
1056
1057// Check the "parent" app to see if all its children are checked or not
1058bool mainWin::allChildrenPkgsChecked(QString parent)
1059{
1060        QTreeWidgetItemIterator it(treeMetaPkgs);
1061        while (*it) {
1062         if ((*it)->text(0) == parent ) {
1063           if ( (*it)->childCount() <= 0)
1064             return true;
1065
1066           for ( int i = 0; i < (*it)->childCount() ; ++i) {
1067             if ( ! allChildrenPkgsChecked((*it)->child(i)->text(0)))
1068               return false;
1069
1070             if ((*it)->child(i)->checkState(0) != Qt::Checked ) 
1071               return false;
1072           }
1073         }
1074         ++it;
1075        }
1076        return true;
1077}
1078
1079// Check the "parent" app to see if all its children are unchecked or not
1080bool mainWin::allChildrenPkgsUnchecked(QString parent)
1081{
1082        QTreeWidgetItemIterator it(treeMetaPkgs);
1083        while (*it) {
1084         if ((*it)->text(0) == parent ) {
1085           if ( (*it)->childCount() <= 0)
1086             return true;
1087
1088           for ( int i = 0; i < (*it)->childCount() ; ++i) {
1089             if ( ! allChildrenPkgsUnchecked((*it)->child(i)->text(0)))
1090               return false;
1091
1092             if ((*it)->child(i)->checkState(0) != Qt::Unchecked ) 
1093               return false;
1094           }
1095         }
1096         ++it;
1097        }
1098        return true;
1099}
1100
1101// Check all children of parent
1102void mainWin::checkAllChildrenPkgs(QString parent)
1103{
1104        QTreeWidgetItemIterator it(treeMetaPkgs);
1105        while (*it) {
1106         if (! (*it)->parent()) {
1107           ++it;
1108           continue;
1109         } 
1110
1111         // Lets walk the tree see what pops up
1112         bool pFound=false;
1113         QTreeWidgetItem *itP = (*it)->parent();
1114         do {
1115           pFound=false;
1116           if (itP->text(0) == parent) {
1117             (*it)->setCheckState(0, Qt::Checked);
1118             break;
1119           }
1120           if ( itP->parent() ) {
1121             itP = itP->parent();
1122             pFound=true;
1123           }
1124         } while (pFound);
1125
1126         ++it;
1127       }
1128}
1129
1130// UnCheck all children of parent
1131void mainWin::uncheckAllChildrenPkgs(QString parent)
1132{
1133        QTreeWidgetItemIterator it(treeMetaPkgs);
1134        while (*it) {
1135         if (! (*it)->parent()) {
1136           ++it;
1137           continue;
1138         } 
1139
1140         // Lets walk the tree see what pops up
1141         bool pFound=false;
1142         QTreeWidgetItem *itP = (*it)->parent();
1143         do {
1144           pFound=false;
1145           if (itP->text(0) == parent) {
1146             (*it)->setCheckState(0, Qt::Unchecked);
1147             break;
1148           }
1149           if ( itP->parent() ) {
1150             itP = itP->parent();
1151             pFound=true;
1152           }
1153         } while (pFound);
1154
1155         ++it;
1156       }
1157}
1158
1159void mainWin::slotMetaRightClick()
1160{
1161        QTreeWidgetItemIterator it(treeMetaPkgs);
1162        while (*it) {
1163          for (int z=0; z < metaPkgList.count(); ++z) {
1164            if ( (*it)->isSelected() && (*it)->text(0) == metaPkgList.at(z).at(0) ) {
1165              if (metaPkgList.at(z).at(5) == "CATEGORY")
1166                return;
1167              popup = new QMenu;
1168              popup->setTitle((*it)->text(0));
1169              popup->addAction(tr("View Packages"), this, SLOT(slotMetaViewPkgs()));
1170              popup->exec( QCursor::pos() );
1171            }
1172          }
1173         ++it;
1174        }
1175}
1176
1177void mainWin::slotMetaViewPkgs()
1178{
1179        QStringList packageList;
1180        QTreeWidgetItemIterator it(treeMetaPkgs);
1181        while (*it) {
1182          for (int z=0; z < metaPkgList.count(); ++z) {
1183            if ( (*it)->isSelected() && (*it)->text(0) == metaPkgList.at(z).at(0) ) {
1184 
1185                QFile pList(metaPkgList.at(z).at(6));
1186                if ( ! pList.exists() )
1187                  return;
1188               
1189                if ( ! pList.open(QIODevice::ReadOnly | QIODevice::Text))
1190                  return;
1191
1192                while ( !pList.atEnd() )
1193                  packageList << pList.readLine().simplified();
1194
1195                pList.close();
1196                packageList.sort();
1197                       
1198                dIB = new dialogInfo();
1199                dIB->programInit(tr("Package Listing for:") + " " + (*it)->text(0));
1200                dIB->setInfoText(packageList.join("\n"));
1201                dIB->show();
1202            }
1203          }
1204         ++it;
1205        }
1206}
1207
1208QString mainWin::getLineFromCommandOutput( QString cmd )
1209{
1210        FILE *file = popen(cmd.toLatin1(),"r");
1211 
1212        char buffer[100];
1213 
1214        QString line = "";
1215        char firstChar;
1216
1217        if ((firstChar = fgetc(file)) != -1){
1218                line += firstChar;
1219                line += fgets(buffer,100,file);
1220        }
1221        pclose(file);
1222        return line.simplified();
1223}
Note: See TracBrowser for help on using the repository browser.