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

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

Fix some bugs working with PKGNG in a chroot

  • Property mode set to 100644
File size: 34.2 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");
476  else
477    getNGProc->start(QString("chroot"), QStringList() << wDir << "pkg" << "rquery" << "-a" << "%o:::%n-%v:::%c:::%sh");
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;
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
570        // Check if we need to add a top-level category
571        if ( cat != curCat )
572        {
573           qDebug() << "Adding cat: " + cat;
574           catItem = new QTreeWidgetItem(QStringList() << cat);
575           treeNGPkgs->addTopLevelItem(catItem);
576           curCat = cat;
577        }
578 
579        // Now lets create the item and attach to the category
580        QTreeWidgetItem *pkgItem = new QTreeWidgetItem();
581        pkgItem->setText(0, name + " (" + pkgname + ") - " + size );
582        pkgItem->setToolTip(0, desc);
583
584        if ( pkgList.indexOf(pkgname) != -1 ) {
585          pkgItem->setCheckState(0, Qt::Checked);
586          selPkgList << pkgname;
587        } else
588          pkgItem->setCheckState(0, Qt::Unchecked);
589 
590        catItem->addChild(pkgItem);
591   }
592
593}
594
595// Lets prompt user, and do it!
596void mainWin::applyNGChanges()
597{
598   QString tmp;
599   QStringList curPkgChecked;
600   QStringList newPkgs;
601   QStringList rmPkgs;
602
603   QTreeWidgetItemIterator it(treeNGPkgs);
604   while (*it) {
605         if ((*it)->checkState(0) == Qt::Checked) {
606           tmp = (*it)->text(0).section("(", 1, 1).section(")", 0, 0);
607           curPkgChecked << tmp;
608           if (pkgList.indexOf(tmp) == -1 ) 
609              newPkgs << tmp;
610         }
611         ++it;
612   }
613
614   for ( int i=0; i < pkgList.size(); ++i)
615      // Has this package been unchecked?
616      if (curPkgChecked.indexOf(pkgList.at(i)) == -1 )  {
617         // Make sure this is a package in the repo
618         // This filters out any custom packages the user may have loaded which may not exist in our repo
619         QRegExp rx("*" + pkgList.at(i) + "*");
620         rx.setPatternSyntax(QRegExp::Wildcard);
621         if ( tmpPkgList.indexOf(rx) != -1 )
622           rmPkgs << pkgList.at(i);
623      }
624
625   if ( rmPkgs.isEmpty() && newPkgs.isEmpty() ) {
626      QMessageBox::warning(this, tr("No changes"),
627        tr("No changes to make!"),
628        QMessageBox::Ok,
629        QMessageBox::Ok);
630      return;
631   }
632
633   qDebug() << "Added packages" << newPkgs;
634   qDebug() << "Removed packages" << rmPkgs;
635   pkgRemoveList = rmPkgs;
636   pkgAddList = newPkgs;
637
638   QString confirmText;
639
640   // Lets start creating our confirmation text
641   if ( ! rmPkgs.isEmpty() ) {
642      confirmText+=tr("The following packages will be removed:") + "\n"; 
643      confirmText+= "------------------------------------------\n";
644      confirmText+=rmPkgs.join("\n"); 
645      confirmText+= "\n\n" + tr("The following packages that require the above packages will also removed:") + "\n"; 
646      confirmText+= "------------------------------------------\n";
647      for ( int i=0; i < rmPkgs.size(); ++i) {
648         QRegExp rx(rmPkgs.at(i) + ":::*");
649         rx.setPatternSyntax(QRegExp::Wildcard);
650         QStringList rDeps = pkgRDepList.filter(rx);
651         for ( int r=0; r < rDeps.size(); ++r) {
652             QString pName = rDeps.at(r).section(":::", 1, 1); 
653             // Is this package installed?
654             if ( pkgList.indexOf(pName) != -1 )
655               confirmText+= pName + " ";
656         }
657      }
658   }
659
660   if ( ! newPkgs.isEmpty() ) {
661      if ( ! rmPkgs.isEmpty() )
662        confirmText+= "\n\n";
663      confirmText+=tr("The following packages will be installed:") + "\n"; 
664      confirmText+= "------------------------------------------\n";
665      confirmText+=newPkgs.join("\n"); 
666      confirmText+= "\n\n" + tr("The following dependances will also be installed:") + "\n"; 
667      confirmText+= "------------------------------------------\n";
668      for ( int i=0; i < newPkgs.size(); ++i) {
669         QRegExp rx(newPkgs.at(i) + ":::*");
670         rx.setPatternSyntax(QRegExp::Wildcard);
671         QStringList aDeps = pkgDepList.filter(rx);
672         for ( int r=0; r < aDeps.size(); ++r) {
673             QString pName = aDeps.at(r).section(":::", 1, 1); 
674             // Is this package installed?
675             if ( pkgList.indexOf(pName) == -1 )
676               confirmText+= pName + " ";
677         }
678      }
679   }
680
681   // Launch our AddPartitionDialog to add a new device
682   askUserConfirm = new dialogConfirm();
683   connect(askUserConfirm, SIGNAL(ok()),this, SLOT(slotStartNGChanges()) );
684   askUserConfirm->programInit(tr("Confirm package changes"));
685   askUserConfirm->setInfoText(QString(confirmText));
686   askUserConfirm->exec();
687
688}
689
690
691// Time to start doing our NG changes!
692void mainWin::slotStartNGChanges()
693{
694  // Init the pkg process
695  prepPkgProcess();
696
697  // Create our runlist of package commands
698  QStringList pCmds;
699 
700  if ( ! pkgRemoveList.isEmpty() ) {
701    if ( wDir.isEmpty() )
702      pCmds << "pkg" << "delete" << "-R" << "-y" << pkgRemoveList.join(" ");
703    else
704      pCmds << "chroot" << wDir << "pkg" << "delete" << "-R" << "-y" << pkgRemoveList.join(" ");
705    pkgCmdList << pCmds;
706  }
707         
708  pCmds.clear();
709
710  if ( ! pkgAddList.isEmpty() ) {
711    if ( wDir.isEmpty() )
712      pCmds << "pc-pkg" << "install" << "-y" << pkgAddList.join(" ");
713    else
714      pCmds << "chroot" << wDir << "pc-pkg" << "install" << "-y" << pkgAddList.join(" ");
715    pkgCmdList << pCmds;
716  }
717
718  // Lets kick it off now
719  startPkgProcess();
720}
721
722// Display found meta-pkg data
723void mainWin::populateMetaPkgs()
724{
725  pushPkgApply->setEnabled(false);
726  treeMetaPkgs->clear();
727  tmpMetaPkgList.clear();
728  new QTreeWidgetItem(treeMetaPkgs, QStringList() << tr("Loading... Please wait...") );
729
730  if ( ! metaPkgList.isEmpty() )
731        disconnect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), 0, 0);
732  metaPkgList.clear();
733
734  // Start the process to get meta-pkg info
735  getMetaProc = new QProcess();
736  qDebug() << "Searching for meta-pkgs...";
737  connect( getMetaProc, SIGNAL(readyReadStandardOutput()), this, SLOT(slotGetPackageDataOutput()) );
738  connect( getMetaProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotFinishLoadingMetaPkgs()) );
739  getMetaProc->setProcessChannelMode(QProcess::MergedChannels);
740  getMetaProc->start(QString("pc-metapkgmanager"), QStringList() << "list");
741
742}
743
744// Display found meta-pkg data
745void mainWin::slotFinishLoadingMetaPkgs()
746{
747
748  // Populate the metaPkgList
749  parseTmpMetaList();
750
751  treeMetaPkgs->clear();
752
753  addTreeItems(QString()); 
754
755  pushPkgApply->setEnabled(false);
756
757  connect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotDeskPkgsChanged(QTreeWidgetItem *, int)));
758}
759
760void mainWin::addTreeItems(QString parent)
761{
762  for (int z=0; z < metaPkgList.count(); ++z) {
763    if ( metaPkgList.at(z).at(3) != parent )
764      continue;
765
766    // Hide the "base-system" package, since we are installing it anyway
767    if (metaPkgList.at(z).at(0) == "base-system" )
768      return;
769
770    QTreeWidgetItem *deskItem = new QTreeWidgetItem(QStringList() << metaPkgList.at(z).at(0) );
771    deskItem->setIcon(0, QIcon(metaPkgList.at(z).at(2)));
772    deskItem->setToolTip(0, metaPkgList.at(z).at(1));
773    deskItem->setCheckState(0, Qt::Unchecked);
774
775    if ( metaPkgList.at(z).at(5) == "YES" )
776      deskItem->setCheckState(0, Qt::Checked);
777
778    if ( parent.isEmpty() ) {
779      treeMetaPkgs->addTopLevelItem(deskItem);
780    } else {
781      // Locate the parent to attach to
782      QTreeWidgetItemIterator it(treeMetaPkgs);
783      while (*it) {
784        if ((*it)->text(0) == parent ) {
785          (*it)->addChild(deskItem);
786          if ( metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::Unchecked)
787            (*it)->setCheckState(0, Qt::PartiallyChecked);
788          if ( metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::Checked)
789            (*it)->setCheckState(0, Qt::PartiallyChecked);
790          break;
791        }
792        it++;
793      }
794    }
795
796    // Now look for any possible children
797    addTreeItems(metaPkgList.at(z).at(0));   
798  }
799}
800
801// Check if a meta-pkg is installed
802bool mainWin::isMetaPkgInstalled(QString mPkg)
803{
804  QString tmp;
805  QProcess pcmp;
806  pcmp.start(QString("pc-metapkgmanager"), QStringList() << chrootArg1 << chrootArg2 << "status" << mPkg);
807  while ( pcmp.state() != QProcess::NotRunning ) {
808     pcmp.waitForFinished(50);
809     QCoreApplication::processEvents();
810  }
811
812  while (pcmp.canReadLine()) {
813     tmp = pcmp.readLine().simplified();
814     if ( tmp.indexOf("is installed") != -1 )
815     return true;
816  }
817
818  return false;
819}
820
821// Function which checks for our GUI package schema data
822void mainWin::slotGetPackageDataOutput()
823{
824  while (getMetaProc->canReadLine())
825        tmpMetaPkgList << getMetaProc->readLine().simplified();
826}
827
828// Parse the pc-metapkg saved output
829void mainWin::parseTmpMetaList()
830{
831  QString tmp, mName, mDesc, mIcon, mParent, mDesktop, mInstalled, mPkgFileList;
832  QStringList package;
833
834  for ( int i = 0 ; i < tmpMetaPkgList.size(); i++ )
835  {
836        QApplication::processEvents();
837
838        tmp = tmpMetaPkgList.at(i);
839
840        if ( tmp.indexOf("Meta Package: ") == 0) {
841                mName = tmp.replace("Meta Package: ", "");
842                continue;
843        }
844        if ( tmp.indexOf("Description: ") == 0) {
845                mDesc = tmp.replace("Description: ", "");
846                continue;
847        }
848        if ( tmp.indexOf("Icon: ") == 0) {
849                mIcon = tmp.replace("Icon: ", "");
850                mPkgFileList = mIcon;
851                mPkgFileList.replace("pkg-icon.png", "pkg-list");
852                continue;
853        }
854        if ( tmp.indexOf("Parent: ") == 0) {
855                mParent = tmp.replace("Parent: ", "");
856                continue;
857        }
858        if ( tmp.indexOf("Desktop: ") == 0) {
859                mDesktop = tmp.replace("Desktop: ", "");
860                continue;
861        }
862
863        // This is an empty category
864        if ( tmp.indexOf("Category Entry") == 0) {
865                // Now add this category to the string list
866                package.clear();
867                qDebug() << "Found Package" << mName << mDesc << mIcon << mParent << mDesktop;
868                mInstalled = "CATEGORY";
869                package << mName << mDesc << mIcon << mParent << mDesktop << mInstalled;
870                metaPkgList.append(package);
871                mName=""; mDesc=""; mIcon=""; mParent=""; mDesktop=""; mInstalled=""; mPkgFileList="";
872        }
873
874        // We have a Meta-Pkg
875        if ( tmp.indexOf("Required Packages:") == 0) {
876                // Now add this meta-pkg to the string list
877                package.clear();
878                qDebug() << "Found Package" << mName << mDesc << mIcon << mParent << mDesktop << mPkgFileList;
879
880                if ( isMetaPkgInstalled(mName) )
881                        mInstalled = "YES";
882                else
883                        mInstalled = "NO";
884
885                package << mName << mDesc << mIcon << mParent << mDesktop << mInstalled << mPkgFileList;
886                metaPkgList.append(package);
887                mName=""; mDesc=""; mIcon=""; mParent=""; mDesktop=""; mInstalled=""; mPkgFileList="";
888        }
889
890    }
891
892}
893
894void mainWin::saveMetaPkgs()
895{
896        if ( ! haveMetaPkgChanges() )
897                return;
898
899        addPkgs = getAddPkgs();
900        delPkgs = getDelPkgs(); 
901
902        startMetaChanges();
903
904}
905
906void mainWin::startMetaChanges()
907{
908
909  // Init the pkg process
910  prepPkgProcess();
911  // Create our runlist of package commands
912  QStringList pCmds;
913
914  if ( ! delPkgs.isEmpty() ) {
915    if ( wDir.isEmpty() )
916      pCmds << "pc-metapkgmanager" << "del" << delPkgs;
917    else 
918      pCmds << "chroot" << wDir << "pc-metapkgmanager" << "del" << delPkgs;
919    pkgCmdList << pCmds;
920  }
921 
922  pCmds.clear();
923
924  if ( ! addPkgs.isEmpty() ) {
925    if ( wDir.isEmpty() )
926      pCmds << "pc-metapkgmanager" << "add" << addPkgs;
927    else 
928      pCmds << "chroot" << wDir << "pc-metapkgmanager" << "add" << addPkgs;
929    pkgCmdList << pCmds;
930  }
931
932  // Lets kick it off now
933  startPkgProcess();
934}
935
936bool mainWin::haveAMetaDesktop()
937{
938        // If running in a chroot we can skip this check
939        if ( ! chrootArg1.isEmpty() )
940          return true;
941       
942        QTreeWidgetItemIterator it(treeMetaPkgs);
943        while (*it) {
944         if ( ((*it)->checkState(0) == Qt::Checked) || ((*it)->checkState(0) == Qt::PartiallyChecked) )
945           for (int z=0; z < metaPkgList.count(); ++z)
946             if ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(4) == "YES" )
947                return true;
948         ++it;
949        }
950
951        QMessageBox::warning(this, tr("No Desktop"),
952          tr("No desktops have been selected! Please choose at least one desktop before saving."),
953          QMessageBox::Ok,
954          QMessageBox::Ok);
955
956        return false;
957}
958
959bool mainWin::haveMetaPkgChanges()
960{
961        QTreeWidgetItemIterator it(treeMetaPkgs);
962        while (*it) {
963          for (int z=0; z < metaPkgList.count(); ++z)
964            // See if any packages status have changed
965            if ( ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::Unchecked ) \
966              || ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::PartiallyChecked ) \
967              || ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::Checked ) )
968                return true;
969         ++it;
970        }
971
972        return false;
973}
974
975QString mainWin::getAddPkgs()
976{
977        QString tmp;
978        QTreeWidgetItemIterator it(treeMetaPkgs);
979        while (*it) {
980          for (int z=0; z < metaPkgList.count(); ++z)
981            // See if any packages status have changed
982            if ( ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::Checked ) || \
983                 ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::PartiallyChecked ) )
984                if ( tmp.isEmpty() )
985                        tmp = (*it)->text(0);
986                else
987                        tmp = tmp + "," + (*it)->text(0);
988         ++it;
989        }
990
991        return tmp;
992}
993
994QString mainWin::getDelPkgs()
995{
996        QString tmp;
997        QTreeWidgetItemIterator it(treeMetaPkgs);
998        while (*it) {
999          for (int z=0; z < metaPkgList.count(); ++z)
1000            // See if any packages status have changed
1001            if ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::Unchecked )
1002                if ( tmp.isEmpty() )
1003                        tmp = (*it)->text(0);
1004                else
1005                        tmp = tmp + "," + (*it)->text(0);
1006         ++it;
1007        }
1008
1009        return tmp;
1010}
1011
1012
1013// Time to save meta-pkgs
1014void mainWin::slotApplyMetaChanges() {
1015    saveMetaPkgs();
1016}
1017
1018
1019
1020// The User changed the tree widget checked / unchecked stuff sanity check
1021void mainWin::slotDeskPkgsChanged(QTreeWidgetItem *aItem, int __unused)
1022{
1023        if (!aItem)
1024          return;
1025
1026        disconnect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), 0, 0);
1027
1028        if (aItem->childCount() == 0) {
1029                if (aItem->checkState(0) == Qt::Checked && aItem->parent() )
1030                        if ( allChildrenPkgsChecked(aItem->parent()->text(0)))
1031                                aItem->parent()->setCheckState(0, Qt::Checked); 
1032                        else
1033                                aItem->parent()->setCheckState(0, Qt::PartiallyChecked);       
1034                if (aItem->checkState(0) == Qt::Unchecked && aItem->parent() )
1035                        if ( ! allChildrenPkgsUnchecked(aItem->parent()->text(0)))
1036                                aItem->parent()->setCheckState(0, Qt::PartiallyChecked);       
1037
1038
1039        } else {
1040                if (aItem->checkState(0) == Qt::Checked )
1041                        checkAllChildrenPkgs(aItem->text(0));
1042                else
1043                        uncheckAllChildrenPkgs(aItem->text(0));
1044        }
1045       
1046
1047    connect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotDeskPkgsChanged(QTreeWidgetItem *, int)));
1048
1049        if ( haveMetaPkgChanges() )
1050                pushPkgApply->setEnabled(true);
1051        else
1052                pushPkgApply->setEnabled(false);
1053}
1054
1055// Check the "parent" app to see if all its children are checked or not
1056bool mainWin::allChildrenPkgsChecked(QString parent)
1057{
1058        QTreeWidgetItemIterator it(treeMetaPkgs);
1059        while (*it) {
1060         if ((*it)->text(0) == parent ) {
1061           if ( (*it)->childCount() <= 0)
1062             return true;
1063
1064           for ( int i = 0; i < (*it)->childCount() ; ++i) {
1065             if ( ! allChildrenPkgsChecked((*it)->child(i)->text(0)))
1066               return false;
1067
1068             if ((*it)->child(i)->checkState(0) != Qt::Checked ) 
1069               return false;
1070           }
1071         }
1072         ++it;
1073        }
1074        return true;
1075}
1076
1077// Check the "parent" app to see if all its children are unchecked or not
1078bool mainWin::allChildrenPkgsUnchecked(QString parent)
1079{
1080        QTreeWidgetItemIterator it(treeMetaPkgs);
1081        while (*it) {
1082         if ((*it)->text(0) == parent ) {
1083           if ( (*it)->childCount() <= 0)
1084             return true;
1085
1086           for ( int i = 0; i < (*it)->childCount() ; ++i) {
1087             if ( ! allChildrenPkgsUnchecked((*it)->child(i)->text(0)))
1088               return false;
1089
1090             if ((*it)->child(i)->checkState(0) != Qt::Unchecked ) 
1091               return false;
1092           }
1093         }
1094         ++it;
1095        }
1096        return true;
1097}
1098
1099// Check all children of parent
1100void mainWin::checkAllChildrenPkgs(QString parent)
1101{
1102        QTreeWidgetItemIterator it(treeMetaPkgs);
1103        while (*it) {
1104         if (! (*it)->parent()) {
1105           ++it;
1106           continue;
1107         } 
1108
1109         // Lets walk the tree see what pops up
1110         bool pFound=false;
1111         QTreeWidgetItem *itP = (*it)->parent();
1112         do {
1113           pFound=false;
1114           if (itP->text(0) == parent) {
1115             (*it)->setCheckState(0, Qt::Checked);
1116             break;
1117           }
1118           if ( itP->parent() ) {
1119             itP = itP->parent();
1120             pFound=true;
1121           }
1122         } while (pFound);
1123
1124         ++it;
1125       }
1126}
1127
1128// UnCheck all children of parent
1129void mainWin::uncheckAllChildrenPkgs(QString parent)
1130{
1131        QTreeWidgetItemIterator it(treeMetaPkgs);
1132        while (*it) {
1133         if (! (*it)->parent()) {
1134           ++it;
1135           continue;
1136         } 
1137
1138         // Lets walk the tree see what pops up
1139         bool pFound=false;
1140         QTreeWidgetItem *itP = (*it)->parent();
1141         do {
1142           pFound=false;
1143           if (itP->text(0) == parent) {
1144             (*it)->setCheckState(0, Qt::Unchecked);
1145             break;
1146           }
1147           if ( itP->parent() ) {
1148             itP = itP->parent();
1149             pFound=true;
1150           }
1151         } while (pFound);
1152
1153         ++it;
1154       }
1155}
1156
1157void mainWin::slotMetaRightClick()
1158{
1159        QTreeWidgetItemIterator it(treeMetaPkgs);
1160        while (*it) {
1161          for (int z=0; z < metaPkgList.count(); ++z) {
1162            if ( (*it)->isSelected() && (*it)->text(0) == metaPkgList.at(z).at(0) ) {
1163              if (metaPkgList.at(z).at(5) == "CATEGORY")
1164                return;
1165              popup = new QMenu;
1166              popup->setTitle((*it)->text(0));
1167              popup->addAction(tr("View Packages"), this, SLOT(slotMetaViewPkgs()));
1168              popup->exec( QCursor::pos() );
1169            }
1170          }
1171         ++it;
1172        }
1173}
1174
1175void mainWin::slotMetaViewPkgs()
1176{
1177        QStringList packageList;
1178        QTreeWidgetItemIterator it(treeMetaPkgs);
1179        while (*it) {
1180          for (int z=0; z < metaPkgList.count(); ++z) {
1181            if ( (*it)->isSelected() && (*it)->text(0) == metaPkgList.at(z).at(0) ) {
1182 
1183                QFile pList(metaPkgList.at(z).at(6));
1184                if ( ! pList.exists() )
1185                  return;
1186               
1187                if ( ! pList.open(QIODevice::ReadOnly | QIODevice::Text))
1188                  return;
1189
1190                while ( !pList.atEnd() )
1191                  packageList << pList.readLine().simplified();
1192
1193                pList.close();
1194                packageList.sort();
1195                       
1196                dIB = new dialogInfo();
1197                dIB->programInit(tr("Package Listing for:") + " " + (*it)->text(0));
1198                dIB->setInfoText(packageList.join("\n"));
1199                dIB->show();
1200            }
1201          }
1202         ++it;
1203        }
1204}
1205
1206QString mainWin::getLineFromCommandOutput( QString cmd )
1207{
1208        FILE *file = popen(cmd.toLatin1(),"r");
1209 
1210        char buffer[100];
1211 
1212        QString line = "";
1213        char firstChar;
1214
1215        if ((firstChar = fgetc(file)) != -1){
1216                line += firstChar;
1217                line += fgets(buffer,100,file);
1218        }
1219        pclose(file);
1220        return line.simplified();
1221}
Note: See TracBrowser for help on using the repository browser.