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

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

Some cosmetic improvements to PKGNG manager, now when we click a package
we will be shown a details widget, which has name / size / desc / options
/ depends / URL

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