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

releng/10.0.2releng/10.0.3releng/10.1releng/10.1.1
Last change on this file since 26c7c82 was 26c7c82, checked in by Kris Moore <kris@…>, 13 months ago

Add new "Package cleanup" functionality to package manager. This
will run 'pkg autoremove' and do cleanup of packages no longer
needed.

This needs some testing still.

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