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

9.1-release9.2-releasereleng/10.0releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1
Last change on this file since ad90f5d was afa0da8, checked in by Kris Moore <kris@…>, 20 months ago

Now we can add / remove pkgng packages via a GUI!

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