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

releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1
Last change on this file since e3174a0a was 405f33b, checked in by Kris Moore <kris@…>, 11 months ago

Fix a bug with stray EVENT_PIPE usage during package install

  • Property mode set to 100644
File size: 46.6 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(pushCloseAdv, SIGNAL(clicked()), this, SLOT(slotCloseAdvClicked()));
38  connect(buttonRescanPkgs, SIGNAL(clicked()), this, SLOT(slotRescanPkgsClicked()));
39  connect(pushPkgApply, SIGNAL( clicked() ), this, SLOT( slotApplyClicked() ) );
40  connect(action_Quit, SIGNAL( triggered(bool) ), this, SLOT( slotCloseClicked() ) );
41  connect(action_Configuration, SIGNAL( triggered(bool) ), this, SLOT( slotConfigClicked() ) );
42  connect(tool_search, SIGNAL( clicked() ), this, SLOT( slotSearchPackages() ) );
43  connect(line_search, SIGNAL( returnPressed()), this, SLOT( slotSearchPackages()) );
44       
45  // Setup the action group
46  viewGroup = new QActionGroup(this);
47  viewGroup->addAction(action_Basic);
48  viewGroup->addAction(action_Advanced);
49
50  treeMetaPkgs->setContextMenuPolicy(Qt::CustomContextMenu);
51  connect(treeMetaPkgs, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(slotMetaRightClick()) );
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_Basic->setChecked(false);
67     action_Basic->setEnabled(false);
68     action_Advanced->setChecked(true);
69     action_Advanced->setEnabled(false);
70  } else {
71    // Connect our view modes only when not running via in a chroot
72    connect(action_Basic, SIGNAL( triggered(bool) ), this, SLOT( slotViewChanged() ) );
73    connect(action_Advanced, SIGNAL( triggered(bool) ), this, SLOT( slotViewChanged() ) );
74  }
75
76  initMetaWidget();
77
78  //Change output palette (white on black)
79  QPalette palette = textDisplayOut->palette();
80  palette.setColor(QPalette::Base, Qt::black);
81  palette.setColor(QPalette::Text, Qt::white);
82  textDisplayOut->setPalette(palette);
83}
84
85void mainWin::slotViewChanged()
86{
87  QString mode;
88  if ( action_Basic->isChecked() ) {
89    stackedPkgView->setCurrentIndex(0);
90    mode="Basic";
91  } else {
92    mode="Advanced";
93    stackedPkgView->setCurrentIndex(1);
94  }
95
96  // Save the mode as the default at next open
97  QSettings settings("PC-BSD", "PackageManager");
98  settings.setValue("view/mode", mode);
99
100  // Changed view, lets refresh
101  initMetaWidget();
102}
103
104void mainWin::slotRescanPkgsClicked()
105{
106  // Check for pkg updates
107  checkMPKGUpdates();
108}
109
110void mainWin::slotApplyClicked() {
111  // Running in basic mode
112  if ( stackedPkgView->currentIndex() == 0 )
113  {
114     saveMetaPkgs();   
115  } else {
116     // Running in advanced mode
117     applyNGChanges();
118  }
119
120}
121
122void mainWin::slotSearchPackages(){
123  QString pkgSearch = line_search->text();
124  if(pkgSearch.isEmpty()){ return; }
125  qDebug() << "Search for package:" <<pkgSearch;
126  //Get the pointer to the proper treewidget
127  QTreeWidget *TW = treeNGPkgs;
128  if( stackedPkgView->currentIndex() == 0 ){ TW = treeMetaPkgs; }
129  //Make sure the tree widget is not empty
130  if(TW->topLevelItemCount() < 2){ return; }
131  //Get the currently selected item
132  QTreeWidgetItem *CI = TW->currentItem();
133  bool found=false; bool atTop=false;
134  if(CI == 0){ atTop=true; }
135  //Now search the tree, starting at that item
136  found = performSearch(pkgSearch, TW, CI);
137  if(!found && !atTop){
138    //Ask whether to restart the search at the top
139    if(QMessageBox::Yes == QMessageBox::question(this,tr("No Search Results"),tr("Do you want to continue the search from the top?"),QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) ){
140      //Restart the search from the top
141      found = performSearch(pkgSearch, TW, 0);
142    }
143  }
144  if(!found){
145    QMessageBox::information(this, tr("No Search Results"), tr("No packages could be found with that search term. Please adjust it and try again.") );
146  }
147  qDebug() << " - Search Finished";
148}
149
150bool mainWin::performSearch(QString pkgSearch, QTreeWidget *TW, QTreeWidgetItem *SI){
151  //Start Iterating over the tree
152  bool found=false;
153  bool started = false;
154  //if(SI==0){ started = true; }
155  for(int p=0; (p<TW->topLevelItemCount()) && !found; p++){
156    //Check the actual item itself
157    QTreeWidgetItem *CI = TW->topLevelItem(p);
158    if(started && CI->text(0).contains(pkgSearch, Qt::CaseInsensitive)){
159      TW->setCurrentItem(CI);
160      TW->scrollToItem(CI);
161      found=true;         
162    }else{   
163      found = searchChildren(pkgSearch, TW, CI, started, SI);
164    }
165  }
166  return found;
167}
168
169bool mainWin::searchChildren(QString srch, QTreeWidget *TW, QTreeWidgetItem *CI, bool &started, QTreeWidgetItem *SI){
170  //This is a recursive function for searching all the children of a particular item
171  // TW - TreeWidget pointer
172  // CI - Current TreeWidget Item (to search the children of)
173  // SI - Start Item (Try to start searching right after this item - optional)
174  // bool started - Start Item found and search has been started (optional input/output)
175       
176  //qDebug() << "Search Children of:" << CI->text(0) << srch << started;
177  //Check for the start position
178  int start = -1;
179  if(SI == 0 || SI == CI){
180    //No search item to start at
181    start = 0;
182    started = true;
183  }else if( !started){
184    QTreeWidgetItem *PI = SI;
185      while( (start == -1) && (PI!=0) ){
186        start = CI->indexOfChild(PI);
187        PI = PI->parent(); //look up one more layer to make sure it is not a child of one of these items
188      }
189  }else{ start = 0; } //start with the first child
190  //Now quit if the start item is not found here
191  if(start == -1){ started = false; return false; }
192 
193  //Now start searching
194  bool found = false;
195  for(int i=start; (i<CI->childCount()) && !found ; i++){
196    if(started){
197      //Check this item
198      if(CI->child(i)->text(0).contains(srch, Qt::CaseInsensitive)){
199        TW->setCurrentItem(CI->child(i));
200        TW->scrollToItem(CI->child(i));
201        found=true;
202        break;
203      }
204    }else if( SI == CI->child(i) ){
205      started = true; //but don't look at this item, continue on to the next one (or children)
206    }
207    if(found){ break; }
208    else if(CI->child(i)->childCount() > 0){
209      //recursively search this items children
210      found = searchChildren(srch, TW, CI->child(i), started, SI); 
211    }
212  }
213  return found;
214}
215
216void mainWin::checkMPKGUpdates() {
217
218  QString line, tmp, name, pkgname, pkgover, pkgnver;
219  QStringList up, listPkgs;
220  bool haveUpdates = false;
221  int totPkgs=0;
222  buttonRescanPkgs->setEnabled(false);
223  pushUpdatePkgs->setEnabled(false);
224  listViewUpdatesPkgs->clear();
225  groupUpdatesPkgs->setTitle(tr("Checking for updates"));
226
227  QProcess p;
228  if ( wDir.isEmpty() )
229     p.start(QString("pc-updatemanager"), QStringList() << "pkgcheck");
230  else
231     p.start(QString("chroot"), QStringList() << wDir << "pc-updatemanager" << "pkgcheck");
232  while(p.state() == QProcess::Starting || p.state() == QProcess::Running)
233     QCoreApplication::processEvents();
234
235  if ( p.exitCode() != 0 )
236    QMessageBox::warning(this, tr("Package Check"), tr("Unable to check for package updates!"));
237
238  while (p.canReadLine()) {
239    line = p.readLine().simplified();
240    qDebug() << line;
241    if ( line.indexOf("Upgrading") == 0 ) {
242      tmp = line;
243      pkgname = tmp.section(" ", 1, 1);
244      pkgname.replace(":", "");
245      pkgover = tmp.section(" ", 2, 2);
246      pkgnver = tmp.section(" ", 4, 4);
247      QTreeWidgetItem *myItem = new QTreeWidgetItem(QStringList() << pkgname << pkgover << pkgnver);
248      listViewUpdatesPkgs->addTopLevelItem(myItem);
249      haveUpdates = true;
250      totPkgs++;
251    } // End of upgrading section
252    if ( line.indexOf("Reinstalling") == 0 ) {
253      tmp = line;
254      pkgname = tmp.section(" ", 1, 1);
255      pkgover = pkgname.section("-", -1);
256      pkgname.truncate(pkgname.lastIndexOf("-"));
257      pkgnver = tmp.section(" ", 2);
258      QTreeWidgetItem *myItem = new QTreeWidgetItem(QStringList() << pkgname << pkgover << pkgnver);
259      listViewUpdatesPkgs->addTopLevelItem(myItem);
260      haveUpdates = true;
261      totPkgs++;
262    }
263  }
264
265  buttonRescanPkgs->setEnabled(true);
266  pushUpdatePkgs->setEnabled(haveUpdates);
267  if ( totPkgs > 0 ) {
268    tabUpdates->setTabText(1, tr("Package Updates (%1)").arg(totPkgs));
269    groupUpdatesPkgs->setTitle(tr("Available updates"));
270  } else {
271    tabUpdates->setTabText(1, tr("Package Updates"));
272    groupUpdatesPkgs->setTitle(tr("No available updates"));
273  }
274 
275}
276
277void mainWin::slotSingleInstance() {
278   this->hide();
279   this->showNormal();
280   this->activateWindow();
281   this->raise();
282}
283
284void mainWin::slotCloseClicked() {
285   close();
286}
287
288void mainWin::slotUpdatePkgsClicked() {
289  dPackages = false;
290  uPackages = false;
291
292  // Set the type of pkg command
293  pkgProcessType="update";
294
295  // Init the pkg process
296  prepPkgProcess();
297
298  // Create our runlist of package commands
299  QStringList pCmds;
300
301  if ( wDir.isEmpty() )
302    pCmds << "pc-updatemanager" << "pkgupdate";
303  else
304    pCmds << "chroot" << wDir << "pc-updatemanager" << "pkgupdate";
305
306  // Setup our runList
307  pkgCmdList << pCmds;
308
309  // Start the updating now
310  startPkgProcess();
311
312  textStatus->setText(tr("Starting package updates..."));
313
314}
315
316QString mainWin::getConflictDetailText() {
317
318  QStringList ConList = ConflictList.split(" ");
319  QStringList tmpDeps;
320  QString retText;
321
322  for (int i = 0; i < ConList.size(); ++i) {
323    QProcess p;
324    tmpDeps.clear();
325
326    if ( wDir.isEmpty() )
327      p.start("pkg", QStringList() << "rquery" << "%rn-%rv" << ConList.at(i));
328    else
329      p.start("chroot", QStringList() << wDir << "pkg" "rquery" << "%rn-%rv" << ConList.at(i) );
330
331    if(p.waitForFinished()) {
332      while (p.canReadLine()) {
333        tmpDeps << p.readLine().simplified();
334      }
335    }
336    retText+= ConList.at(i) + " " + tr("required by:") + "\n" + tmpDeps.join(" ");
337  }
338
339  return retText;
340}
341
342void mainWin::prepPkgProcess() {
343  pkgCmdList.clear();
344  textDisplayOut->clear();
345  pkgHasFailed=false;
346}
347
348void mainWin::startPkgProcess() {
349
350  if ( pkgCmdList.isEmpty() )
351    return;
352  if ( pkgCmdList.at(0).at(0).isEmpty() )
353     return; 
354
355  // Get the command name
356  QString cmd;
357  cmd = pkgCmdList.at(0).at(0);
358
359  // Get any optional flags
360  QStringList flags;
361  for (int i = 0; i < pkgCmdList.at(0).size(); ++i) {
362     if ( i == 0 )
363       continue;
364     flags << pkgCmdList.at(0).at(i);
365  } 
366
367  qDebug() << cmd + " " + flags.join(" ");
368
369  system("rm /tmp/pkg-fifo 2>/dev/null");
370
371  // Create the EVENT_PIPE
372  if ( wDir.isEmpty() )
373    system("mkfifo /tmp/pkg-fifo ; sleep 1");
374  else
375    system("mkfifo " + wDir.toLatin1() + "/tmp/pkg-fifo ; sleep 1");
376
377  // Open and connect the EVENT_PIPE
378  eP = new QProcess();
379  eP->setProcessChannelMode(QProcess::MergedChannels);
380  connect( eP, SIGNAL(readyRead()), this, SLOT(slotReadEventPipe()) );
381  connect( eP, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotReadEventPipe()) );
382  eP->start(QString("cat"), QStringList() << "-u" << wDir + "/tmp/pkg-fifo");
383  qDebug() << "Starting EVENT_PIPE";
384  eP->waitForStarted();
385
386  // Setup the first process
387  uProc = new QProcess();
388  QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
389  env.insert("PCFETCHGUI", "YES");
390  env.insert("EVENT_PIPE", "/tmp/pkg-fifo");
391  uProc->setProcessEnvironment(env);
392  uProc->setProcessChannelMode(QProcess::MergedChannels);
393
394  // Connect the slots
395  connect( uProc, SIGNAL(readyReadStandardOutput()), this, SLOT(slotReadPkgOutput()) );
396  connect( uProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotPkgDone()) );
397
398  uProc->start(cmd, flags);
399
400  stackedTop->setCurrentIndex(1);
401
402  progressUpdate->setRange(0, 0 );
403  progressUpdate->setValue(0);
404
405}
406
407void mainWin::slotReadPkgOutput() {
408   QString line, tmp, cur, tot, fname;
409   int curItem, totItem;
410   bool ok;
411
412   while (uProc->canReadLine()) {
413     line = uProc->readLine().simplified();
414     qDebug() << line;
415
416     // Empty line? We can skip it
417     if ( line.isEmpty() )
418        continue;
419
420     tmp = line;
421     tmp.truncate(50);
422
423     // Flags we can parse out and not show the user
424
425     // Check if we have crashed into a conflict and ask the user what to do
426     if ( line.indexOf("PKGCONFLICTS: ") == 0 ) {
427        tmp = line; 
428        tmp.replace("PKGCONFLICTS: ", "");
429        ConflictList = tmp;
430        continue;
431     }
432     if ( line.indexOf("PKGREPLY: ") == 0 ) {
433        QString ans;
434        tmp = line; 
435        tmp.replace("PKGREPLY: ", "");
436        QMessageBox msgBox;
437        msgBox.setText(tr("The following packages are causing conflicts with the selected changes and can be automatically removed. Continue?") + "\n" + ConflictList);
438        msgBox.setStandardButtons(QMessageBox::Yes|QMessageBox::No);
439        msgBox.setDetailedText(getConflictDetailText());
440        msgBox.setDefaultButton(QMessageBox::No);
441        if ( msgBox.exec() == QMessageBox::Yes) {
442          // We will try to fix conflicts
443          ans="yes";
444        } else {
445          // We will fail :(
446          QMessageBox::warning(this, tr("Package Conflicts"),
447          tr("You may need to manually fix the conflicts before trying again."),
448          QMessageBox::Ok,
449          QMessageBox::Ok);
450          ans="no";
451        }
452
453        QFile pkgTrig( tmp );
454        if ( pkgTrig.open( QIODevice::WriteOnly ) ) {
455           QTextStream streamTrig( &pkgTrig );
456           streamTrig << ans;
457           pkgTrig.close();
458        }
459        continue;
460     }
461
462     if ( line.indexOf("FETCH: ") == 0 ) { 
463        progressUpdate->setValue(progressUpdate->value() + 1); 
464        tmp = line; 
465        tmp = tmp.remove(0, tmp.lastIndexOf("/") + 1); 
466        progressUpdate->setRange(0, 0);
467        progressUpdate->setValue(0);
468        curFileText = tr("Downloading: %1").arg(tmp); 
469        textStatus->setText(tr("Downloading: %1").arg(tmp)); 
470        continue;
471     } 
472     if ( line.indexOf("FETCHDONE") == 0 )
473        continue;
474
475     if ( line.indexOf("SIZE: ") == 0 ) {
476          bool ok, ok2;
477          line.replace("SIZE: ", "");
478          line.replace("DOWNLOADED: ", "");
479          line.replace("SPEED: ", "");
480          line.section(" ", 0, 0).toInt(&ok);
481          line.section(" ", 1, 1).toInt(&ok2);
482   
483          if ( ok && ok2 ) {
484            QString unit;
485            int tot = line.section(" ", 0, 0).toInt(&ok);
486            int cur = line.section(" ", 1, 1).toInt(&ok2);
487            QString percent = QString::number( (float)(cur * 100)/tot );
488            QString speed = line.section(" ", 2, 3);
489
490            // Get the MB downloaded / total
491            if ( tot > 2048 ) {
492              unit="MB";
493              tot = tot / 1024;
494              cur = cur / 1024;
495            } else {
496              unit="KB";
497            }
498
499            QString ProgressString=QString("(%1" + unit + " of %2" + unit + " at %3)").arg(cur).arg(tot).arg(speed);
500            progressUpdate->setRange(0, tot);
501            progressUpdate->setValue(cur);
502            textStatus->setText(curFileText + " " + ProgressString); 
503         }
504         continue;
505     }
506
507
508     // Now show output on GUI
509     textDisplayOut->insertPlainText(line + "\n");
510     textDisplayOut->moveCursor(QTextCursor::End);
511
512
513     // Any other flags to look for?
514     /////////////////////////////////////////////////////
515     if ( line.indexOf("to be downloaded") != -1 ) {
516       textStatus->setText(tr("Downloading packages..."));
517       curUpdate = 0;
518       progressUpdate->setValue(0);
519       continue;
520     }
521     if ( line.indexOf("Checking integrity") == 0 ) {
522       textStatus->setText(line);
523       uPackages = true;
524       dPackages = false;
525       curUpdate = 0;
526       progressUpdate->setValue(0);
527       progressUpdate->setRange(0, 0);
528       progressUpdate->setValue(0);
529       continue;
530     }
531     
532     if ( uPackages ) {
533       if ( line.indexOf("[") == 0 ) {
534         tmp=line.section("]", 1, 1);
535         textStatus->setText(tmp);
536         tmp=line.section("/", 0, 0).replace("[", "");
537         tmp.toInt(&ok);
538         if (ok)  {
539           curItem=tmp.toInt(&ok);
540           tmp=line.section("/", 1, 1).section("]", 0, 0);
541           tmp.toInt(&ok);
542           if (ok)  {
543             totItem=tmp.toInt(&ok);
544             progressUpdate->setRange(0, totItem);
545             progressUpdate->setValue(curItem);
546           }
547
548         }
549       }
550       continue;
551     }
552
553   } // end of while
554}
555
556void mainWin::slotPkgDone() {
557
558  if ( uProc->exitCode() != 0 )
559    pkgHasFailed=true;
560
561  // Close the event pipe
562  eP->kill();
563  qDebug() << "Stopping EVENT_PIPE";
564  system("rm " + wDir.toLatin1() + "/tmp/pkg-fifo");
565
566  // Run the next command on the stack if necessary
567  if (  pkgCmdList.size() > 1 ) {
568        pkgCmdList.removeAt(0); 
569        startPkgProcess();     
570        return;
571  }
572
573  // Eventually we will have more stuff to do after running a package command
574  //if ( pkgProcessType == "update" )
575  //{
576  //}
577
578  // Nothing left to run! Lets wrap up
579  QFile sysTrig( SYSTRIGGER );
580  if ( sysTrig.open( QIODevice::WriteOnly ) ) {
581    QTextStream streamTrig( &sysTrig );
582     streamTrig << "INSTALLFINISHED: ";
583  }
584
585  if ( pkgHasFailed ) {
586    QFile file( "/tmp/pkg-output.log" );
587    if ( file.open( QIODevice::WriteOnly ) ) {
588       QTextStream stream( &file );
589       stream << textDisplayOut->toPlainText();
590       file.close();
591    }
592    QMessageBox::warning(this, tr("Failed!"), tr("The package commands failed. A copy of the output was saved to /tmp/pkg-output.log"));
593  } else
594    QMessageBox::warning(this, tr("Finished!"), tr("Package changes complete!" ));
595
596  // Clear out the old commands
597  pkgCmdList.clear();
598
599  // Switch back to our main display
600  stackedTop->setCurrentIndex(0);
601 
602  // Re-init the meta-widget
603  initMetaWidget();
604
605}
606
607/*****************************************
608Code for package stuff
609******************************************/
610
611void mainWin::initMetaWidget()
612{
613  qDebug() << "Starting metaWidget...";
614  groupInfo->setVisible(false);
615  //Make sure the search box is disabled at startup
616  tool_search->setEnabled(false);
617
618  // We will refresh the update tab after, clear it out for now
619  buttonRescanPkgs->setEnabled(false);
620  pushUpdatePkgs->setEnabled(false);
621  listViewUpdatesPkgs->clear();
622  groupUpdatesPkgs->setTitle(tr("Reading package database..."));
623
624  // Running in basic mode
625  if ( stackedPkgView->currentIndex() == 0 )
626  {
627    populateMetaPkgs();
628    // Connect our slots
629  } else {
630    // Running in advanced mode
631    populateNGPkgs();
632  }
633}
634
635void mainWin::populateNGPkgs()
636{
637  pushPkgApply->setEnabled(false);
638  treeNGPkgs->clear();
639  tmpPkgList.clear();
640  new QTreeWidgetItem(treeNGPkgs, QStringList() << tr("Loading... Please wait...") );
641
642  if ( ! pkgList.isEmpty() ) {
643        disconnect(treeNGPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), 0, 0);
644        disconnect(treeNGPkgs, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), 0, 0);
645  }
646  pkgList.clear();
647  selPkgList.clear();
648
649  // Start the process to get meta-pkg info
650  getNGProc = new QProcess();
651  qDebug() << "Searching for pkgs...";
652  connect( getNGProc, SIGNAL(readyReadStandardOutput()), this, SLOT(slotGetNGPackageDataOutput()) );
653  connect( getNGProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotGetNGInstalledPkgs()) );
654  getNGProc->setProcessChannelMode(QProcess::MergedChannels);
655  if ( wDir.isEmpty() )
656    getNGProc->start(QString("pkg"), QStringList() << "rquery" << "-a" << "%o:::%n-%v:::%c:::%sh:::%m:::%w");
657  else
658    getNGProc->start(QString("chroot"), QStringList() << wDir << "pkg" << "rquery" << "-a" << "%o:::%n-%v:::%c:::%sh:::%m:::%w");
659
660}
661
662void mainWin::slotGetNGPackageDataOutput()
663{
664   while (getNGProc->canReadLine())
665     tmpPkgList << getNGProc->readLine().simplified();
666}
667
668void mainWin::slotGetNGInstalledDataOutput()
669{
670   while (getNGProc->canReadLine())
671     pkgList << getNGProc->readLine().simplified();
672}
673
674void mainWin::slotGetNGInstalledPkgs() {
675
676  qDebug() << "Building dependancy lists...";
677  QProcess p;
678  pkgDepList.clear();
679  if ( wDir.isEmpty() )
680    p.start("pkg", QStringList() << "rquery" << "-a" << "%n-%v:::%dn-%dv");
681  else
682    p.start("chroot", QStringList() << wDir << "pkg" << "rquery" << "-a" << "%n-%v:::%dn-%dv" );
683  while(p.state() == QProcess::Starting || p.state() == QProcess::Running) {
684      p.waitForFinished(200);
685      QCoreApplication::processEvents();
686  }
687  while (p.canReadLine()) {
688    pkgDepList << p.readLine().simplified();
689  }
690
691  getNGProc = new QProcess();
692  qDebug() << "Searching for installed pkgs...";
693  connect( getNGProc, SIGNAL(readyReadStandardOutput()), this, SLOT(slotGetNGInstalledDataOutput()) );
694  connect( getNGProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotFinishLoadingNGPkgs()) );
695  getNGProc->setProcessChannelMode(QProcess::MergedChannels);
696  if ( wDir.isEmpty() )
697    getNGProc->start(QString("pkg"), QStringList() << "info" << "-aq" );
698  else
699    getNGProc->start(QString("chroot"), QStringList() << wDir << "pkg" << "info" << "-aq");
700
701}
702
703void mainWin::slotFinishLoadingNGPkgs()
704{
705  treeNGPkgs->clear();
706
707  addNGItems();
708
709  pushPkgApply->setEnabled(false);
710
711  connect(treeNGPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotEnableApply()));
712  connect(treeNGPkgs, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(slotNGItemChanged()));
713  //Enable the search option
714  tool_search->setEnabled(true);
715  // Now we can look for updates safely
716  slotRescanPkgsClicked();
717}
718
719void mainWin::slotNGItemChanged()
720{
721  if ( ! treeNGPkgs->currentItem() ) {
722     groupInfo->setVisible(false);
723     return;
724  }
725  QString desc, size, maint, weburl;
726
727  QTreeWidgetItem *cItem = treeNGPkgs->currentItem();
728  QString pName = cItem->text(0).section("(", 1, 1).section(")", 0, 0);
729  if ( pName.isEmpty() ) {
730     groupInfo->setVisible(false);
731     return;
732  }
733  qDebug() << "Checking: " + pName;
734
735  QRegExp rx("*:::" + pName + ":::*");
736  rx.setPatternSyntax(QRegExp::Wildcard);
737  int pAt = tmpPkgList.indexOf(rx);
738  if (pAt == -1 ) {
739     qDebug() << "Unable to find package: " + pName;
740     groupInfo->setVisible(false);
741     return;
742  }
743
744  desc = tmpPkgList.at(pAt).section(":::", 2,2);
745  size = tmpPkgList.at(pAt).section(":::", 3,3);
746  maint = tmpPkgList.at(pAt).section(":::", 4,4);
747  weburl = tmpPkgList.at(pAt).section(":::", 5,5);
748  labelPkgNameVer->setText(pName);
749  labelSize->setText(size);
750  labelWeb->setText(weburl);
751  textDesc->setText(desc);
752  textOptions->clear();
753
754  QCoreApplication::processEvents();
755
756  // Display the depends
757  QString depTxt;
758  QRegExp rxd( pName + ":::*");
759  rxd.setPatternSyntax(QRegExp::Wildcard);
760  QStringList aDeps = pkgDepList.filter(rxd);
761  for ( int r=0; r < aDeps.size(); ++r) {
762      QString dName = aDeps.at(r).section(":::", 1, 1);
763      // Is this package installed?
764      if ( pkgList.indexOf(dName) != -1 )
765         depTxt+= dName + " (Installed)\n";
766      else
767         depTxt+= dName + "\n";
768  }
769
770  textDeps->setText(depTxt);
771
772  groupInfo->setVisible(true);
773
774  getNGInfo = new QProcess();
775  qDebug() << "Getting Info for " + pName;
776  connect( getNGInfo, SIGNAL(readyReadStandardOutput()), this, SLOT(slotNGReadInfo()) );
777  getNGInfo->setProcessChannelMode(QProcess::MergedChannels);
778  if ( wDir.isEmpty() )
779    getNGInfo->start(QString("pkg"), QStringList() << "rquery" << "%Ok=%Ov" << pName );
780  else
781    getNGInfo->start(QString("chroot"), QStringList() << wDir << "pkg" << "rquery" << "%Ok=%Ov" << pName);
782}
783
784void mainWin::slotNGReadInfo()
785{
786  while (getNGInfo->canReadLine())
787     textOptions->append(getNGInfo->readLine().simplified() );
788
789  textOptions->moveCursor(QTextCursor::Start);
790}
791
792void mainWin::slotEnableApply()
793{
794  pushPkgApply->setEnabled(true);
795}
796
797void mainWin::addNGItems()
798{
799   QString curCat, cat, name, pkgname, desc, size, maint, weburl;
800
801   // We like to add alphabetically
802   tmpPkgList.sort();
803
804   QTreeWidgetItem *catItem = new QTreeWidgetItem;
805
806   // Lets start adding packages to the tree widget
807   for (int i = 0; i < tmpPkgList.size(); ++i) {
808        name = cat = tmpPkgList.at(i).section(":::", 0,0);
809        cat=cat.section("/", 0, 0);
810        name=name.section("/", 1, 1);
811        pkgname = tmpPkgList.at(i).section(":::", 1,1);
812        desc = tmpPkgList.at(i).section(":::", 2,2);
813        size = tmpPkgList.at(i).section(":::", 3,3);
814        maint = tmpPkgList.at(i).section(":::", 4,4);
815        weburl = tmpPkgList.at(i).section(":::", 5,5);
816
817        // Check if we need to add a top-level category
818        if ( cat != curCat )
819        {
820           qDebug() << "Adding cat: " + cat;
821           catItem = new QTreeWidgetItem(QStringList() << cat);
822           treeNGPkgs->addTopLevelItem(catItem);
823           curCat = cat;
824        }
825 
826        // Now lets create the item and attach to the category
827        QTreeWidgetItem *pkgItem = new QTreeWidgetItem();
828        pkgItem->setText(0, name + " (" + pkgname + ") - " + size );
829        pkgItem->setToolTip(0, desc);
830
831        if ( pkgList.indexOf(pkgname) != -1 ) {
832          pkgItem->setCheckState(0, Qt::Checked);
833          selPkgList << pkgname;
834        } else
835          pkgItem->setCheckState(0, Qt::Unchecked);
836 
837        catItem->addChild(pkgItem);
838   }
839}
840
841// Lets prompt user, and do it!
842void mainWin::applyNGChanges()
843{
844   QString tmp;
845   QStringList curPkgChecked;
846   QStringList newPkgs;
847   QStringList rmPkgs;
848
849   QTreeWidgetItemIterator it(treeNGPkgs);
850   while (*it) {
851         if ((*it)->checkState(0) == Qt::Checked) {
852           tmp = (*it)->text(0).section("(", 1, 1).section(")", 0, 0);
853           curPkgChecked << tmp;
854           if (pkgList.indexOf(tmp) == -1 ) 
855              newPkgs << tmp;
856         }
857         ++it;
858   }
859
860   for ( int i=0; i < pkgList.size(); ++i)
861      // Has this package been unchecked?
862      if (curPkgChecked.indexOf(pkgList.at(i)) == -1 )  {
863         // Make sure this is a package in the repo
864         // This filters out any custom packages the user may have loaded which may not exist in our repo
865         QRegExp rx("*" + pkgList.at(i) + "*");
866         rx.setPatternSyntax(QRegExp::Wildcard);
867         if ( tmpPkgList.indexOf(rx) != -1 )
868           rmPkgs << pkgList.at(i);
869      }
870
871   if ( rmPkgs.isEmpty() && newPkgs.isEmpty() ) {
872      QMessageBox::warning(this, tr("No changes"),
873        tr("No changes to make!"),
874        QMessageBox::Ok,
875        QMessageBox::Ok);
876      return;
877   }
878
879   qDebug() << "Added packages" << newPkgs;
880   qDebug() << "Removed packages" << rmPkgs;
881   pkgRemoveList = rmPkgs;
882   pkgAddList = newPkgs;
883
884   QString confirmText;
885
886   // Lets start creating our confirmation text
887   if ( ! rmPkgs.isEmpty() ) {
888      confirmText+=tr("The following packages will be removed:") + "\n"; 
889      confirmText+= "------------------------------------------\n";
890      confirmText+=rmPkgs.join("\n"); 
891      confirmText+= "\n\n" + tr("The following packages that require the above packages will also removed:") + "\n"; 
892      confirmText+= "------------------------------------------\n";
893      for ( int i=0; i < rmPkgs.size(); ++i) {
894       
895         // Get rdeps for this pkg
896         qDebug() << "Building reverse dependancy lists...";
897         pkgRDepList.clear();
898         QProcess p;
899         if ( wDir.isEmpty() )
900           p.start("pkg", QStringList() << "rquery" << "%n-%v:::%rn-%rv" << rmPkgs.at(i));
901         else
902           p.start("chroot", QStringList() << wDir << "pkg" << "rquery" << "%n-%v:::%rn-%rv" << rmPkgs.at(i) );
903         while(p.state() == QProcess::Starting || p.state() == QProcess::Running) {
904           p.waitForFinished(200);
905           QCoreApplication::processEvents();
906         }
907         while (p.canReadLine()) {
908           pkgRDepList << p.readLine().simplified();
909         }
910
911         QRegExp rx(rmPkgs.at(i) + ":::*");
912         rx.setPatternSyntax(QRegExp::Wildcard);
913         QStringList rDeps = pkgRDepList.filter(rx);
914         for ( int r=0; r < rDeps.size(); ++r) {
915             QString pName = rDeps.at(r).section(":::", 1, 1); 
916             // Is this package installed?
917             if ( pkgList.indexOf(pName) != -1 )
918               confirmText+= pName + " ";
919         }
920      }
921   }
922
923   if ( ! newPkgs.isEmpty() ) {
924      if ( ! rmPkgs.isEmpty() )
925        confirmText+= "\n\n";
926      confirmText+=tr("The following packages will be installed:") + "\n"; 
927      confirmText+= "------------------------------------------\n";
928      confirmText+=newPkgs.join("\n"); 
929      confirmText+= "\n\n" + tr("The following dependances will also be installed:") + "\n"; 
930      confirmText+= "------------------------------------------\n";
931      for ( int i=0; i < newPkgs.size(); ++i) {
932         QRegExp rx(newPkgs.at(i) + ":::*");
933         rx.setPatternSyntax(QRegExp::Wildcard);
934         QStringList aDeps = pkgDepList.filter(rx);
935         for ( int r=0; r < aDeps.size(); ++r) {
936             QString pName = aDeps.at(r).section(":::", 1, 1); 
937             // Is this package installed?
938             if ( pkgList.indexOf(pName) == -1 )
939               confirmText+= pName + " ";
940         }
941      }
942   }
943
944   // Launch our AddPartitionDialog to add a new device
945   askUserConfirm = new dialogConfirm();
946   connect(askUserConfirm, SIGNAL(ok()),this, SLOT(slotStartNGChanges()) );
947   askUserConfirm->programInit(tr("Confirm package changes"));
948   askUserConfirm->setInfoText(QString(confirmText));
949   askUserConfirm->exec();
950
951}
952
953
954// Time to start doing our NG changes!
955void mainWin::slotStartNGChanges()
956{
957  // Init the pkg process
958  prepPkgProcess();
959
960  // Create our runlist of package commands
961  QStringList pCmds;
962 
963  if ( ! pkgRemoveList.isEmpty() ) {
964    pkgProcessType="delete";
965    if ( wDir.isEmpty() )
966      pCmds << "pkg" << "delete" << "-R" << "-y" << pkgRemoveList.join(" ");
967    else
968      pCmds << "chroot" << wDir << "pkg" << "delete" << "-R" << "-y" << pkgRemoveList.join(" ");
969    pkgCmdList << pCmds;
970  }
971         
972  pCmds.clear();
973
974  // Adding packages
975  if ( ! pkgAddList.isEmpty() ) {
976    pkgProcessType="add";
977
978    // Look for conflicts first
979    if ( wDir.isEmpty() )
980      pCmds << "pc-pkg" << "check-conflict" << pkgAddList.join(" ");
981    else
982      pCmds << "chroot" << wDir << "pc-pkg" << "check-conflict" << pkgAddList.join(" ");
983    pkgCmdList << pCmds;
984    pCmds.clear();
985
986    // Now spin up the install process
987    if ( wDir.isEmpty() )
988      pCmds << "pkg" << "install" << "-y" << pkgAddList.join(" ");
989    else
990      pCmds << "chroot" << wDir << "pkg" << "install" << "-y" << pkgAddList.join(" ");
991
992    pkgCmdList << pCmds;
993  }
994
995  // Lets kick it off now
996  startPkgProcess();
997}
998
999// Display found meta-pkg data
1000void mainWin::populateMetaPkgs()
1001{
1002  pushPkgApply->setEnabled(false);
1003  treeMetaPkgs->clear();
1004  tmpMetaPkgList.clear();
1005  new QTreeWidgetItem(treeMetaPkgs, QStringList() << tr("Loading... Please wait...") );
1006
1007  if ( ! metaPkgList.isEmpty() )
1008        disconnect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), 0, 0);
1009  metaPkgList.clear();
1010
1011  // Start the process to get meta-pkg info
1012  getMetaProc = new QProcess();
1013  qDebug() << "Searching for meta-pkgs...";
1014  connect( getMetaProc, SIGNAL(readyReadStandardOutput()), this, SLOT(slotGetPackageDataOutput()) );
1015  connect( getMetaProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotFinishLoadingMetaPkgs()) );
1016  getMetaProc->setProcessChannelMode(QProcess::MergedChannels);
1017  getMetaProc->start(QString("pc-metapkgmanager"), QStringList() << "list");
1018
1019}
1020
1021// Display found meta-pkg data
1022void mainWin::slotFinishLoadingMetaPkgs()
1023{
1024
1025  // Populate the metaPkgList
1026  parseTmpMetaList();
1027
1028  treeMetaPkgs->clear();
1029
1030  addTreeItems(QString()); 
1031
1032  pushPkgApply->setEnabled(false);
1033
1034  connect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotDeskPkgsChanged(QTreeWidgetItem *, int)));
1035  //Enable the search option
1036  tool_search->setEnabled(true);
1037  // Now we can look for updates safely
1038  slotRescanPkgsClicked();
1039}
1040
1041void mainWin::addTreeItems(QString parent)
1042{
1043  for (int z=0; z < metaPkgList.count(); ++z) {
1044    if ( metaPkgList.at(z).at(3) != parent )
1045      continue;
1046
1047    // Hide the "base-system" package, since we are installing it anyway
1048    if (metaPkgList.at(z).at(0) == "base-system" )
1049      return;
1050
1051    QTreeWidgetItem *deskItem = new QTreeWidgetItem(QStringList() << metaPkgList.at(z).at(0) );
1052    deskItem->setIcon(0, QIcon(metaPkgList.at(z).at(2)));
1053    deskItem->setToolTip(0, metaPkgList.at(z).at(1));
1054    deskItem->setCheckState(0, Qt::Unchecked);
1055
1056    if ( metaPkgList.at(z).at(5) == "YES" )
1057      deskItem->setCheckState(0, Qt::Checked);
1058
1059    if ( parent.isEmpty() ) {
1060      treeMetaPkgs->addTopLevelItem(deskItem);
1061    } else {
1062      // Locate the parent to attach to
1063      QTreeWidgetItemIterator it(treeMetaPkgs);
1064      while (*it) {
1065        if ((*it)->text(0) == parent ) {
1066          (*it)->addChild(deskItem);
1067          if ( metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::Unchecked)
1068            (*it)->setCheckState(0, Qt::PartiallyChecked);
1069          if ( metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::Checked)
1070            (*it)->setCheckState(0, Qt::PartiallyChecked);
1071          break;
1072        }
1073        it++;
1074      }
1075    }
1076
1077    // Now look for any possible children
1078    addTreeItems(metaPkgList.at(z).at(0));   
1079  }
1080
1081}
1082
1083// Check if a meta-pkg is installed
1084bool mainWin::isMetaPkgInstalled(QString mPkg)
1085{
1086  QString tmp;
1087  QProcess pcmp;
1088  pcmp.start(QString("pc-metapkgmanager"), QStringList() << chrootArg1 << chrootArg2 << "status" << mPkg);
1089  while ( pcmp.state() != QProcess::NotRunning ) {
1090     pcmp.waitForFinished(50);
1091     QCoreApplication::processEvents();
1092  }
1093
1094  while (pcmp.canReadLine()) {
1095     tmp = pcmp.readLine().simplified();
1096     if ( tmp.indexOf("is installed") != -1 )
1097     return true;
1098  }
1099
1100  return false;
1101}
1102
1103// Function which checks for our GUI package schema data
1104void mainWin::slotGetPackageDataOutput()
1105{
1106  while (getMetaProc->canReadLine())
1107        tmpMetaPkgList << getMetaProc->readLine().simplified();
1108}
1109
1110// Parse the pc-metapkg saved output
1111void mainWin::parseTmpMetaList()
1112{
1113  QString tmp, mName, mDesc, mIcon, mParent, mDesktop, mInstalled, mPkgFileList;
1114  QStringList package;
1115
1116  for ( int i = 0 ; i < tmpMetaPkgList.size(); i++ )
1117  {
1118        QApplication::processEvents();
1119
1120        tmp = tmpMetaPkgList.at(i);
1121
1122        if ( tmp.indexOf("Meta Package: ") == 0) {
1123                mName = tmp.replace("Meta Package: ", "");
1124                continue;
1125        }
1126        if ( tmp.indexOf("Description: ") == 0) {
1127                mDesc = tmp.replace("Description: ", "");
1128                continue;
1129        }
1130        if ( tmp.indexOf("Icon: ") == 0) {
1131                mIcon = tmp.replace("Icon: ", "");
1132                mPkgFileList = mIcon;
1133                mPkgFileList.replace("pkg-icon.png", "pkg-list");
1134                continue;
1135        }
1136        if ( tmp.indexOf("Parent: ") == 0) {
1137                mParent = tmp.replace("Parent: ", "");
1138                continue;
1139        }
1140        if ( tmp.indexOf("Desktop: ") == 0) {
1141                mDesktop = tmp.replace("Desktop: ", "");
1142                continue;
1143        }
1144
1145        // This is an empty category
1146        if ( tmp.indexOf("Category Entry") == 0) {
1147                // Now add this category to the string list
1148                package.clear();
1149                qDebug() << "Found Package" << mName << mDesc << mIcon << mParent << mDesktop;
1150                mInstalled = "CATEGORY";
1151                package << mName << mDesc << mIcon << mParent << mDesktop << mInstalled;
1152                metaPkgList.append(package);
1153                mName=""; mDesc=""; mIcon=""; mParent=""; mDesktop=""; mInstalled=""; mPkgFileList="";
1154        }
1155
1156        // We have a Meta-Pkg
1157        if ( tmp.indexOf("Required Packages:") == 0) {
1158                // Now add this meta-pkg to the string list
1159                package.clear();
1160                qDebug() << "Found Package" << mName << mDesc << mIcon << mParent << mDesktop << mPkgFileList;
1161
1162                if ( isMetaPkgInstalled(mName) )
1163                        mInstalled = "YES";
1164                else
1165                        mInstalled = "NO";
1166
1167                package << mName << mDesc << mIcon << mParent << mDesktop << mInstalled << mPkgFileList;
1168                metaPkgList.append(package);
1169                mName=""; mDesc=""; mIcon=""; mParent=""; mDesktop=""; mInstalled=""; mPkgFileList="";
1170        }
1171
1172    }
1173
1174}
1175
1176void mainWin::saveMetaPkgs()
1177{
1178        if ( ! haveMetaPkgChanges() )
1179                return;
1180
1181        addPkgs = getAddPkgs();
1182        delPkgs = getDelPkgs(); 
1183
1184        startMetaChanges();
1185
1186}
1187
1188void mainWin::startMetaChanges()
1189{
1190
1191  // Init the pkg process
1192  prepPkgProcess();
1193  // Create our runlist of package commands
1194  QStringList pCmds;
1195
1196  if ( ! delPkgs.isEmpty() ) {
1197    pkgProcessType="deletemeta";
1198    if ( wDir.isEmpty() )
1199      pCmds << "pc-metapkgmanager" << "del" << delPkgs;
1200    else 
1201      pCmds << "chroot" << wDir << "pc-metapkgmanager" << "del" << delPkgs;
1202    pkgCmdList << pCmds;
1203  }
1204 
1205  pCmds.clear();
1206
1207  if ( ! addPkgs.isEmpty() ) {
1208    pkgProcessType="addmeta";
1209    if ( wDir.isEmpty() )
1210      pCmds << "pc-metapkgmanager" << "add" << addPkgs;
1211    else 
1212      pCmds << "chroot" << wDir << "pc-metapkgmanager" << "add" << addPkgs;
1213    pkgCmdList << pCmds;
1214  }
1215
1216  // Lets kick it off now
1217  startPkgProcess();
1218}
1219
1220bool mainWin::haveAMetaDesktop()
1221{
1222        // If running in a chroot we can skip this check
1223        if ( ! chrootArg1.isEmpty() )
1224          return true;
1225       
1226        QTreeWidgetItemIterator it(treeMetaPkgs);
1227        while (*it) {
1228         if ( ((*it)->checkState(0) == Qt::Checked) || ((*it)->checkState(0) == Qt::PartiallyChecked) )
1229           for (int z=0; z < metaPkgList.count(); ++z)
1230             if ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(4) == "YES" )
1231                return true;
1232         ++it;
1233        }
1234
1235        QMessageBox::warning(this, tr("No Desktop"),
1236          tr("No desktops have been selected! Please choose at least one desktop before saving."),
1237          QMessageBox::Ok,
1238          QMessageBox::Ok);
1239
1240        return false;
1241}
1242
1243bool mainWin::haveMetaPkgChanges()
1244{
1245        QTreeWidgetItemIterator it(treeMetaPkgs);
1246        while (*it) {
1247          for (int z=0; z < metaPkgList.count(); ++z)
1248            // See if any packages status have changed
1249            if ( ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::Unchecked ) \
1250              || ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::PartiallyChecked ) \
1251              || ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::Checked ) )
1252                return true;
1253         ++it;
1254        }
1255
1256        return false;
1257}
1258
1259QString mainWin::getAddPkgs()
1260{
1261        QString tmp;
1262        QTreeWidgetItemIterator it(treeMetaPkgs);
1263        while (*it) {
1264          for (int z=0; z < metaPkgList.count(); ++z)
1265            // See if any packages status have changed
1266            if ( ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::Checked ) || \
1267                 ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "NO" && (*it)->checkState(0) == Qt::PartiallyChecked ) ){
1268                if ( tmp.isEmpty() ){
1269                        tmp = (*it)->text(0);
1270                }else{
1271                        tmp = tmp + "," + (*it)->text(0);
1272                }
1273            }
1274         ++it;
1275        }
1276
1277        return tmp;
1278}
1279
1280QString mainWin::getDelPkgs()
1281{
1282        QString tmp;
1283        QTreeWidgetItemIterator it(treeMetaPkgs);
1284        while (*it) {
1285          for (int z=0; z < metaPkgList.count(); ++z)
1286            // See if any packages status have changed
1287            if ( (*it)->text(0) == metaPkgList.at(z).at(0) && metaPkgList.at(z).at(5) == "YES" && (*it)->checkState(0) == Qt::Unchecked ) {
1288                if ( tmp.isEmpty() ){
1289                        tmp = (*it)->text(0);
1290                }else{
1291                        tmp = tmp + "," + (*it)->text(0);
1292                }
1293            }
1294         ++it;
1295        }
1296
1297        return tmp;
1298}
1299
1300
1301// Time to save meta-pkgs
1302void mainWin::slotApplyMetaChanges() {
1303    saveMetaPkgs();
1304}
1305
1306
1307
1308// The User changed the tree widget checked / unchecked stuff sanity check
1309void mainWin::slotDeskPkgsChanged(QTreeWidgetItem *aItem, int __unused)
1310{
1311        if (!aItem)
1312          return;
1313
1314        disconnect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), 0, 0);
1315
1316        if (aItem->childCount() == 0) {
1317                if (aItem->checkState(0) == Qt::Checked && aItem->parent() ){
1318                        if ( allChildrenPkgsChecked(aItem->parent()->text(0))){
1319                                aItem->parent()->setCheckState(0, Qt::Checked); 
1320                        }else{
1321                                aItem->parent()->setCheckState(0, Qt::PartiallyChecked);       
1322                        }
1323                }
1324                if (aItem->checkState(0) == Qt::Unchecked && aItem->parent() ){
1325                        if ( ! allChildrenPkgsUnchecked(aItem->parent()->text(0)))
1326                                aItem->parent()->setCheckState(0, Qt::PartiallyChecked);       
1327                }
1328
1329        } else {
1330                if (aItem->checkState(0) == Qt::Checked ){
1331                        checkAllChildrenPkgs(aItem->text(0));
1332                }else{
1333                        uncheckAllChildrenPkgs(aItem->text(0));
1334                }
1335        }
1336       
1337
1338    connect(treeMetaPkgs, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotDeskPkgsChanged(QTreeWidgetItem *, int)));
1339
1340        if ( haveMetaPkgChanges() )
1341                pushPkgApply->setEnabled(true);
1342        else
1343                pushPkgApply->setEnabled(false);
1344}
1345
1346// Check the "parent" app to see if all its children are checked or not
1347bool mainWin::allChildrenPkgsChecked(QString parent)
1348{
1349        QTreeWidgetItemIterator it(treeMetaPkgs);
1350        while (*it) {
1351         if ((*it)->text(0) == parent ) {
1352           if ( (*it)->childCount() <= 0)
1353             return true;
1354
1355           for ( int i = 0; i < (*it)->childCount() ; ++i) {
1356             if ( ! allChildrenPkgsChecked((*it)->child(i)->text(0)))
1357               return false;
1358
1359             if ((*it)->child(i)->checkState(0) != Qt::Checked ) 
1360               return false;
1361           }
1362         }
1363         ++it;
1364        }
1365        return true;
1366}
1367
1368// Check the "parent" app to see if all its children are unchecked or not
1369bool mainWin::allChildrenPkgsUnchecked(QString parent)
1370{
1371        QTreeWidgetItemIterator it(treeMetaPkgs);
1372        while (*it) {
1373         if ((*it)->text(0) == parent ) {
1374           if ( (*it)->childCount() <= 0)
1375             return true;
1376
1377           for ( int i = 0; i < (*it)->childCount() ; ++i) {
1378             if ( ! allChildrenPkgsUnchecked((*it)->child(i)->text(0)))
1379               return false;
1380
1381             if ((*it)->child(i)->checkState(0) != Qt::Unchecked ) 
1382               return false;
1383           }
1384         }
1385         ++it;
1386        }
1387        return true;
1388}
1389
1390// Check all children of parent
1391void mainWin::checkAllChildrenPkgs(QString parent)
1392{
1393        QTreeWidgetItemIterator it(treeMetaPkgs);
1394        while (*it) {
1395         if (! (*it)->parent()) {
1396           ++it;
1397           continue;
1398         } 
1399
1400         // Lets walk the tree see what pops up
1401         bool pFound=false;
1402         QTreeWidgetItem *itP = (*it)->parent();
1403         do {
1404           pFound=false;
1405           if (itP->text(0) == parent) {
1406             (*it)->setCheckState(0, Qt::Checked);
1407             break;
1408           }
1409           if ( itP->parent() ) {
1410             itP = itP->parent();
1411             pFound=true;
1412           }
1413         } while (pFound);
1414
1415         ++it;
1416       }
1417}
1418
1419// UnCheck all children of parent
1420void mainWin::uncheckAllChildrenPkgs(QString parent)
1421{
1422        QTreeWidgetItemIterator it(treeMetaPkgs);
1423        while (*it) {
1424         if (! (*it)->parent()) {
1425           ++it;
1426           continue;
1427         } 
1428
1429         // Lets walk the tree see what pops up
1430         bool pFound=false;
1431         QTreeWidgetItem *itP = (*it)->parent();
1432         do {
1433           pFound=false;
1434           if (itP->text(0) == parent) {
1435             (*it)->setCheckState(0, Qt::Unchecked);
1436             break;
1437           }
1438           if ( itP->parent() ) {
1439             itP = itP->parent();
1440             pFound=true;
1441           }
1442         } while (pFound);
1443
1444         ++it;
1445       }
1446}
1447
1448void mainWin::slotMetaRightClick()
1449{
1450        QTreeWidgetItemIterator it(treeMetaPkgs);
1451        while (*it) {
1452          for (int z=0; z < metaPkgList.count(); ++z) {
1453            if ( (*it)->isSelected() && (*it)->text(0) == metaPkgList.at(z).at(0) ) {
1454              if (metaPkgList.at(z).at(5) == "CATEGORY")
1455                return;
1456              popup = new QMenu;
1457              popup->setTitle((*it)->text(0));
1458              popup->addAction(tr("View Packages"), this, SLOT(slotMetaViewPkgs()));
1459              popup->exec( QCursor::pos() );
1460            }
1461          }
1462         ++it;
1463        }
1464}
1465
1466void mainWin::slotMetaViewPkgs()
1467{
1468        QStringList packageList;
1469        QTreeWidgetItemIterator it(treeMetaPkgs);
1470        while (*it) {
1471          for (int z=0; z < metaPkgList.count(); ++z) {
1472            if ( (*it)->isSelected() && (*it)->text(0) == metaPkgList.at(z).at(0) ) {
1473 
1474                QFile pList(metaPkgList.at(z).at(6));
1475                if ( ! pList.exists() )
1476                  return;
1477               
1478                if ( ! pList.open(QIODevice::ReadOnly | QIODevice::Text))
1479                  return;
1480
1481                while ( !pList.atEnd() )
1482                  packageList << pList.readLine().simplified();
1483
1484                pList.close();
1485                packageList.sort();
1486                       
1487                dIB = new dialogInfo();
1488                dIB->programInit(tr("Package Listing for:") + " " + (*it)->text(0));
1489                dIB->setInfoText(packageList.join("\n"));
1490                dIB->show();
1491            }
1492          }
1493         ++it;
1494        }
1495}
1496
1497QString mainWin::getLineFromCommandOutput( QString cmd )
1498{
1499        FILE *file = popen(cmd.toLatin1(),"r");
1500 
1501        char buffer[100];
1502 
1503        QString line = "";
1504        char firstChar;
1505
1506        if ((firstChar = fgetc(file)) != -1){
1507                line += firstChar;
1508                line += fgets(buffer,100,file);
1509        }
1510        pclose(file);
1511        return line.simplified();
1512}
1513
1514void mainWin::slotCloseAdvClicked()
1515{
1516   groupInfo->setVisible(false);
1517}
1518
1519void mainWin::closeEvent(QCloseEvent *event) {
1520
1521  if ( pkgCmdList.isEmpty() ) {
1522    this->close();
1523    return;   
1524  }
1525  if ( pkgCmdList.at(0).at(0).isEmpty() ) {
1526    this->close();
1527    return; 
1528  }
1529
1530  //Verify that they want to continue
1531  QMessageBox::StandardButton button = QMessageBox::warning(this, tr("Processes Running"), tr("Packages are currently being changed. Are you sure you want to quit?"), QMessageBox::Yes | QMessageBox::Cancel,QMessageBox::Cancel);
1532  if(button == QMessageBox::Yes) {
1533    this->close();
1534  } else {
1535    event->ignore();
1536    return;
1537  }
1538}
1539
1540
1541void mainWin::slotReadEventPipe()
1542{
1543   QString line, tmp, file, dl, tot;
1544   bool ok, ok2;
1545
1546   while (eP->canReadLine()) {
1547     line = eP->readLine().simplified();
1548     //qDebug() << line;
1549
1550     // KPM!!
1551     // TODO 12-12-2013
1552     // No JSON in Qt4, once we move to Qt5, replace this hack
1553     // with the new JSON parser
1554
1555     // Look for any "msg" lines
1556     if ( line.indexOf("\"msg") != -1 ) {
1557          line.remove(0, line.indexOf("\"msg") + 8);
1558          line.truncate(line.lastIndexOf("\""));
1559          qDebug() << line;
1560          textStatus->setText(line);
1561          continue;
1562     }
1563
1564     // Look for a download status update
1565     if ( line.indexOf("\"INFO_FETCH") != -1 && line.indexOf("\"url\"") != -1 ) {
1566          line.remove(0, line.indexOf("\"url") + 8);
1567          line.truncate(line.lastIndexOf("}"));
1568
1569          // Get the file basename
1570          file = line;
1571          file.truncate(line.indexOf("\""));
1572          QFileInfo tFile;
1573          tFile.setFile(file);
1574          file = tFile.baseName();
1575
1576          // Get the download / total
1577          dl = line.section(":", 2, 2).section(",", 0, 0);
1578          tot = line.section(":", 3, 3).section("}", 0, 0);
1579          dl = dl.simplified();
1580          tot = tot.simplified();
1581
1582          dl.toLongLong(&ok);
1583          tot.toLongLong(&ok2);
1584          if ( ok && ok2) {
1585            progressUpdate->setRange(0, tot.toLongLong(&ok) / 1024);
1586            progressUpdate->setValue(dl.toLongLong(&ok) / 1024 );
1587          }
1588
1589          // Set the status update
1590          textStatus->setText(tr("Downloading") + " " + file + " (" + dl + " / " + tot + ")" );
1591     }
1592
1593   } // End of while canReadLine()
1594
1595}
1596
1597void mainWin::slotConfigClicked()
1598{
1599   configD = new dialogConfig();
1600   connect(configD, SIGNAL(ok()),this, SLOT(slotConfigFinished()) );
1601   configD->programInit();
1602   configD->show();
1603}
1604
1605void mainWin::slotConfigFinished()
1606{
1607   // Changed view, lets refresh
1608   initMetaWidget();
1609}
Note: See TracBrowser for help on using the repository browser.