source: src-qt4/pc-installgui/installer.cpp @ 0de7e02

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

Add new UI code to walk the user through saving their installation config file

  • Property mode set to 100644
File size: 53.0 KB
Line 
1#include <QCloseEvent>
2#include <QProcess>
3#include <QTimer>
4#include <QTranslator>
5#include <QInputDialog>
6#include <QGraphicsPixmapItem>
7
8#include "backend.h"
9#include "installer.h"
10#include "helpText.h"
11
12Installer::Installer(QWidget *parent) : QMainWindow(parent)
13{
14    setupUi(this);
15    translator = new QTranslator();
16    haveWarnedSpace=false;
17
18    connect(abortButton, SIGNAL(clicked()), this, SLOT(slotAbort()));
19    connect(backButton, SIGNAL(clicked()), this, SLOT(slotBack()));
20    connect(nextButton, SIGNAL(clicked()), this, SLOT(slotNext()));
21
22    connect(helpButton, SIGNAL(clicked()), this, SLOT(slotHelp()));
23    connect(pushTouchKeyboard, SIGNAL(clicked()), this, SLOT(slotPushVirtKeyboard()));
24    connect(pushChangeKeyLayout, SIGNAL(clicked()), this, SLOT(slotPushKeyLayout()));
25    connect(pushHardware, SIGNAL(clicked()), this, SLOT(slotCheckHardware()));
26    connect(pushLoadConfig, SIGNAL(clicked()), this, SLOT(slotLoadConfigUSB()));
27    connect(pushSaveConfig, SIGNAL(clicked()), this, SLOT(slotSaveConfigUSB()));
28    connect(pushSaveConfig2, SIGNAL(clicked()), this, SLOT(slotSaveConfigUSB()));
29
30    abortButton->setText(tr("&Cancel"));
31    backButton->setText(tr("&Back"));
32    nextButton->setText(tr("&Next"));
33
34    // Init the MBR to yes
35    loadMBR = true;
36    // Init the GPT to no
37    loadGPT = false;
38
39    // No optional components by default
40    fSRC=false;
41    fPORTS=false;
42
43    // Load the keyboard info
44    keyModels = Scripts::Backend::keyModels();
45    keyLayouts = Scripts::Backend::keyLayouts();
46
47    // Set the arch name
48    setArch();
49
50    // Start on the first screen
51    installStackWidget->setCurrentIndex(0);
52    backButton->setVisible(false);
53}
54
55Installer::~Installer()
56{
57    //delete ui;
58}
59
60bool Installer::isInstalled()
61{
62    return false;
63}
64
65void Installer::setArch()
66{
67   QProcess m;
68   m.start(QString("uname"), QStringList() << "-m");
69   while(m.state() == QProcess::Starting || m.state() == QProcess::Running) {
70      m.waitForFinished(200);
71      QCoreApplication::processEvents();
72   }
73
74   // Get output
75   Arch = m.readLine().simplified();
76   qDebug() << Arch;
77}
78
79void Installer::slotCheckHardware()
80{
81  pcHardware = new dialogCheckHardware();
82  pcHardware->programInit();
83  pcHardware->setWindowModality(Qt::ApplicationModal);
84  pcHardware->show();
85  pcHardware->raise();
86}
87
88void Installer::slotPushKeyLayout()
89{
90  wKey = new widgetKeyboard();
91  wKey->programInit(keyModels, keyLayouts);
92  wKey->setWindowModality(Qt::ApplicationModal);
93  wKey->show();
94  wKey->raise();
95}
96
97void Installer::initInstall()
98{
99    // load languages
100    comboLanguage->clear();
101    languages = Scripts::Backend::languages();
102    for (int i=0; i < languages.count(); ++i) {
103        QString languageStr = languages.at(i);
104        QString language = languageStr.split("-").at(0);
105        comboLanguage->addItem(language.trimmed());
106    }
107    connect(comboLanguage, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotChangeLanguage()));
108
109    // Load any package scheme data
110    listDeskPkgs = Scripts::Backend::getPackageData(availDesktopPackageData, QString());
111    listServerPkgs = Scripts::Backend::getPackageData(availServerPackageData, QString("trueos"));
112
113    // Do check for available meta-pkgs on boot media
114    if ( QFile::exists("/tmp/no-meta-pkgs") )
115        hasPkgsOnMedia = false;
116    else
117        hasPkgsOnMedia = true;
118
119    qDebug() << "Package Media:" << availDesktopPackageData << hasPkgsOnMedia;
120
121    // See if this media has a freebsd release on it
122    if ( QFile::exists("/tmp/no-fbsd-release") ) {
123        hasFreeBSDOnMedia = false;
124    } else {
125        hasFreeBSDOnMedia = true;
126    }
127       
128    // Do check for install pkgs on boot media
129    if ( QFile::exists("/tmp/no-install-pkgs") ) {
130        hasInstallOnMedia = false;
131    } else {
132        hasInstallOnMedia = true;
133    }
134
135    // Set the key toggle
136    toggleKeyLayout = true;
137
138    // Is this a LIVE disk?
139    if ( QFile::exists("/usr/pcbsd-live") )
140        isLiveMode = true;
141    else
142        isLiveMode = false;
143
144    // Get available memory
145    systemMemory = Scripts::Backend::systemMemory();
146
147    // Load up the keyboard information
148    //connectKeyboardSlots();
149
150    // Connect the disk slots
151    connect(pushDiskCustomize,SIGNAL(clicked()), this, SLOT(slotDiskCustomizeClicked()));
152
153    // Load the disks
154    loadDiskInfo();
155   
156
157    // Init the desktop wheel
158    initDesktopSelector();
159}
160
161void Installer::loadDiskInfo()
162{
163   sysDisks = Scripts::Backend::hardDrives();
164   if ( sysDisks.empty() ) {
165      QMessageBox::critical(this, tr("PC-BSD Installer"),
166                                tr("Unable to detect any disk drives! The install will now exit."),
167                                QMessageBox::Ok,
168                                QMessageBox::Ok);
169      exit(1);
170   }
171
172   // For now use the first disk we find
173   if ( ! autoGenPartitionLayout(sysDisks.at(0).at(1), true) )
174   {
175      QMessageBox::critical(this, tr("PC-BSD Installer"),
176        tr("Unable to suggest a partition for the detected disk."),
177        QMessageBox::Ok,
178        QMessageBox::Ok);
179   }
180
181   textEditDiskSummary->clear();
182   QStringList summary = getDiskSummary();
183   for ( int i=0; i < summary.count(); ++i)
184     textEditDiskSummary->append(summary.at(i));
185
186   textEditDiskSummary->moveCursor(QTextCursor::Start);
187
188}
189
190// Function which will auto-generate a partition layout based upon the target disk / slice
191bool Installer::autoGenPartitionLayout(QString target, bool isDisk)
192{
193  QString targetType, tmp;
194  int targetLoc, totalSize = 0, mntsize;
195  QString targetDisk, targetSlice, tmpPass, fsType;
196  bool ok;
197  ok = false;
198
199  // Clear out the original disk layout
200  sysFinalDiskLayout.clear();
201  QStringList fileSystem;
202  qDebug() << "Generating disk layout";
203
204
205  if ( isDisk ) {
206    targetType = "DRIVE";
207    targetSlice = "ALL";
208    targetDisk = target;
209    targetLoc = 1;
210  } else {
211    targetType = "SLICE";
212    targetDisk = target;
213    targetDisk.truncate(targetDisk.size() -2);
214    targetSlice = target;
215    targetSlice = targetSlice.remove(0, targetSlice.size() -2);
216    targetLoc = 2;
217  }
218 
219  // Lets get the size for this disk / partition
220  for (int i=0; i < sysDisks.count(); ++i) {
221      // Make sure to only add the slices to the listDiskSlices
222      if ( sysDisks.at(i).at(0) == targetType && target == sysDisks.at(i).at(targetLoc))
223        totalSize = sysDisks.at(i).at(targetLoc + 1).toInt(&ok);
224  }
225
226  // Give us a small buffer for rounding errors
227  totalSize = totalSize - 10;
228
229  // We got a valid size for this disk / slice, lets generate the layout now
230  if( !ok )
231    return false;
232
233
234  // If on amd64 lets use ZFS, it rox
235  if ( Arch == "amd64" ) {
236    // Add the main zfs pool with standard partitions
237    fsType= "ZFS";
238    fileSystem << targetDisk << targetSlice << "/,/tmp(compress=lzjb),/usr(canmount=off),/usr/home,/usr/jails,/usr/obj(compress=lzjb),/usr/pbi,/usr/ports(compress=gzip),/usr/ports/distfiles(compress=off),/usr/src(compress=gzip),/var(canmount=off),/var/audit(compress=lzjb),/var/log(compress=gzip),/var/tmp(compress=lzjb)" << fsType << tmp.setNum(totalSize) << "" << "";
239    //qDebug() << "Auto-Gen FS:" <<  fileSystem;
240    sysFinalDiskLayout << fileSystem;
241    fileSystem.clear();
242    return true;
243  }
244
245  // Looks like not on amd64, fallback to UFS+SUJ and print a nice
246  // warning for the user explaining they *really* want to be on amd64
247  QMessageBox::warning(this, tr("PC-BSD Installer"),
248      tr("Detected that you are running the 32bit version. If your system is 64bit capable (most systems made after 2005), you really should be running the 64bit version"),
249      QMessageBox::Ok,
250      QMessageBox::Ok);
251
252  // Start the UFS layout now
253  mntsize = 2000;
254  fsType="UFS+SUJ";
255
256  fileSystem << targetDisk << targetSlice << "/" << fsType << tmp.setNum(mntsize) << "" << "";
257  totalSize = totalSize - mntsize;
258  //qDebug() << "Auto-Gen FS:" <<  fileSystem;
259  sysFinalDiskLayout << fileSystem;
260  fileSystem.clear();
261   
262
263  // Figure out the swap size, try for 2xPhysMem first, fallback to 256 if not enough space
264  mntsize = systemMemory * 2;
265  if ( totalSize - mntsize < 3000 )
266     mntsize = 256;
267
268  // Cap the swap size to 2GB
269  if ( mntsize > 2000 )
270     mntsize = 2000;
271
272  fileSystem << targetDisk << targetSlice << "SWAP" << "SWAP" << tmp.setNum(mntsize) << "" << "";
273  totalSize = totalSize - mntsize;
274  //qDebug() << "Auto-Gen FS:" <<  fileSystem;
275  sysFinalDiskLayout << fileSystem;
276  fileSystem.clear();
277
278  // If less than 3GB, skip /var and leave on /
279  if ( totalSize > 3000 ) {
280    // Figure out the default size for /var if we are on FreeBSD / PC-BSD
281    mntsize = 2048;
282    fileSystem << targetDisk << targetSlice << "/var" << fsType << tmp.setNum(mntsize) << "" << "";
283    totalSize = totalSize - mntsize;
284    //qDebug() << "Auto-Gen FS:" <<  fileSystem;
285    sysFinalDiskLayout << fileSystem;
286    fileSystem.clear();
287  }
288
289  // Now use the rest of the disk / slice for /usr
290  fileSystem << targetDisk << targetSlice << "/usr" << fsType << tmp.setNum(totalSize) << "" << "";
291  //qDebug() << "Auto-Gen FS:" <<  fileSystem;
292  sysFinalDiskLayout << fileSystem;
293  fileSystem.clear();
294
295  return true; 
296 
297}
298
299// Function which returns the pc-sysinstall cfg data
300QStringList Installer::getDiskSummary()
301{
302  QList<QStringList> copyList;
303  QStringList summaryList;
304  QString tmp, workingDisk, workingSlice, tmpSlice, XtraTmp, startPart, sliceSize;
305  int disk = 0;
306
307  // Copy over the list to a new variable we can mangle without modifying the original
308  copyList = sysFinalDiskLayout;
309
310  if ( copyList.at(0).at(0) == "MANUAL" )
311  {
312    summaryList << "";
313    summaryList << tr("Installing to file-system mounted at /mnt");
314    return summaryList;
315  }
316
317  // Start our summary
318  summaryList << "";
319  summaryList << "<b>" + tr("The disk will be setup with the following configuration:") + "</b>";
320
321  while ( ! copyList.empty() )
322  {
323    workingDisk = copyList.at(0).at(0);
324    workingSlice = copyList.at(0).at(1);
325    tmpSlice = workingSlice;
326
327    // Check if this is an install to "Unused Space"
328    for (int z=0; z < sysDisks.count(); ++z)
329      if ( sysDisks.at(z).at(0) == "SLICE" \
330        && sysDisks.at(z).at(2) == workingDisk + workingSlice \
331        && sysDisks.at(z).at(4) == "Unused Space" )
332          tmpSlice = "free";
333
334    // Check for any mirror for this device
335    for (int i=0; i < copyList.count(); ++i) {
336       if ( copyList.at(i).at(2).indexOf("MIRROR(" + workingDisk + ")") != -1 )
337       {
338         summaryList << tr("Disk:") + copyList.at(i).at(0) + " " + tr("Mirroring:") + workingDisk;
339         copyList.removeAt(i);
340         break;
341       }
342    }
343
344    // If after doing the mirror, our list is empty, break out
345    if ( copyList.empty() )
346      break;
347   
348    // If there is a dedicated /boot partition, need to list that first, see what is found
349    for (int i=0; i < copyList.count(); ++i) {
350      QStringList mounts = copyList.at(i).at(2).split(",");
351      for (int z = 0; z < mounts.size(); ++z) {
352        if ( copyList.at(i).at(0) == workingDisk \
353          && copyList.at(i).at(1) == workingSlice \
354          && mounts.at(z) == "/boot" )
355                startPart="/boot";
356      }
357    }
358
359    // If no dedicated /boot partition, then lets list "/" first
360    if(startPart.isEmpty())
361        startPart="/";
362
363    // Start by looking for the root partition
364    for (int i=0; i < copyList.count(); ++i) {
365      QStringList mounts = copyList.at(i).at(2).split(",");
366      for (int z = 0; z < mounts.size(); ++z) {
367        if ( copyList.at(i).at(0) == workingDisk \
368          && copyList.at(i).at(1) == workingSlice \
369          && mounts.at(z) == startPart ) {
370
371          // Check if we have any extra arguments to throw on the end
372          XtraTmp="";
373          if ( ! copyList.at(i).at(5).isEmpty() )
374            XtraTmp=" (" + copyList.at(i).at(5) + ")" ;
375
376          // Write the user summary
377          summaryList << "";
378          summaryList << tr("Partition:") + " " + workingDisk + "(" + workingSlice + "):";
379          summaryList << tr("FileSystem:") + " " + copyList.at(i).at(3);
380          summaryList << tr("Size:") + " " + copyList.at(i).at(4) + "MB ";
381          if ( copyList.at(i).at(3) == "ZFS" ) {
382            QStringList zDS = copyList.at(i).at(2).split(",/");
383            QString zTMP;
384            for (int ds = 0; ds < zDS.size(); ++ds) {
385              if ( zDS.at(ds) != "/" )
386                zDS.replace(ds, "/" + zDS.at(ds));
387              if ( zDS.at(ds).indexOf("(") != -1 ) {
388                zTMP = zDS.at(ds);
389                zTMP.replace("(", " (");
390                zDS.replace(ds, zTMP );
391              }
392            } 
393            summaryList << tr("ZFS Datasets:<br>") + " " + zDS.join("<br>");
394          } else {
395            summaryList << tr("Mount:") + " " + copyList.at(i).at(2);
396          }
397          if ( ! XtraTmp.isEmpty() ) {
398            summaryList << tr("Options:") + " " + copyList.at(i).at(5);
399          }
400
401          // Done with this item, remove it now
402          copyList.removeAt(i);
403          break;
404        }
405      }
406    }
407
408
409    // Now look for SWAP
410    for (int i=0; i < copyList.count(); ++i) {
411      if ( copyList.at(i).at(0) == workingDisk \
412        && copyList.at(i).at(1) == workingSlice \
413        && copyList.at(i).at(2) == "SWAP" ) {
414
415        // Write the user summary
416        summaryList << "";
417        summaryList << tr("Partition:") + " " + workingDisk + "(" + workingSlice + "):";
418        summaryList << tr("FileSystem:") + " " + copyList.at(i).at(3);
419        summaryList << tr("Size:") + " " + copyList.at(i).at(4) + "MB ";
420
421        // Done with this item, remove it now
422        copyList.removeAt(i);
423        break;
424      }
425    }
426
427 
428    // Now look for any other partitions
429    int count = copyList.count();
430    for (int i=0; i < count; ++i) {
431      if ( copyList.at(i).at(0) == workingDisk \
432        && copyList.at(i).at(1) == workingSlice ) {
433
434        // Check if we have any extra arguments to throw on the end
435        XtraTmp="";
436        if ( ! copyList.at(i).at(5).isEmpty() )
437          XtraTmp=" (" + copyList.at(i).at(5) + ")" ;
438
439        // If we are working on the last partition, set the size to 0 to use remaining disk
440        if ( i == (count - 1) ) 
441                sliceSize = "0";
442        else
443                sliceSize=copyList.at(i).at(4);
444
445        // Write the user summary
446        summaryList << "";
447        summaryList << tr("Partition:") + " " + workingDisk + "(" + workingSlice + "):";
448        summaryList << tr("FileSystem:") + " " + copyList.at(i).at(3);
449        summaryList << tr("Size:") + " " + copyList.at(i).at(4) + "MB ";
450        if ( copyList.at(i).at(3) != "ZFS" )
451          summaryList << tr("Mount:") + " " + copyList.at(i).at(2);
452        if ( ! XtraTmp.isEmpty() ) {
453          summaryList << tr("Options:") + " " + copyList.at(i).at(5);
454        }
455
456        // Done with this item, remove it now
457        copyList.removeAt(i);
458        i--;
459        count--;
460      }
461    }
462
463    // Increment our disk counter
464    disk++;
465  }
466
467  return summaryList;
468}
469
470void Installer::slotDiskCustomizeClicked()
471{
472  wDisk = new wizardDisk();
473  wDisk->programInit();
474  wDisk->setWindowModality(Qt::ApplicationModal);
475  connect(wDisk, SIGNAL(saved(QList<QStringList>, bool, bool)), this, SLOT(slotSaveDiskChanges(QList<QStringList>, bool, bool)));
476  wDisk->show();
477  wDisk->raise();
478}
479
480void Installer::slotDesktopCustomizeClicked()
481{
482  desks = new desktopSelection();
483  if ( wheelCurItem != wPCSERVER && wheelCurItem != 11 && wheelCurItem != 12)
484     desks->programInit(listDeskPkgs,selectedPkgs);
485  else
486     desks->programInit(listServerPkgs,selectedPkgs);
487  desks->setWindowModality(Qt::ApplicationModal);
488  connect(desks, SIGNAL(saved(QStringList)), this, SLOT(slotSaveMetaChanges(QStringList)));
489  desks->show();
490  desks->raise();
491}
492
493void Installer::slotSaveMetaChanges(QStringList sPkgs)
494{
495  selectedPkgs = sPkgs;
496
497  // Only add +10 if we are not already on the custom screen
498  if ( wheelCurItem < 10 )
499    wheelCurItem= wheelCurItem + 10;
500
501  switch (wheelCurItem) {
502    case 12:
503        groupDeskSummary->setTitle(tr("TrueOS Package Selection"));
504        break;
505    case 11:
506        groupDeskSummary->setTitle(tr("FreeBSD Package Selection"));
507        break;
508    default:
509        groupDeskSummary->setTitle(tr("PC-BSD Package Selection"));
510        break;
511  }
512
513  textDeskSummary->setText(tr("The following meta-pkgs will be installed:") + "<br>" + selectedPkgs.join("<br>"));
514  graphicsViewOS->setScene(customScene);
515}
516
517void Installer::slotSaveDiskChanges(QList<QStringList> newSysDisks, bool MBR, bool GPT)
518{
519  // Save the new disk layout
520  loadMBR = MBR;
521  loadGPT = GPT;
522  sysFinalDiskLayout = newSysDisks;
523  textEditDiskSummary->clear();
524  QStringList summary = getDiskSummary();
525  for ( int i=0; i < summary.count(); ++i)
526    textEditDiskSummary->append(summary.at(i));
527               
528  textEditDiskSummary->moveCursor(QTextCursor::Start);
529 
530  // Regenerate the config
531  startConfigGen();
532}
533
534void Installer::slotDesktopLeftClicked()
535{
536  if ( wheelCurItem >= 10 ) {
537    int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
538                              tr("You currently have a custom package set configured. Continue changing to a default set?"),
539                              QMessageBox::No | QMessageBox::Yes,
540                              QMessageBox::No);
541    switch (ret) {
542    case QMessageBox::Yes:
543        break;
544    case QMessageBox::No: // :)
545        return;
546        break;
547    }
548    wheelCurItem = wheelCurItem - 10;
549    graphicsViewOS->setScene(defaultScene);
550  }
551  moveDesktopWheel(false);
552}
553
554void Installer::slotDesktopRightClicked()
555{
556  if ( wheelCurItem >= 10 ) {
557    int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
558                              tr("You currently have a custom package set configured. Continue changing to a default set?"),
559                              QMessageBox::No | QMessageBox::Yes,
560                              QMessageBox::No);
561    switch (ret) {
562    case QMessageBox::Yes:
563        break;
564    case QMessageBox::No: // :)
565        return;
566        break;
567    }
568    wheelCurItem = wheelCurItem - 10;
569    graphicsViewOS->setScene(defaultScene);
570  }
571  moveDesktopWheel(true);
572}
573
574void Installer::moveDesktopWheel(bool direction)
575{
576  qDebug() << wheelCurItem << direction;
577  // Make sure we aren't scrolling too far
578  if ( direction && wheelCurItem >= wheelIcons.size() )
579    return;
580  if ( hasFreeBSDOnMedia ) {
581    if ( ! direction && wheelCurItem <= 1 )
582      return;
583  } else {
584    if ( ! direction && wheelCurItem <= 2 )
585      return;
586  }
587
588
589  int tItem, tPixel, cPixel;
590  cPixel=96 + ((wheelCurItem-1) * 64) + (wheelCurItem * 32);
591
592  // Right
593  if ( direction ) {
594    tItem=wheelCurItem + 1;
595    tPixel=96 + ((tItem-1) * 64) + (tItem * 32);
596  } else {
597  // Left
598    tItem=wheelCurItem - 1;
599    tPixel=96 + ((tItem-1) * 64) + (tItem * 32);
600  } 
601
602  if ( direction ) {
603    while ( cPixel < tPixel ) {
604      cPixel++;
605      graphicsViewOS->centerOn(cPixel,0);
606      graphicsViewOS->show();
607      QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 22);
608     
609    }
610  } else {
611    while ( cPixel > tPixel ) {
612      cPixel--;
613      graphicsViewOS->centerOn(cPixel,0);
614      graphicsViewOS->show();
615      QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 22);
616    }
617  }
618 
619  wheelCurItem=tItem;
620
621  groupDeskSummary->setTitle(wheelName.at(tItem-1));
622  textDeskSummary->setText(wheelDesc.at(tItem-1));
623
624  // No custom packages for FreeBSD vanilla
625  if ( wheelCurItem == 1 ) 
626    pushDeskCustomize->setEnabled(false);
627  else
628    pushDeskCustomize->setEnabled(true);
629 
630  changeMetaPkgSelection();
631}
632
633void Installer::changeMetaPkgSelection()
634{
635
636  // Set the default desktop meta-pkgs based upon the selection
637  // 1 = FreeBSD
638  switch (wheelCurItem)
639  {
640    case wKDE:
641      selectedPkgs.clear();
642      selectedPkgs << "KDE" << "KDE-Accessibility" << "KDE-Artwork" << "KDE-Education" << "KDE-Games" << "KDE-Graphics" << "KDE-Multimedia" << "KDE-Network" << "KDE-PIM";
643      if ( comboLanguage->currentIndex() != 0 ) 
644         selectedPkgs << "KDE-L10N";
645      break;
646    case wLXDE:
647      selectedPkgs.clear();
648      selectedPkgs << "LXDE";
649      break;
650    case wGNOME:
651      selectedPkgs.clear();
652      selectedPkgs << "GNOME" << "GNOME-Accessibility" << "GNOME-Games" << "GNOME-Net" << "GNOME-Utilities";
653      break;
654    case wXFCE:
655      selectedPkgs.clear();
656      selectedPkgs << "XFCE" << "XFCE-Plugins";
657      break;
658    default:
659      selectedPkgs.clear();
660      return;
661  }
662
663  // Check if we are using NVIDIA driver and include it automatically
664  QFile file("/etc/X11/xorg.conf");
665  if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
666      return;
667         
668  QTextStream in(&file);
669  while (!in.atEnd()) {
670      QString line = in.readLine();
671      if ( line.indexOf("nvidia") != -1 ) {
672        selectedPkgs << "NVIDIA";
673        break;
674      }
675  }     
676  file.close();
677  // Done with NVIDIA check
678
679  qDebug() << selectedPkgs;
680
681}
682
683void Installer::initDesktopSelector()
684{
685    QString fbsdIcon;
686
687    if ( hasFreeBSDOnMedia )
688       fbsdIcon = ":modules/images/freebsd.png";
689    else
690       fbsdIcon = "";
691
692    // Init the desktop selector
693    wheelIcons << fbsdIcon << ":/modules/images/pcbsd-server.png" << ":/PCBSD/images/kde.png" << ":/PCBSD/images/lxde.png" << ":/PCBSD/images/gnome.png" << ":/PCBSD/images/xfce.png";
694    wheelName << "FreeBSD Server" << "TrueOS" << "KDE" << "LXDE" << "GNOME" << "XFCE"; 
695    wheelDesc << tr("FreeBSD is an advanced operating system for modern server, desktop, and embedded computer platforms. FreeBSD's code base has undergone over thirty years of continuous development, improvement, and optimization.") \
696    << tr("TrueOS is a console based server running FreeBSD. It includes command-line versions of The Warden jail management, PBI manager, ZFS boot environments (beadm), and other helpful utilities for system administrators.")  \
697    << tr("KDE is a full-featured desktop environment, which includes support for 3D desktop effects, multiple desktops, and a variety of built-in tools and utilities for both new and power-desktop users.<br><br>* Recommended for higher-end systems with 2GB of RAM or more *") \
698    << tr("LXDE is a lightweight desktop, minimalist in nature, with support for multiple-desktops, a system tray, application menu and more.<br><br>* Recommended for netbooks, or lower-end systems * ") \
699    << tr("GNOME is a full-featured desktop environment, complete with a large number of integrated utilities and tools for desktop users.") \
700    << tr("XFCE is a light and modular desktop, with a number of features to enhance customizing the desktop to your liking."); 
701
702    int xOff=96;
703    defaultScene = new QGraphicsScene(0,0,(96 + 96 + (wheelIcons.size()*64) + (wheelIcons.size()*32) ),64);
704    for ( int i = 0; i < wheelIcons.size(); ++i) {
705      defaultScene->addPixmap(QPixmap(wheelIcons.at(i)))->setOffset(xOff,0);
706      xOff = xOff +96;
707    }
708    graphicsViewOS->setScene(defaultScene);
709
710    // If less than 2GB memory, default to LXDE, otherwise KDE
711    if ( systemMemory > 2048 )  {
712      wheelCurItem=2;
713    } else {
714      wheelCurItem=3;
715    }
716    graphicsViewOS->centerOn(191,0);
717    graphicsViewOS->show();
718    moveDesktopWheel(true);
719
720    customScene = new QGraphicsScene(0,0,220,64);
721    customScene->addText(tr("Custom Package Selection"));
722
723    // Connect our slots
724    connect(pushDeskRight,SIGNAL(clicked()), this, SLOT(slotDesktopRightClicked()));
725    connect(pushDeskLeft,SIGNAL(clicked()), this, SLOT(slotDesktopLeftClicked()));
726    connect(pushDeskCustomize,SIGNAL(clicked()), this, SLOT(slotDesktopCustomizeClicked()));
727}
728
729void Installer::proceed(bool forward)
730{
731    int count = installStackWidget->count() - 1;
732    int index = installStackWidget->currentIndex();
733
734    index = forward ?
735            (index == count ? count : index + 1) :
736            (index == 0 ? 0 : index - 1);
737
738    if ( index > 0 && index != 4)
739      backButton->setVisible(true);
740    else
741      backButton->setVisible(false);
742
743    installStackWidget->setCurrentIndex(index);
744}
745
746// Slot which is called when the Finish button is clicked
747void Installer::slotFinished()
748{
749  qApp->quit();
750}
751
752void Installer::slotSaveFBSDSettings(QString rootPW, QString name, QString userName, QString userPW, QString shell, QString hostname, bool ssh, bool src, bool ports, QStringList netSettings)
753{
754  fRootPW = rootPW;
755  fName = name;
756  fUserName = userName;
757  fUserPW = userPW;
758  fShell = shell;
759  fHost = hostname;
760  fSSH = ssh;
761  fSRC = src;
762  fPORTS = ports;
763  fNetSettings = netSettings;
764  installStackWidget->setCurrentIndex(installStackWidget->currentIndex() + 1);
765
766  // Generate the pc-sysinstall config
767  startConfigGen();
768}
769
770void Installer::slotNext()
771{
772   QString tmp;
773
774   // If no pkgs on media
775   if ( installStackWidget->currentIndex() == 0 && ! hasPkgsOnMedia) {
776     installStackWidget->setCurrentIndex(2);
777     return;
778   }
779
780   // Start the FreeBSD wizard
781   if ( installStackWidget->currentIndex() == 1 && (wheelCurItem == wFREEBSD || wheelCurItem == wPCSERVER || wheelCurItem == 12) ) {
782     bool tOS;
783     if ( wheelCurItem == wPCSERVER || wheelCurItem == 12 )
784       tOS = true;
785     else
786       tOS = false;
787
788     wFBSD = new wizardFreeBSD();
789     wFBSD->setWindowModality(Qt::ApplicationModal);
790     wFBSD->programInit(tOS);
791     connect(wFBSD, SIGNAL(saved(QString, QString, QString, QString, QString, QString, bool, bool, bool, QStringList)), this, SLOT(slotSaveFBSDSettings(QString, QString, QString, QString, QString, QString, bool, bool, bool, QStringList)));
792     wFBSD->show();
793     wFBSD->raise();
794     return ;
795   }
796
797   // Create the pc-sysinstall config
798   if ( installStackWidget->currentIndex() == 1 )
799     startConfigGen();
800
801   // If the chosen disk is too small or partition is invalid, don't continue
802   if ( installStackWidget->currentIndex() == 2 && ! checkDiskRequirements())
803      return;
804
805   if ( installStackWidget->currentIndex() == 2 )
806   {
807      startConfigGen();
808      int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
809                                tr("Start the installation now?"),
810                                QMessageBox::No | QMessageBox::Yes,
811                                QMessageBox::No);
812      switch (ret) {
813      case QMessageBox::Yes:
814          startInstall();
815          break;
816      case QMessageBox::No: // :)
817          return;
818          break;
819      }
820   }
821
822   proceed(true);
823}
824
825void Installer::slotBack()
826{
827   // If no pkgs on media
828   if ( installStackWidget->currentIndex() == 2 && ! hasPkgsOnMedia) {
829        installStackWidget->setCurrentIndex(0);
830        return;
831   }
832
833   proceed(false);
834}
835
836void Installer::slotAbort()
837{
838   close();
839}
840
841void Installer::slotChangeLanguage()
842{
843    if ( comboLanguage->currentIndex() == -1 )
844      return;
845
846    // Figure out the language code
847    QString langCode = languages.at(comboLanguage->currentIndex());
848   
849    // Grab the language code
850    langCode.truncate(langCode.lastIndexOf(")"));
851    langCode.remove(0, langCode.lastIndexOf("(") + 1); 
852
853    // Check what directory our app is in
854    QString appDir;
855    if ( QFile::exists("/usr/local/bin/pc-sysinstaller") )
856      appDir = "/usr/local/share/pcbsd";
857    else
858      appDir = QCoreApplication::applicationDirPath();
859
860    //QTranslator *translator = new QTranslator();
861    qDebug() << "Remove the translator";
862    if ( ! translator->isEmpty() )
863      QCoreApplication::removeTranslator(translator);
864
865    if (translator->load( QString("SysInstaller_") + langCode, appDir + "/i18n/" )) {
866      qDebug() << "Load new Translator" << langCode;
867      QCoreApplication::installTranslator(translator);
868      this->retranslateUi(this);
869    }
870}
871
872void Installer::changeLang(QString code)
873{
874   // Change the language in the combobox with the current running one
875   comboLanguage->disconnect();
876
877   for (int i=0; i < languages.count(); ++i) {
878      if ( languages.at(i).indexOf("(" + code + ")" ) != -1 ) {
879        comboLanguage->setCurrentIndex(i); 
880      }
881   }
882
883   connect(comboLanguage, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotChangeLanguage()));
884}
885
886QStringList Installer::getGlobalCfgSettings()
887{
888
889  QStringList tmpList;
890  QString tmp, upDrive;
891
892  tmpList << "# Auto-Generated pc-sysinstall configuration";
893  tmpList << "installInteractive=no";
894
895  if ( sysFinalDiskLayout.at(0).at(0) == "MANUAL" )
896  {
897    tmpList << "installMode=extract";
898    tmpList << "installLocation=/mnt";
899  } else {
900    // Doing a fresh install
901    tmpList << "installMode=fresh";
902  }
903 
904  QString distFiles;
905  distFiles="base doc games kernel";
906  if ( Arch == "amd64" )
907     distFiles+=" lib32";
908
909  // If we are doing a PC-BSD install
910  if ( wheelCurItem != wPCSERVER && wheelCurItem != 12 && wheelCurItem != wFREEBSD ) {
911    tmpList << "installType=PCBSD";
912    tmpList << "packageType=dist";
913  } else {
914    tmpList << "installType=FreeBSD";
915    tmpList << "packageType=dist";
916  }
917
918  // Set the distFiles being used
919  tmpList << "distFiles=" + distFiles;
920  tmpList << "";
921
922  // If we have a custom hostname, add it to the config
923  if ( ! fHost.isEmpty() )
924    tmpList << "hostname=" + fHost;
925
926 
927  // Networking setup
928  if ( wheelCurItem != wFREEBSD && wheelCurItem != wPCSERVER && wheelCurItem != 12 ) {
929    // PC-BSD network setup
930    tmpList << "netSaveDev=AUTO-DHCP-SLAAC";
931  } else {
932    // FreeBSD network setup
933    if ( fNetSettings.at(0) == "AUTO-DHCP" )
934      tmpList << "netSaveDev=AUTO-DHCP";
935    else if ( fNetSettings.at(0) == "AUTO-DHCP-SLAAC" ) {
936      tmpList << "netSaveDev=AUTO-DHCP-SLAAC";
937      // We cannot rely on SLAAC to provide DNS for example.  The same is true
938      // for DHCP but the worls seems to have forgotten...
939      tmpList << "netSaveIPv6=" + fNetSettings.at(5);
940      tmpList << "netSaveIPv6NameServer=" + fNetSettings.at(6);
941      tmpList << "netSaveIPv6DefaultRouter=" + fNetSettings.at(7);
942    } else if ( fNetSettings.at(0) == "IPv6-SLAAC" ) {
943       tmpList << "netSaveDev=IPv6-SLAAC";
944      // We cannot rely on SLAAC to provide DNS for example.  The same is true
945      // for DHCP but the worls seems to have forgotten...
946      tmpList << "netSaveIPv6=" + fNetSettings.at(5);
947      tmpList << "netSaveIPv6NameServer=" + fNetSettings.at(6);
948      tmpList << "netSaveIPv6DefaultRouter=" + fNetSettings.at(7);
949    } 
950    else
951    {
952      tmp = fNetSettings.at(0);
953      if ( tmp.indexOf(":") > 0 )
954        tmp.truncate(tmp.indexOf(":"));
955      tmpList << "netSaveDev=" + tmp;
956      tmpList << "netSaveIP_" + tmp + "=" + fNetSettings.at(1); 
957      tmpList << "netSaveMask_" + tmp + "=" + fNetSettings.at(2);
958      tmpList << "netSaveNameServer=" + fNetSettings.at(3);
959      tmpList << "netSaveDefaultRouter=" + fNetSettings.at(4);
960      tmpList << "netSaveIPv6=" + fNetSettings.at(5);
961      tmpList << "netSaveIPv6NameServer=" + fNetSettings.at(6);
962      tmpList << "netSaveIPv6DefaultRouter=" + fNetSettings.at(7);
963    }
964  }
965
966
967  // Doing install from /dist directory
968  tmpList << "installMedium=local"; 
969  tmpList << "localPath=/dist";
970
971  if ( comboLanguage->currentIndex() != 0 ) {
972    QString lang = languages.at(comboLanguage->currentIndex());
973    // Grab the language code
974    lang.truncate(lang.lastIndexOf(")"));
975    lang.remove(0, lang.lastIndexOf("(") + 1);
976    tmpList << "";
977    tmpList << "localizeLang=" + lang;
978  }
979
980  // Setup custom keyboard layouts
981  /* KPM
982  tmpList << "";
983  tmpList << "# Keyboard Layout Options";
984  tmp = comboBoxKeyboardModel->currentText();
985  tmp.truncate(tmp.indexOf(")"));
986  tmp = tmp.remove(0, tmp.indexOf(" (") + 2 );
987  tmpList << "localizeKeyModel=" + tmp;
988
989  tmp = listKbLayouts->currentItem()->text();
990  tmp.truncate(tmp.indexOf(")"));
991  tmp = tmp.remove(0, tmp.indexOf(" (") + 2 );
992  tmpList << "localizeKeyLayout=" + tmp;
993
994  tmp = listKbVariants->currentItem()->text();
995  if ( tmp != "<none>" ) {
996    tmp.truncate(tmp.indexOf(")"));
997    tmp = tmp.remove(0, tmp.indexOf(" (") + 2 );
998    tmpList << "localizeKeyVariant=" + tmp;
999  }
1000  */
1001
1002  tmpList << " ";
1003
1004  return tmpList;
1005}
1006
1007void Installer::startConfigGen()
1008{
1009
1010  if ( ! haveWarnedSpace )
1011     checkSpaceWarning();
1012
1013  QStringList cfgList;
1014
1015  // Generate the config file now
1016  cfgList+=getGlobalCfgSettings();
1017
1018  cfgList+=getDiskCfgSettings();
1019
1020  cfgList+=getComponentCfgSettings();
1021
1022  // Save the install config script to disk
1023  cfgList << "runExtCommand=/root/save-config.sh";
1024
1025  cfgList+= "";
1026
1027  // If doing install from package disk
1028  if ( hasPkgsOnMedia )
1029    cfgList+=getDeskPkgCfg();
1030
1031  cfgList+= "";
1032
1033  if ( wheelCurItem != wFREEBSD && wheelCurItem != wPCSERVER && wheelCurItem != 12 ) {
1034    // Doing PC-BSD Install
1035
1036    QString lang;
1037    if ( comboLanguage->currentIndex() != 0 )
1038      lang = languages.at(comboLanguage->currentIndex());
1039    else
1040      lang="en_US";
1041
1042    // Setup the desktop
1043    cfgList << "runCommand=sh /usr/local/share/pcbsd/scripts/sys-init.sh desktop " + lang;
1044
1045    // Setup for a fresh system first boot
1046    cfgList << "# Touch flags to enable PC-BSD setup at first boot";
1047    cfgList << "runCommand=touch /var/.runxsetup";
1048    cfgList << "runCommand=touch /var/.pcbsd-firstboot";
1049    cfgList << "runCommand=touch /var/.pcbsd-firstgui";
1050
1051  } else if ( wheelCurItem == wPCSERVER || wheelCurItem == 12 ) {
1052    // Doing TrueOS Install
1053    cfgList+=getUsersCfgSettings();
1054
1055    // Enable SSH?
1056    if ( fSSH )
1057      cfgList << "runCommand=echo 'sshd_enable=\"YES\"' >>/etc/rc.conf";
1058
1059    // Setup the TrueOS server
1060    cfgList << "runCommand=sh /usr/local/share/pcbsd/scripts/sys-init.sh server";
1061
1062  } else { // End of PC-BSD specific setup
1063    // Doing FreeBSD Install
1064    cfgList+=getUsersCfgSettings();
1065
1066    // Enable SSH?
1067    if ( fSSH )
1068      cfgList << "runCommand=echo 'sshd_enable=\"YES\"' >>/etc/rc.conf";
1069
1070  }
1071
1072  // Run newaliases to fix mail errors
1073  cfgList << "runCommand=newaliases";
1074
1075  // Now write out the cfgList to file
1076  QFile cfgfile( PCSYSINSTALLCFG );
1077  if ( cfgfile.open( QIODevice::WriteOnly ) ) {
1078    QTextStream stream( &cfgfile );
1079    for ( int i=0; i < cfgList.count(); ++i) {
1080      stream <<  cfgList.at(i) << "\n";
1081    }
1082    cfgfile.close();
1083  }
1084}
1085
1086void Installer::slotHelp()
1087{
1088        pcHelp = new dialogHelp();
1089        switch (installStackWidget->currentIndex()) {
1090        case 0:
1091                pcHelp->dialogInit(HELPTEXT0);
1092                break;
1093        case 1:
1094                pcHelp->dialogInit(HELPTEXT1);
1095                break;
1096        case 2:
1097                pcHelp->dialogInit(HELPTEXT2);
1098                break;
1099        case 3:
1100                pcHelp->dialogInit(HELPTEXT3);
1101                break;
1102        default:
1103                pcHelp->dialogInit("No help text...");
1104                break;
1105        }
1106        pcHelp->show();
1107}
1108
1109// Function which returns the pc-sysinstall cfg data
1110QStringList Installer::getDiskCfgSettings()
1111{
1112  QStringList tmpList;
1113  QList<QStringList> copyList;
1114  QString tmp, workingDisk, workingSlice, tmpSlice, XtraTmp, startPart, sliceSize;
1115  int disk = 0;
1116
1117  // Copy over the list to a new variable we can mangle without modifying the original
1118  copyList = sysFinalDiskLayout;
1119
1120  // Doing manual extraction
1121  if ( copyList.at(0).at(0) == "MANUAL" )
1122    return QStringList();
1123
1124  while ( ! copyList.empty() )
1125  {
1126    workingDisk = copyList.at(0).at(0);
1127    workingSlice = copyList.at(0).at(1);
1128    tmpSlice = workingSlice;
1129    tmpList << "# Disk Setup for " + workingDisk ;
1130
1131    // Check if this is an install to "Unused Space"
1132    for (int z=0; z < sysDisks.count(); ++z)
1133      if ( sysDisks.at(z).at(0) == "SLICE" \
1134        && sysDisks.at(z).at(2) == workingDisk + workingSlice \
1135        && sysDisks.at(z).at(4) == "Unused Space" )
1136          tmpSlice = "free";
1137
1138    tmpList << "disk" + tmp.setNum(disk) + "=" + workingDisk;
1139    tmpList << "partition=" + tmpSlice;
1140
1141    // Are we loading a boot-loader?
1142    if ( loadMBR )
1143      tmpList << "bootManager=bsd";
1144    else
1145      tmpList << "bootManager=none";
1146
1147    // Set the GPT/MBR options
1148    if ( loadGPT ) 
1149      tmpList << "partscheme=GPT";
1150    else
1151      tmpList << "partscheme=MBR";
1152
1153    tmpList << "commitDiskPart";
1154    tmpList << "";
1155
1156    // If after doing the mirror, our list is empty, break out
1157    if ( copyList.empty() )
1158      break;
1159   
1160    // Now print the partition section for this slice
1161    tmpList << "# Partition Setup for " + workingDisk + "(" + workingSlice + ")";
1162    tmpList << "# All sizes are expressed in MB";
1163    tmpList << "# Avail FS Types, UFS, UFS+S, UFS+SUJ, UFS+J, ZFS, SWAP";
1164    tmpList << "# UFS.eli, UFS+S.eli, UFS+SUJ, UFS+J.eli, ZFS.eli, SWAP.eli";
1165
1166    // If there is a dedicated /boot partition, need to list that first, see what is found
1167    for (int i=0; i < copyList.count(); ++i) {
1168      QStringList mounts = copyList.at(i).at(2).split(",");
1169      for (int z = 0; z < mounts.size(); ++z) {
1170        if ( copyList.at(i).at(0) == workingDisk \
1171          && copyList.at(i).at(1) == workingSlice \
1172          && mounts.at(z) == "/boot" )
1173                startPart="/boot";
1174      }
1175    }
1176
1177    // If no dedicated /boot partition, then lets list "/" first
1178    if(startPart.isEmpty())
1179        startPart="/";
1180
1181    // Start by looking for the root partition
1182    for (int i=0; i < copyList.count(); ++i) {
1183      QStringList mounts = copyList.at(i).at(2).split(",");
1184      for (int z = 0; z < mounts.size(); ++z) {
1185        if ( copyList.at(i).at(0) == workingDisk \
1186          && copyList.at(i).at(1) == workingSlice \
1187          && mounts.at(z) == startPart ) {
1188
1189          // Check if we have any extra arguments to throw on the end
1190          XtraTmp="";
1191          if ( ! copyList.at(i).at(5).isEmpty() )
1192            XtraTmp=" (" + copyList.at(i).at(5) + ")" ;
1193
1194          // Write out the partition line
1195          tmpList << "disk" + tmp.setNum(disk) + "-part=" \
1196                   + copyList.at(i).at(3) + " " + copyList.at(i).at(4) \
1197                   + " " + copyList.at(i).at(2) + XtraTmp;
1198
1199          // Check if we have an encryption passphrase to use
1200          if ( ! copyList.at(i).at(6).isEmpty() )
1201            tmpList << "encpass=" + copyList.at(i).at(6);
1202
1203          // Done with this item, remove it now
1204          copyList.removeAt(i);
1205          break;
1206        }
1207      }
1208    }
1209
1210    // Now look for SWAP
1211    for (int i=0; i < copyList.count(); ++i) {
1212      if ( copyList.at(i).at(0) == workingDisk \
1213        && copyList.at(i).at(1) == workingSlice \
1214        && copyList.at(i).at(2) == "SWAP" ) {
1215
1216        // Write the partition line
1217        tmpList << "disk" + tmp.setNum(disk) + "-part=" \
1218                 + copyList.at(i).at(3) + " " + copyList.at(i).at(4) \
1219                 + " none";
1220
1221        // Done with this item, remove it now
1222        copyList.removeAt(i);
1223        break;
1224      }
1225    }
1226 
1227    // Now look for any other partitions
1228    int count = copyList.count();
1229    for (int i=0; i < count; ++i) {
1230      if ( copyList.at(i).at(0) == workingDisk \
1231        && copyList.at(i).at(1) == workingSlice ) {
1232
1233        // Check if we have any extra arguments to throw on the end
1234        XtraTmp="";
1235        if ( ! copyList.at(i).at(5).isEmpty() )
1236          XtraTmp=" (" + copyList.at(i).at(5) + ")" ;
1237
1238        // If we are working on the last partition, set the size to 0 to use remaining disk
1239        if ( i == (count - 1) ) 
1240                sliceSize = "0";
1241        else
1242                sliceSize=copyList.at(i).at(4);
1243
1244        // Write the partition line
1245        tmpList << "disk" + tmp.setNum(disk) + "-part=" \
1246                 + copyList.at(i).at(3) + " " + sliceSize \
1247                 + " " + copyList.at(i).at(2) + XtraTmp;
1248
1249        // Check if we have an encryption passphrase to use
1250        if ( ! copyList.at(i).at(6).isEmpty() )
1251          tmpList << "encpass=" + copyList.at(i).at(6);
1252
1253        // Done with this item, remove it now
1254        copyList.removeAt(i);
1255        i--;
1256        count--;
1257      }
1258    }
1259
1260
1261    // Close out this partition section
1262    tmpList << "commitDiskLabel";
1263    tmpList << "";
1264
1265    // Increment our disk counter
1266    disk++;
1267  }
1268
1269  return tmpList;
1270}
1271
1272// Slot which checks any disk requirements before procceding to the next page
1273bool Installer::checkDiskRequirements()
1274{
1275  // For now just return true, the wizard should handle making sure
1276  // the user doesn't shoot themselves in the foot during disk setup
1277  return true;
1278}
1279
1280// Function which begins the backend install, and connects slots to monitor it
1281void Installer::startInstall()
1282{
1283  // Disable the back / next buttons until we are finished
1284  nextButton->setEnabled(false);
1285  backButton->setEnabled(false);
1286  progressBarInstall->setValue(0); 
1287  installFoundCounter = false;
1288  installFoundMetaCounter = false;
1289  installFoundFetchOutput = false;
1290
1291  // Setup some defaults for the secondary progress bar
1292  progressBarInstall2->setValue(0); 
1293  progressBarInstall2->setHidden(true); 
1294  labelInstallStatus2->setText("");
1295  labelInstallStatus2->setHidden(true);
1296
1297  // Kill any hald instances, which causes failures to install when it
1298  // tries to mount our new partitions
1299  QProcess::execute("killall", QStringList() << "hald");
1300
1301  // Start our process to begin the install
1302  QString PCSYSINSTALL;
1303  if ( QFile::exists("/root/pc-sysinstall/pc-sysinstall") ) 
1304     PCSYSINSTALL = "/root/pc-sysinstall/pc-sysinstall";
1305  else 
1306     PCSYSINSTALL = "/usr/local/sbin/pc-sysinstall";
1307
1308  QString program = PCSYSINSTALL;
1309  QStringList arguments;
1310  arguments << "-c" << PCSYSINSTALLCFG;
1311
1312  installProc = new QProcess();
1313  installProc->setProcessChannelMode(QProcess::MergedChannels);
1314  connect(installProc,SIGNAL(finished( int, QProcess::ExitStatus)),this,SLOT(slotInstallProcFinished( int, QProcess::ExitStatus)));
1315  connect(installProc,SIGNAL(readyRead()),this,SLOT(slotReadInstallerOutput()));
1316  installProc->start(program, arguments);
1317
1318}
1319
1320// Function run when the install failed to prompt user for course of action
1321void Installer::installFailed()
1322{
1323   QString sysLog;
1324   labelInstallStatus->setText(tr("Failed!"));
1325
1326   QMessageBox msgBox;
1327   msgBox.setWindowTitle(tr("PC-BSD Installer"));
1328   msgBox.setIcon(QMessageBox::Critical);
1329   msgBox.setText(tr("The installer has encountered an error and has been halted."));
1330   msgBox.setInformativeText(tr("Do you want to generate an error report?"));
1331   msgBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
1332   msgBox.setDefaultButton(QMessageBox::Yes);
1333
1334   // If we have a log, show it in the detailed view button
1335   if ( QFile::exists("/tmp/.pc-sysinstall/pc-sysinstall.log") )
1336   {
1337     QFile logFile("/tmp/.pc-sysinstall/pc-sysinstall.log");
1338     if (logFile.open(QIODevice::ReadOnly | QIODevice::Text))
1339         while (!logFile.atEnd())
1340           sysLog = sysLog + logFile.readLine() + "\n";
1341     msgBox.setDetailedText(sysLog);
1342   }
1343   int ret = msgBox.exec();
1344
1345   switch (ret) {
1346   case QMessageBox::Yes:
1347       // Generate the error report
1348       Scripts::Backend::createErrorReport();
1349       break;
1350   case QMessageBox::No: // :)
1351       break;
1352   }
1353
1354   QMessageBox msgBox2;
1355   msgBox2.setWindowTitle(tr("PC-BSD Installer"));
1356   msgBox2.setIcon(QMessageBox::Critical);
1357   msgBox2.setText(tr("Restart the system now?") );
1358   msgBox2.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
1359   msgBox2.setDefaultButton(QMessageBox::Yes);
1360   msgBox2.setDetailedText(sysLog);
1361
1362   ret = msgBox2.exec();
1363
1364   switch (ret) {
1365   case QMessageBox::Yes:
1366       close();
1367       break;
1368   case QMessageBox::No: // :)
1369       break;
1370   }
1371
1372}
1373
1374// Slot which is called when the installation has finished
1375void Installer::slotInstallProcFinished( int exitCode, QProcess::ExitStatus status)
1376{
1377  QString tmp;
1378  if ( status != QProcess::NormalExit || exitCode != 0 )
1379  {
1380     installFailed();
1381  } else {
1382    // Move to the final page, and show a finish button
1383    proceed(true);
1384    nextButton->setEnabled(true);
1385    nextButton->setText(tr("&Finish"));
1386    nextButton->disconnect();
1387    connect(nextButton, SIGNAL(clicked()), this, SLOT(slotFinished()));
1388    backButton->setEnabled(false);
1389    abortButton->setEnabled(false);
1390  }
1391}
1392
1393// Slot which reads the output of the installer
1394void Installer::slotReadInstallerOutput()
1395{
1396  QString tmp, line;
1397  int range;
1398  bool ok;
1399
1400
1401  while ( installProc->canReadLine() )
1402  {
1403     tmp = installProc->readLine();
1404     tmp.truncate(75);
1405     //qDebug() << tmp;
1406
1407     // If doing a restore, don't bother checking for other values
1408     //if ( radioRestore->isChecked() ) {
1409     //   labelInstallStatus->setText(tmp);
1410     // continue;
1411     //}
1412
1413     // Parse fetch output
1414     if ( installFoundFetchOutput ) {
1415       if ( tmp.indexOf("SIZE: ") != -1 ) {
1416
1417          // Get the total range first
1418          line = tmp;
1419          tmp = tmp.remove(0, tmp.indexOf(":") + 2 );
1420          tmp.truncate(tmp.indexOf(" ")); 
1421          range = tmp.toInt(&ok);
1422          if ( ok )
1423             progressBarInstall->setRange(0, range + 1);
1424
1425          // Now get the current progress
1426          tmp = line;
1427          tmp = tmp.remove(0, tmp.indexOf(":") + 2 );
1428          tmp = tmp.remove(0, tmp.indexOf(":") + 2 );
1429          range = tmp.toInt(&ok);
1430          if ( ok )
1431             progressBarInstall->setValue(range);
1432           
1433          continue;
1434        } else {
1435          installFoundFetchOutput = false;
1436          break;
1437        }
1438     } 
1439
1440     // Unknown point in install
1441     if ( ! installFoundCounter && ! installFoundMetaCounter ) {
1442
1443        // Check if we've found fetch output to update the progress bar with
1444        if ( tmp.indexOf("FETCH: ") != -1 ) {
1445          installFoundFetchOutput = true;
1446          break;
1447        }
1448
1449        if ( tmp.indexOf("INSTALLCOUNT: ") != -1 ) {
1450          tmp = tmp.remove(0, tmp.indexOf(":") + 1 ); 
1451          range = tmp.toInt(&ok);
1452          if ( ok ) {
1453             range = range + 50;
1454             progressBarInstall->setRange(0, range + 1); 
1455             installFoundCounter = true;
1456             if ( availDesktopPackageData )
1457                labelInstallStatus->setText(tr("Extracting system...")); 
1458             else
1459                labelInstallStatus->setText(tr("Installing system... This may take a while...")); 
1460          }
1461
1462          break;
1463
1464        } 
1465
1466        // Check if we are on the meta-pkg installation
1467        if ( tmp.indexOf("Packages to install: ") != -1 ) {
1468          tmp = tmp.remove(0, tmp.indexOf(":") + 1 ); 
1469          range = tmp.toInt(&ok);
1470          if ( ok ) {
1471             progressBarInstall->setRange(0, range + 1); 
1472             progressBarInstall->setValue(0); 
1473             progressBarInstall2->setRange(0, 0); 
1474             labelInstallStatus2->setHidden(false);
1475             progressBarInstall2->setHidden(false); 
1476             installFoundMetaCounter = true;
1477             installFoundCounter = false;
1478             labelInstallStatus->setText(tr("Installing packages... This may take a while...")); 
1479             continue;
1480          }
1481
1482        } 
1483
1484        labelInstallStatus->setText(tmp);
1485        continue; 
1486     } 
1487
1488     // Doing file-extraction still
1489     if ( installFoundCounter ) {
1490
1491       // Doing dist-files, may have multiple images to extract
1492       if ( tmp.indexOf("INSTALLCOUNT: ") != -1 ) {
1493         tmp = tmp.remove(0, tmp.indexOf(":") + 1 ); 
1494         range = tmp.toInt(&ok);
1495         if ( ok ) {
1496            progressBarInstall->setRange(0, range + 1); 
1497            installFoundCounter = true;
1498            if ( availDesktopPackageData )
1499              labelInstallStatus->setText(tr("Extracting system...")); 
1500            else
1501              labelInstallStatus->setText(tr("Installing system... This may take a while...")); 
1502         }
1503         break;
1504       } 
1505
1506
1507       // Increment the progress
1508       progressBarInstall->setValue(progressBarInstall->value() + 1); 
1509
1510       // We've reached the end of this counted section
1511       if ( tmp.indexOf("Extraction Finished") != -1 ) {
1512         installFoundCounter = false;
1513         progressBarInstall->setRange(0, 0); 
1514       }
1515
1516       continue;
1517     }
1518
1519     // Doing meta-pkgs
1520     if ( installFoundMetaCounter ) {
1521        if ( tmp.indexOf("Package installation complete!") != -1 ) {
1522           installFoundMetaCounter = false;
1523           progressBarInstall->setRange(0, 0); 
1524           progressBarInstall2->setHidden(true);
1525           labelInstallStatus2->setHidden(true);
1526           continue;
1527        }
1528
1529        // If we are installing a package, show details to user
1530        if ( tmp.indexOf("Installing") == 0 )
1531          labelInstallStatus2->setText(tmp.section("...", 0, 0));
1532     }
1533
1534  } // end of while loop
1535}
1536
1537// Return list of components to install
1538QStringList Installer::getComponentCfgSettings()
1539{
1540  QStringList componentList, com;
1541  if ( fSRC )
1542    com << "src";
1543  if ( fPORTS )
1544    com << "ports";
1545
1546  if ( ! com.isEmpty() ) {
1547    componentList << "";
1548    componentList << "# Optional Components";
1549    componentList << "installComponents=" + com.join(",");
1550  }
1551
1552  return componentList;
1553}
1554
1555// Start xvkbd
1556void Installer::slotPushVirtKeyboard()
1557{
1558   system("killall -9 xvkbd; xvkbd -compact &");
1559}
1560
1561// Return the configuration for desktop packages
1562QStringList Installer::getDeskPkgCfg()
1563{
1564   if ( wheelCurItem == wFREEBSD )
1565      return QStringList();
1566
1567   QStringList cfgList, pkgList;
1568   QString line;
1569
1570   QList<QStringList> curList;
1571
1572   if ( wheelCurItem != wPCSERVER && wheelCurItem != 11 && wheelCurItem != 12) {
1573     curList = listDeskPkgs;
1574     pkgList << "pcbsd-base";
1575   } else {
1576     curList = listServerPkgs;
1577     pkgList << "trueos-base";
1578   }
1579
1580   // Loop though list of pkgs, see what to install
1581   for ( int d=0; d < curList.count(); ++d) {
1582     for ( int i=0; i < selectedPkgs.count(); ++i)
1583        // Is the package selected or the base-system?
1584        if ( curList.at(d).at(0) == selectedPkgs.at(i) || curList.at(d).at(0) == "base-system" ) {
1585
1586           // Yay! Lets get a list of packages to install
1587           QFile mFile;
1588           mFile.setFileName(curList.at(d).at(6));
1589           if ( ! mFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
1590              qDebug() << "Invalid meta-pkg list:" << curList.at(d).at(6);
1591              break;
1592           }
1593 
1594           // Read in the meta pkg list
1595           QTextStream in(&mFile);
1596           while ( !in.atEnd() ) {
1597             line = in.readLine().simplified();
1598             if ( line.isEmpty() )
1599                 continue; 
1600             
1601             pkgList << line.section(":", 0,0);
1602           }
1603           mFile.close();
1604           break;
1605        }
1606   }
1607
1608   cfgList << "installPackages=" + pkgList.join(" ");
1609   return cfgList;
1610}
1611
1612// Return list of users in cfg format
1613QStringList Installer::getUsersCfgSettings()
1614{
1615   QStringList userList;
1616 
1617   userList << "";
1618   userList << "# Root Password";
1619   userList << "rootPass=" + fRootPW;
1620
1621   userList << "";
1622   userList << "# Users";
1623   userList << "userName=" + fUserName;
1624   userList << "userComment=" + fName;
1625   userList << "userPass=" + fUserPW;
1626   userList << "userShell=" + fShell;
1627   userList << "userHome=/home/" + fUserName;
1628   userList << "userGroups=wheel,operator";
1629   userList << "commitUser";
1630   userList << "";
1631 
1632   return userList;
1633}
1634
1635void Installer::closeEvent(QCloseEvent *event)
1636{
1637    int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
1638                                tr("Are you sure you want to abort this installation?"),
1639                                QMessageBox::No | QMessageBox::Yes,
1640                                QMessageBox::No);
1641    switch (ret) {
1642    case QMessageBox::Yes:
1643        //exit the installer :(
1644        break;
1645    case QMessageBox::No: // :)
1646        event->ignore();
1647        break;
1648    }
1649}
1650
1651void Installer::checkSpaceWarning()
1652{
1653  int totalSize = -1;
1654  int targetSize;
1655  int targetLoc;
1656  bool ok;
1657  QString workingDisk = sysFinalDiskLayout.at(0).at(0);
1658  QString workingSlice = sysFinalDiskLayout.at(0).at(1);
1659  QString targetType;
1660  QString target;
1661  //qDebug() << "Disk layout:" << workingDisk << workingSlice;
1662
1663  if ( workingSlice == "ALL" ) {
1664    targetType = "DRIVE";
1665    target = workingDisk;
1666    targetLoc = 1;
1667  } else {
1668    targetType = "SLICE";
1669    target = workingDisk + workingSlice;
1670    targetLoc = 2;
1671  }
1672 
1673  // Lets get the size for this disk / partition
1674  for (int i=0; i < sysDisks.count(); ++i) {
1675      // Make sure to only add the slices to the listDiskSlices
1676      if ( sysDisks.at(i).at(0) == targetType && target == sysDisks.at(i).at(targetLoc))
1677        totalSize = sysDisks.at(i).at(targetLoc + 1).toInt(&ok);
1678  }
1679
1680  //qDebug() << totalSize;
1681
1682  if ( installStackWidget->currentIndex() == 1 && (wheelCurItem == wPCSERVER || wheelCurItem == 12) )
1683     targetSize=20000;
1684  else
1685     targetSize=50000;
1686
1687  int tGB = targetSize / 1000;
1688
1689  qDebug() << totalSize << targetSize;
1690
1691  // Lets print a nice handy warning for users with possible
1692  // low disk space issues
1693  if ( totalSize < targetSize ) {
1694  QMessageBox::warning(this, tr("PC-BSD Installer"),
1695      QString(tr("The selected disk / partition is less than recommended %1GB. The installation may fail...")).arg(tGB),
1696      QMessageBox::Ok,
1697      QMessageBox::Ok);
1698      haveWarnedSpace = true;     
1699  }
1700
1701  return;
1702}
1703
1704void Installer::slotSaveConfigUSB()
1705{
1706  int ret = QMessageBox::question(this, tr("PC-BSD Installer"),
1707           tr("This will save your installation configuration to a MSDOSFS/FAT32 formatted USB stick. Continue?"),
1708           QMessageBox::No | QMessageBox::Yes,
1709           QMessageBox::No);
1710  switch (ret) {
1711  case QMessageBox::Yes:
1712      break;
1713  case QMessageBox::No: // :)
1714      return;
1715      break;
1716  }
1717
1718  // Prompt to insert USB stick
1719  QMessageBox::information(this, tr("PC-BSD Installer"),
1720          tr("Please insert a USB stick now, and click OK to continue."),
1721          QMessageBox::Ok,
1722          QMessageBox::Ok);
1723
1724  // While USB is settling, this is a good time to ask for the config nickname
1725  bool ok;
1726  QString cfgName = QInputDialog::getText(this, tr("PC-BSD Installer"),
1727                 tr("Please enter the nickname you want to save this configuration as."), 
1728                 QLineEdit::Normal,
1729                 QString("default"), &ok);
1730  if (!ok || cfgName.isEmpty())
1731     return;
1732
1733  // Now lets try to save the media
1734  qDebug() << "Running: /root/save-to-usb.sh" << cfgName;
1735  QProcess m;
1736  m.start(QString("/root/save-to-usb.sh"), QStringList() << cfgName);
1737  while(m.state() == QProcess::Starting || m.state() == QProcess::Running) {
1738     m.waitForFinished(200);
1739     QCoreApplication::processEvents();
1740  }
1741
1742  if ( m.exitCode() != 0 ) {
1743     QMessageBox::critical(this, tr("PC-BSD Installer"),
1744          tr("Failed saving config to USB media. Is the device working and formatted MSDOSFS/FAT32?"),
1745          QMessageBox::Ok,
1746          QMessageBox::Ok);
1747
1748  } else {
1749     QMessageBox::information(this, tr("PC-BSD Installer"),
1750          tr("Configuration saved! You may now safely remove the USB media."),
1751          QMessageBox::Ok,
1752          QMessageBox::Ok);
1753  }
1754 
1755}
1756
1757void Installer::slotLoadConfigUSB()
1758{
1759
1760}
Note: See TracBrowser for help on using the repository browser.