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

releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1
Last change on this file since d18dfae was d18dfae, checked in by JoshDW19 <joshms@…>, 11 months ago

Updated pc-pkgmanager to follow our new GUI guidelines. Removed close button at bottom of main screen.

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