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

9.2-releasereleng/10.0releng/10.0.1releng/10.0.2
Last change on this file since a30e795 was a30e795, checked in by Kris Moore <kris@…>, 13 months ago

After installing pkgs / updates, rescan for any new updates automatically

  • Property mode set to 100644
File size: 36.8 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 || line.indexOf("Reinstalling") == 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-scan for updates
433  slotRescanPkgsClicked();
434
435  // Re-init the meta-widget
436  initMetaWidget();
437
438}
439
440/*****************************************
441Code for package stuff
442******************************************/
443
444void mainWin::initMetaWidget()
445{
446  qDebug() << "Starting metaWidget...";
447  groupInfo->setVisible(false);
448
449  // Running in basic mode
450  if ( stackedPkgView->currentIndex() == 0 )
451  {
452    populateMetaPkgs();
453    // Connect our slots
454  } else {
455    // Running in advanced mode
456    populateNGPkgs();
457  }
458}
459
460void mainWin::populateNGPkgs()
461{
462  pushPkgApply->setEnabled(false);
463  treeNGPkgs->clear();
464  tmpPkgList.clear();
465  new QTreeWidgetItem(treeNGPkgs, QStringList() << tr("Loading... Please wait...") );
466
467  if ( ! pkgList.isEmpty() ) {
468        disconnect(treeNGPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), 0, 0);
469        disconnect(treeNGPkgs, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), 0, 0);
470  }
471  pkgList.clear();
472  selPkgList.clear();
473
474  // Start the process to get meta-pkg info
475  getNGProc = new QProcess();
476  qDebug() << "Searching for pkgs...";
477  connect( getNGProc, SIGNAL(readyReadStandardOutput()), this, SLOT(slotGetNGPackageDataOutput()) );
478  connect( getNGProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotGetNGInstalledPkgs()) );
479  getNGProc->setProcessChannelMode(QProcess::MergedChannels);
480  if ( wDir.isEmpty() )
481    getNGProc->start(QString("pkg"), QStringList() << "rquery" << "-a" << "%o:::%n-%v:::%c:::%sh:::%m:::%w");
482  else
483    getNGProc->start(QString("chroot"), QStringList() << wDir << "pkg" << "rquery" << "-a" << "%o:::%n-%v:::%c:::%sh:::%m:::%w");
484
485}
486
487void mainWin::slotGetNGPackageDataOutput()
488{
489   while (getNGProc->canReadLine())
490     tmpPkgList << getNGProc->readLine().simplified();
491}
492
493void mainWin::slotGetNGInstalledDataOutput()
494{
495   while (getNGProc->canReadLine())
496     pkgList << getNGProc->readLine().simplified();
497}
498
499void mainWin::slotGetNGInstalledPkgs() {
500
501  qDebug() << "Building dependancy lists...";
502  QProcess p;
503  pkgDepList.clear();
504  if ( wDir.isEmpty() )
505    p.start("pkg", QStringList() << "rquery" << "-a" << "%n-%v:::%dn-%dv");
506  else
507    p.start("chroot", QStringList() << wDir << "pkg" << "rquery" << "-a" << "%n-%v:::%dn-%dv" );
508  while(p.state() == QProcess::Starting || p.state() == QProcess::Running) {
509      p.waitForFinished(200);
510      QCoreApplication::processEvents();
511  }
512  while (p.canReadLine()) {
513    pkgDepList << p.readLine().simplified();
514  }
515
516  qDebug() << "Building reverse dependancy lists...";
517  pkgRDepList.clear();
518  if ( wDir.isEmpty() )
519    p.start("pkg", QStringList() << "rquery" << "-a" << "%n-%v:::%rn-%rv");
520  else
521    p.start("chroot", QStringList() << wDir << "pkg" << "rquery" << "-a" << "%n-%v:::%rn-%rv" );
522  while(p.state() == QProcess::Starting || p.state() == QProcess::Running) {
523      p.waitForFinished(200);
524      QCoreApplication::processEvents();
525  }
526  while (p.canReadLine()) {
527    pkgRDepList << p.readLine().simplified();
528  }
529
530  getNGProc = new QProcess();
531  qDebug() << "Searching for installed pkgs...";
532  connect( getNGProc, SIGNAL(readyReadStandardOutput()), this, SLOT(slotGetNGInstalledDataOutput()) );
533  connect( getNGProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotFinishLoadingNGPkgs()) );
534  getNGProc->setProcessChannelMode(QProcess::MergedChannels);
535  if ( wDir.isEmpty() )
536    getNGProc->start(QString("pkg"), QStringList() << "info" << "-aq" );
537  else
538    getNGProc->start(QString("chroot"), QStringList() << wDir << "pkg" << "info" << "-aq");
539
540}
541
542void mainWin::slotFinishLoadingNGPkgs()
543{
544  treeNGPkgs->clear();
545
546  addNGItems();
547
548  pushPkgApply->setEnabled(false);
549
550  connect(treeNGPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotEnableApply()));
551  connect(treeNGPkgs, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(slotNGItemChanged()));
552}
553
554void mainWin::slotNGItemChanged()
555{
556  if ( ! treeNGPkgs->currentItem() ) {
557     groupInfo->setVisible(false);
558     return;
559  }
560  QString desc, size, maint, weburl;
561
562  QTreeWidgetItem *cItem = treeNGPkgs->currentItem();
563  QString pName = cItem->text(0).section("(", 1, 1).section(")", 0, 0);
564  if ( pName.isEmpty() ) {
565     groupInfo->setVisible(false);
566     return;
567  }
568  qDebug() << "Checking: " + pName;
569
570  QRegExp rx("*:::" + pName + ":::*");
571  rx.setPatternSyntax(QRegExp::Wildcard);
572  int pAt = tmpPkgList.indexOf(rx);
573  if (pAt == -1 ) {
574     qDebug() << "Unable to find package: " + pName;
575     groupInfo->setVisible(false);
576     return;
577  }
578
579  desc = tmpPkgList.at(pAt).section(":::", 2,2);
580  size = tmpPkgList.at(pAt).section(":::", 3,3);
581  maint = tmpPkgList.at(pAt).section(":::", 4,4);
582  weburl = tmpPkgList.at(pAt).section(":::", 5,5);
583  labelPkgNameVer->setText(pName);
584  labelSize->setText(size);
585  labelWeb->setText(weburl);
586  textDesc->setText(desc);
587  textOptions->clear();
588
589  QCoreApplication::processEvents();
590
591  // Display the depends
592  QString depTxt;
593  QRegExp rxd( pName + ":::*");
594  rxd.setPatternSyntax(QRegExp::Wildcard);
595  QStringList aDeps = pkgDepList.filter(rxd);
596  for ( int r=0; r < aDeps.size(); ++r) {
597      QString dName = aDeps.at(r).section(":::", 1, 1);
598      // Is this package installed?
599      if ( pkgList.indexOf(dName) != -1 )
600         depTxt+= dName + " (Installed)\n";
601      else
602         depTxt+= dName + "\n";
603  }
604
605  textDeps->setText(depTxt);
606
607  groupInfo->setVisible(true);
608
609  getNGInfo = new QProcess();
610  qDebug() << "Getting Info for " + pName;
611  connect( getNGInfo, SIGNAL(readyReadStandardOutput()), this, SLOT(slotNGReadInfo()) );
612  getNGInfo->setProcessChannelMode(QProcess::MergedChannels);
613  if ( wDir.isEmpty() )
614    getNGInfo->start(QString("pkg"), QStringList() << "rquery" << "%Ok=%Ov" << pName );
615  else
616    getNGInfo->start(QString("chroot"), QStringList() << wDir << "pkg" << "rquery" << "%Ok=%Ov" << pName);
617}
618
619void mainWin::slotNGReadInfo()
620{
621  while (getNGInfo->canReadLine())
622     textOptions->append(getNGInfo->readLine().simplified() );
623
624  textOptions->moveCursor(QTextCursor::Start);
625}
626
627void mainWin::slotEnableApply()
628{
629  pushPkgApply->setEnabled(true);
630}
631
632void mainWin::addNGItems()
633{
634   QString curCat, cat, name, pkgname, desc, size, maint, weburl;
635
636   // We like to add alphabetically
637   tmpPkgList.sort();
638
639   QTreeWidgetItem *catItem;
640
641   // Lets start adding packages to the tree widget
642   for (int i = 0; i < tmpPkgList.size(); ++i) {
643        name = cat = tmpPkgList.at(i).section(":::", 0,0);
644        cat=cat.section("/", 0, 0);
645        name=name.section("/", 1, 1);
646        pkgname = tmpPkgList.at(i).section(":::", 1,1);
647        desc = tmpPkgList.at(i).section(":::", 2,2);
648        size = tmpPkgList.at(i).section(":::", 3,3);
649        maint = tmpPkgList.at(i).section(":::", 4,4);
650        weburl = tmpPkgList.at(i).section(":::", 5,5);
651
652        // Check if we need to add a top-level category
653        if ( cat != curCat )
654        {
655           qDebug() << "Adding cat: " + cat;
656           catItem = new QTreeWidgetItem(QStringList() << cat);
657           treeNGPkgs->addTopLevelItem(catItem);
658           curCat = cat;
659        }
660 
661        // Now lets create the item and attach to the category
662        QTreeWidgetItem *pkgItem = new QTreeWidgetItem();
663        pkgItem->setText(0, name + " (" + pkgname + ") - " + size );
664        pkgItem->setToolTip(0, desc);
665
666        if ( pkgList.indexOf(pkgname) != -1 ) {
667          pkgItem->setCheckState(0, Qt::Checked);
668          selPkgList << pkgname;
669        } else
670          pkgItem->setCheckState(0, Qt::Unchecked);
671 
672        catItem->addChild(pkgItem);
673   }
674
675}
676
677// Lets prompt user, and do it!
678void mainWin::applyNGChanges()
679{
680   QString tmp;
681   QStringList curPkgChecked;
682   QStringList newPkgs;
683   QStringList rmPkgs;
684
685   QTreeWidgetItemIterator it(treeNGPkgs);
686   while (*it) {
687         if ((*it)->checkState(0) == Qt::Checked) {
688           tmp = (*it)->text(0).section("(", 1, 1).section(")", 0, 0);
689           curPkgChecked << tmp;
690           if (pkgList.indexOf(tmp) == -1 ) 
691              newPkgs << tmp;
692         }
693         ++it;
694   }
695
696   for ( int i=0; i < pkgList.size(); ++i)
697      // Has this package been unchecked?
698      if (curPkgChecked.indexOf(pkgList.at(i)) == -1 )  {
699         // Make sure this is a package in the repo
700         // This filters out any custom packages the user may have loaded which may not exist in our repo
701         QRegExp rx("*" + pkgList.at(i) + "*");
702         rx.setPatternSyntax(QRegExp::Wildcard);
703         if ( tmpPkgList.indexOf(rx) != -1 )
704           rmPkgs << pkgList.at(i);
705      }
706
707   if ( rmPkgs.isEmpty() && newPkgs.isEmpty() ) {
708      QMessageBox::warning(this, tr("No changes"),
709        tr("No changes to make!"),
710        QMessageBox::Ok,
711        QMessageBox::Ok);
712      return;
713   }
714
715   qDebug() << "Added packages" << newPkgs;
716   qDebug() << "Removed packages" << rmPkgs;
717   pkgRemoveList = rmPkgs;
718   pkgAddList = newPkgs;
719
720   QString confirmText;
721
722   // Lets start creating our confirmation text
723   if ( ! rmPkgs.isEmpty() ) {
724      confirmText+=tr("The following packages will be removed:") + "\n"; 
725      confirmText+= "------------------------------------------\n";
726      confirmText+=rmPkgs.join("\n"); 
727      confirmText+= "\n\n" + tr("The following packages that require the above packages will also removed:") + "\n"; 
728      confirmText+= "------------------------------------------\n";
729      for ( int i=0; i < rmPkgs.size(); ++i) {
730         QRegExp rx(rmPkgs.at(i) + ":::*");
731         rx.setPatternSyntax(QRegExp::Wildcard);
732         QStringList rDeps = pkgRDepList.filter(rx);
733         for ( int r=0; r < rDeps.size(); ++r) {
734             QString pName = rDeps.at(r).section(":::", 1, 1); 
735             // Is this package installed?
736             if ( pkgList.indexOf(pName) != -1 )
737               confirmText+= pName + " ";
738         }
739      }
740   }
741
742   if ( ! newPkgs.isEmpty() ) {
743      if ( ! rmPkgs.isEmpty() )
744        confirmText+= "\n\n";
745      confirmText+=tr("The following packages will be installed:") + "\n"; 
746      confirmText+= "------------------------------------------\n";
747      confirmText+=newPkgs.join("\n"); 
748      confirmText+= "\n\n" + tr("The following dependances will also be installed:") + "\n"; 
749      confirmText+= "------------------------------------------\n";
750      for ( int i=0; i < newPkgs.size(); ++i) {
751         QRegExp rx(newPkgs.at(i) + ":::*");
752         rx.setPatternSyntax(QRegExp::Wildcard);
753         QStringList aDeps = pkgDepList.filter(rx);
754         for ( int r=0; r < aDeps.size(); ++r) {
755             QString pName = aDeps.at(r).section(":::", 1, 1); 
756             // Is this package installed?
757             if ( pkgList.indexOf(pName) == -1 )
758               confirmText+= pName + " ";
759         }
760      }
761   }
762
763   // Launch our AddPartitionDialog to add a new device
764   askUserConfirm = new dialogConfirm();
765   connect(askUserConfirm, SIGNAL(ok()),this, SLOT(slotStartNGChanges()) );
766   askUserConfirm->programInit(tr("Confirm package changes"));
767   askUserConfirm->setInfoText(QString(confirmText));
768   askUserConfirm->exec();
769
770}
771
772
773// Time to start doing our NG changes!
774void mainWin::slotStartNGChanges()
775{
776  // Init the pkg process
777  prepPkgProcess();
778
779  // Create our runlist of package commands
780  QStringList pCmds;
781 
782  if ( ! pkgRemoveList.isEmpty() ) {
783    if ( wDir.isEmpty() )
784      pCmds << "pkg" << "delete" << "-R" << "-y" << pkgRemoveList.join(" ");
785    else
786      pCmds << "chroot" << wDir << "pkg" << "delete" << "-R" << "-y" << pkgRemoveList.join(" ");
787    pkgCmdList << pCmds;
788  }
789         
790  pCmds.clear();
791
792  if ( ! pkgAddList.isEmpty() ) {
793    if ( wDir.isEmpty() )
794      pCmds << "pc-pkg" << "install" << "-y" << pkgAddList.join(" ");
795    else
796      pCmds << "chroot" << wDir << "pc-pkg" << "install" << "-y" << pkgAddList.join(" ");
797    pkgCmdList << pCmds;
798  }
799
800  // Lets kick it off now
801  startPkgProcess();
802}
803
804// Display found meta-pkg data
805void mainWin::populateMetaPkgs()
806{
807  pushPkgApply->setEnabled(false);
808  treeMetaPkgs->clear();
809  tmpMetaPkgList.clear();
810  new QTreeWidgetItem(treeMetaPkgs, QStringList() << tr("Loading... Please wait...") );
811
812  if ( ! metaPkgList.isEmpty() )
813        disconnect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), 0, 0);
814  metaPkgList.clear();
815
816  // Start the process to get meta-pkg info
817  getMetaProc = new QProcess();
818  qDebug() << "Searching for meta-pkgs...";
819  connect( getMetaProc, SIGNAL(readyReadStandardOutput()), this, SLOT(slotGetPackageDataOutput()) );
820  connect( getMetaProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotFinishLoadingMetaPkgs()) );
821  getMetaProc->setProcessChannelMode(QProcess::MergedChannels);
822  getMetaProc->start(QString("pc-metapkgmanager"), QStringList() << "list");
823
824}
825
826// Display found meta-pkg data
827void mainWin::slotFinishLoadingMetaPkgs()
828{
829
830  // Populate the metaPkgList
831  parseTmpMetaList();
832
833  treeMetaPkgs->clear();
834
835  addTreeItems(QString()); 
836
837  pushPkgApply->setEnabled(false);
838
839  connect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotDeskPkgsChanged(QTreeWidgetItem *, int)));
840}
841
842void mainWin::addTreeItems(QString parent)
843{
844  for (int z=0; z < metaPkgList.count(); ++z) {
845    if ( metaPkgList.at(z).at(3) != parent )
846      continue;
847
848    // Hide the "base-system" package, since we are installing it anyway
849    if (metaPkgList.at(z).at(0) == "base-system" )
850      return;
851
852    QTreeWidgetItem *deskItem = new QTreeWidgetItem(QStringList() << metaPkgList.at(z).at(0) );
853    deskItem->setIcon(0, QIcon(metaPkgList.at(z).at(2)));
854    deskItem->setToolTip(0, metaPkgList.at(z).at(1));
855    deskItem->setCheckState(0, Qt::Unchecked);
856
857    if ( metaPkgList.at(z).at(5) == "YES" )
858      deskItem->setCheckState(0, Qt::Checked);
859
860    if ( parent.isEmpty() ) {
861      treeMetaPkgs->addTopLevelItem(deskItem);
862    } else {
863      // Locate the parent to attach to
864      QTreeWidgetItemIterator it(treeMetaPkgs);
865      while (*it) {
866        if ((*it)->text(0) == parent ) {
867          (*it)->addChild(deskItem);
868          if ( metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::Unchecked)
869            (*it)->setCheckState(0, Qt::PartiallyChecked);
870          if ( metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::Checked)
871            (*it)->setCheckState(0, Qt::PartiallyChecked);
872          break;
873        }
874        it++;
875      }
876    }
877
878    // Now look for any possible children
879    addTreeItems(metaPkgList.at(z).at(0));   
880  }
881}
882
883// Check if a meta-pkg is installed
884bool mainWin::isMetaPkgInstalled(QString mPkg)
885{
886  QString tmp;
887  QProcess pcmp;
888  pcmp.start(QString("pc-metapkgmanager"), QStringList() << chrootArg1 << chrootArg2 << "status" << mPkg);
889  while ( pcmp.state() != QProcess::NotRunning ) {
890     pcmp.waitForFinished(50);
891     QCoreApplication::processEvents();
892  }
893
894  while (pcmp.canReadLine()) {
895     tmp = pcmp.readLine().simplified();
896     if ( tmp.indexOf("is installed") != -1 )
897     return true;
898  }
899
900  return false;
901}
902
903// Function which checks for our GUI package schema data
904void mainWin::slotGetPackageDataOutput()
905{
906  while (getMetaProc->canReadLine())
907        tmpMetaPkgList << getMetaProc->readLine().simplified();
908}
909
910// Parse the pc-metapkg saved output
911void mainWin::parseTmpMetaList()
912{
913  QString tmp, mName, mDesc, mIcon, mParent, mDesktop, mInstalled, mPkgFileList;
914  QStringList package;
915
916  for ( int i = 0 ; i < tmpMetaPkgList.size(); i++ )
917  {
918        QApplication::processEvents();
919
920        tmp = tmpMetaPkgList.at(i);
921
922        if ( tmp.indexOf("Meta Package: ") == 0) {
923                mName = tmp.replace("Meta Package: ", "");
924                continue;
925        }
926        if ( tmp.indexOf("Description: ") == 0) {
927                mDesc = tmp.replace("Description: ", "");
928                continue;
929        }
930        if ( tmp.indexOf("Icon: ") == 0) {
931                mIcon = tmp.replace("Icon: ", "");
932                mPkgFileList = mIcon;
933                mPkgFileList.replace("pkg-icon.png", "pkg-list");
934                continue;
935        }
936        if ( tmp.indexOf("Parent: ") == 0) {
937                mParent = tmp.replace("Parent: ", "");
938                continue;
939        }
940        if ( tmp.indexOf("Desktop: ") == 0) {
941                mDesktop = tmp.replace("Desktop: ", "");
942                continue;
943        }
944
945        // This is an empty category
946        if ( tmp.indexOf("Category Entry") == 0) {
947                // Now add this category to the string list
948                package.clear();
949                qDebug() << "Found Package" << mName << mDesc << mIcon << mParent << mDesktop;
950                mInstalled = "CATEGORY";
951                package << mName << mDesc << mIcon << mParent << mDesktop << mInstalled;
952                metaPkgList.append(package);
953                mName=""; mDesc=""; mIcon=""; mParent=""; mDesktop=""; mInstalled=""; mPkgFileList="";
954        }
955
956        // We have a Meta-Pkg
957        if ( tmp.indexOf("Required Packages:") == 0) {
958                // Now add this meta-pkg to the string list
959                package.clear();
960                qDebug() << "Found Package" << mName << mDesc << mIcon << mParent << mDesktop << mPkgFileList;
961
962                if ( isMetaPkgInstalled(mName) )
963                        mInstalled = "YES";
964                else
965                        mInstalled = "NO";
966
967                package << mName << mDesc << mIcon << mParent << mDesktop << mInstalled << mPkgFileList;
968                metaPkgList.append(package);
969                mName=""; mDesc=""; mIcon=""; mParent=""; mDesktop=""; mInstalled=""; mPkgFileList="";
970        }
971
972    }
973
974}
975
976void mainWin::saveMetaPkgs()
977{
978        if ( ! haveMetaPkgChanges() )
979                return;
980
981        addPkgs = getAddPkgs();
982        delPkgs = getDelPkgs(); 
983
984        startMetaChanges();
985
986}
987
988void mainWin::startMetaChanges()
989{
990
991  // Init the pkg process
992  prepPkgProcess();
993  // Create our runlist of package commands
994  QStringList pCmds;
995
996  if ( ! delPkgs.isEmpty() ) {
997    if ( wDir.isEmpty() )
998      pCmds << "pc-metapkgmanager" << "del" << delPkgs;
999    else 
1000      pCmds << "chroot" << wDir << "pc-metapkgmanager" << "del" << delPkgs;
1001    pkgCmdList << pCmds;
1002  }
1003 
1004  pCmds.clear();
1005
1006  if ( ! addPkgs.isEmpty() ) {
1007    if ( wDir.isEmpty() )
1008      pCmds << "pc-metapkgmanager" << "add" << addPkgs;
1009    else 
1010      pCmds << "chroot" << wDir << "pc-metapkgmanager" << "add" << addPkgs;
1011    pkgCmdList << pCmds;
1012  }
1013
1014  // Lets kick it off now
1015  startPkgProcess();
1016}
1017
1018bool mainWin::haveAMetaDesktop()
1019{
1020        // If running in a chroot we can skip this check
1021        if ( ! chrootArg1.isEmpty() )
1022          return true;
1023       
1024        QTreeWidgetItemIterator it(treeMetaPkgs);
1025        while (*it) {
1026         if ( ((*it)->checkState(0) == Qt::Checked) || ((*it)->checkState(0) == Qt::PartiallyChecked) )
1027           for (int z=0; z < metaPkgList.count(); ++z)
1028             if ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(4) == "YES" )
1029                return true;
1030         ++it;
1031        }
1032
1033        QMessageBox::warning(this, tr("No Desktop"),
1034          tr("No desktops have been selected! Please choose at least one desktop before saving."),
1035          QMessageBox::Ok,
1036          QMessageBox::Ok);
1037
1038        return false;
1039}
1040
1041bool mainWin::haveMetaPkgChanges()
1042{
1043        QTreeWidgetItemIterator it(treeMetaPkgs);
1044        while (*it) {
1045          for (int z=0; z < metaPkgList.count(); ++z)
1046            // See if any packages status have changed
1047            if ( ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::Unchecked ) \
1048              || ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::PartiallyChecked ) \
1049              || ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::Checked ) )
1050                return true;
1051         ++it;
1052        }
1053
1054        return false;
1055}
1056
1057QString mainWin::getAddPkgs()
1058{
1059        QString tmp;
1060        QTreeWidgetItemIterator it(treeMetaPkgs);
1061        while (*it) {
1062          for (int z=0; z < metaPkgList.count(); ++z)
1063            // See if any packages status have changed
1064            if ( ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::Checked ) || \
1065                 ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::PartiallyChecked ) )
1066                if ( tmp.isEmpty() )
1067                        tmp = (*it)->text(0);
1068                else
1069                        tmp = tmp + "," + (*it)->text(0);
1070         ++it;
1071        }
1072
1073        return tmp;
1074}
1075
1076QString mainWin::getDelPkgs()
1077{
1078        QString tmp;
1079        QTreeWidgetItemIterator it(treeMetaPkgs);
1080        while (*it) {
1081          for (int z=0; z < metaPkgList.count(); ++z)
1082            // See if any packages status have changed
1083            if ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::Unchecked )
1084                if ( tmp.isEmpty() )
1085                        tmp = (*it)->text(0);
1086                else
1087                        tmp = tmp + "," + (*it)->text(0);
1088         ++it;
1089        }
1090
1091        return tmp;
1092}
1093
1094
1095// Time to save meta-pkgs
1096void mainWin::slotApplyMetaChanges() {
1097    saveMetaPkgs();
1098}
1099
1100
1101
1102// The User changed the tree widget checked / unchecked stuff sanity check
1103void mainWin::slotDeskPkgsChanged(QTreeWidgetItem *aItem, int __unused)
1104{
1105        if (!aItem)
1106          return;
1107
1108        disconnect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), 0, 0);
1109
1110        if (aItem->childCount() == 0) {
1111                if (aItem->checkState(0) == Qt::Checked && aItem->parent() )
1112                        if ( allChildrenPkgsChecked(aItem->parent()->text(0)))
1113                                aItem->parent()->setCheckState(0, Qt::Checked); 
1114                        else
1115                                aItem->parent()->setCheckState(0, Qt::PartiallyChecked);       
1116                if (aItem->checkState(0) == Qt::Unchecked && aItem->parent() )
1117                        if ( ! allChildrenPkgsUnchecked(aItem->parent()->text(0)))
1118                                aItem->parent()->setCheckState(0, Qt::PartiallyChecked);       
1119
1120
1121        } else {
1122                if (aItem->checkState(0) == Qt::Checked )
1123                        checkAllChildrenPkgs(aItem->text(0));
1124                else
1125                        uncheckAllChildrenPkgs(aItem->text(0));
1126        }
1127       
1128
1129    connect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotDeskPkgsChanged(QTreeWidgetItem *, int)));
1130
1131        if ( haveMetaPkgChanges() )
1132                pushPkgApply->setEnabled(true);
1133        else
1134                pushPkgApply->setEnabled(false);
1135}
1136
1137// Check the "parent" app to see if all its children are checked or not
1138bool mainWin::allChildrenPkgsChecked(QString parent)
1139{
1140        QTreeWidgetItemIterator it(treeMetaPkgs);
1141        while (*it) {
1142         if ((*it)->text(0) == parent ) {
1143           if ( (*it)->childCount() <= 0)
1144             return true;
1145
1146           for ( int i = 0; i < (*it)->childCount() ; ++i) {
1147             if ( ! allChildrenPkgsChecked((*it)->child(i)->text(0)))
1148               return false;
1149
1150             if ((*it)->child(i)->checkState(0) != Qt::Checked ) 
1151               return false;
1152           }
1153         }
1154         ++it;
1155        }
1156        return true;
1157}
1158
1159// Check the "parent" app to see if all its children are unchecked or not
1160bool mainWin::allChildrenPkgsUnchecked(QString parent)
1161{
1162        QTreeWidgetItemIterator it(treeMetaPkgs);
1163        while (*it) {
1164         if ((*it)->text(0) == parent ) {
1165           if ( (*it)->childCount() <= 0)
1166             return true;
1167
1168           for ( int i = 0; i < (*it)->childCount() ; ++i) {
1169             if ( ! allChildrenPkgsUnchecked((*it)->child(i)->text(0)))
1170               return false;
1171
1172             if ((*it)->child(i)->checkState(0) != Qt::Unchecked ) 
1173               return false;
1174           }
1175         }
1176         ++it;
1177        }
1178        return true;
1179}
1180
1181// Check all children of parent
1182void mainWin::checkAllChildrenPkgs(QString parent)
1183{
1184        QTreeWidgetItemIterator it(treeMetaPkgs);
1185        while (*it) {
1186         if (! (*it)->parent()) {
1187           ++it;
1188           continue;
1189         } 
1190
1191         // Lets walk the tree see what pops up
1192         bool pFound=false;
1193         QTreeWidgetItem *itP = (*it)->parent();
1194         do {
1195           pFound=false;
1196           if (itP->text(0) == parent) {
1197             (*it)->setCheckState(0, Qt::Checked);
1198             break;
1199           }
1200           if ( itP->parent() ) {
1201             itP = itP->parent();
1202             pFound=true;
1203           }
1204         } while (pFound);
1205
1206         ++it;
1207       }
1208}
1209
1210// UnCheck all children of parent
1211void mainWin::uncheckAllChildrenPkgs(QString parent)
1212{
1213        QTreeWidgetItemIterator it(treeMetaPkgs);
1214        while (*it) {
1215         if (! (*it)->parent()) {
1216           ++it;
1217           continue;
1218         } 
1219
1220         // Lets walk the tree see what pops up
1221         bool pFound=false;
1222         QTreeWidgetItem *itP = (*it)->parent();
1223         do {
1224           pFound=false;
1225           if (itP->text(0) == parent) {
1226             (*it)->setCheckState(0, Qt::Unchecked);
1227             break;
1228           }
1229           if ( itP->parent() ) {
1230             itP = itP->parent();
1231             pFound=true;
1232           }
1233         } while (pFound);
1234
1235         ++it;
1236       }
1237}
1238
1239void mainWin::slotMetaRightClick()
1240{
1241        QTreeWidgetItemIterator it(treeMetaPkgs);
1242        while (*it) {
1243          for (int z=0; z < metaPkgList.count(); ++z) {
1244            if ( (*it)->isSelected() && (*it)->text(0) == metaPkgList.at(z).at(0) ) {
1245              if (metaPkgList.at(z).at(5) == "CATEGORY")
1246                return;
1247              popup = new QMenu;
1248              popup->setTitle((*it)->text(0));
1249              popup->addAction(tr("View Packages"), this, SLOT(slotMetaViewPkgs()));
1250              popup->exec( QCursor::pos() );
1251            }
1252          }
1253         ++it;
1254        }
1255}
1256
1257void mainWin::slotMetaViewPkgs()
1258{
1259        QStringList packageList;
1260        QTreeWidgetItemIterator it(treeMetaPkgs);
1261        while (*it) {
1262          for (int z=0; z < metaPkgList.count(); ++z) {
1263            if ( (*it)->isSelected() && (*it)->text(0) == metaPkgList.at(z).at(0) ) {
1264 
1265                QFile pList(metaPkgList.at(z).at(6));
1266                if ( ! pList.exists() )
1267                  return;
1268               
1269                if ( ! pList.open(QIODevice::ReadOnly | QIODevice::Text))
1270                  return;
1271
1272                while ( !pList.atEnd() )
1273                  packageList << pList.readLine().simplified();
1274
1275                pList.close();
1276                packageList.sort();
1277                       
1278                dIB = new dialogInfo();
1279                dIB->programInit(tr("Package Listing for:") + " " + (*it)->text(0));
1280                dIB->setInfoText(packageList.join("\n"));
1281                dIB->show();
1282            }
1283          }
1284         ++it;
1285        }
1286}
1287
1288QString mainWin::getLineFromCommandOutput( QString cmd )
1289{
1290        FILE *file = popen(cmd.toLatin1(),"r");
1291 
1292        char buffer[100];
1293 
1294        QString line = "";
1295        char firstChar;
1296
1297        if ((firstChar = fgetc(file)) != -1){
1298                line += firstChar;
1299                line += fgets(buffer,100,file);
1300        }
1301        pclose(file);
1302        return line.simplified();
1303}
Note: See TracBrowser for help on using the repository browser.