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

releng/10.0.1releng/10.0.2
Last change on this file since ca97cef was ca97cef, checked in by Kris Moore <kris@…>, 6 months ago

Fix the status bar of the installer / first wizard, make it white background with black text so its more readable

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