source: src-qt4/pc-bootconfig/mainUI.cpp @ c3b1e67

9.2-releasereleng/10.0releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1
Last change on this file since c3b1e67 was c3b1e67, checked in by Ken Moore <ken@…>, 16 months ago

Make sure that the user cannot try to create a copy of the currently running BE

  • Property mode set to 100644
File size: 18.1 KB
Line 
1#include "mainUI.h"
2#include "ui_mainUI.h"
3
4mainUI::mainUI(QWidget *parent) : QMainWindow(parent), ui(new Ui::mainUI){
5         
6  qDebug() << "Starting up pc-bootconfig...";
7  ui->setupUi(this);  //load the mainUI.ui file
8  //Set paths to GRUB files
9  file_GRUBdefaults="/usr/local/etc/default/grub";
10  file_GRUBentries="/boot/grub/custom.cfg";
11  dir_GRUBthemes="/boot/grub/themes/";
12  dir_GRUBfonts="/boot/grub/";
13  //Make sure that backups exist of the GRUB configuration file
14  if(!QFile::exists(file_GRUBdefaults+".old")){ 
15    QString cmd = "cp "+file_GRUBdefaults+" "+file_GRUBdefaults+".old";
16    system(cmd.toUtf8());
17  }
18  //initialize the QProcess
19  proc = new QProcess(this);
20    proc->setProcessChannelMode(QProcess::MergedChannels);
21 
22  //Load the GRUB defaults file into memory
23  G_goodLoad = loadGRUBdefaults(G_themeFile, G_fontFile, G_timer, G_showMenu, G_defaultBE);
24  //Update the list of available boot environments
25  updateBEList();
26  //Update the GRUB configuration values
27  updateGRUBdefaults();
28  //Update the custom GRUB entries
29  updateGRUBentries();
30  //Setup the Signals/slots for change to GRUB values
31  connect(ui->line_GRUBthemefile,SIGNAL(textChanged(QString)),this,SLOT(GRUBchangedefaults()) );
32  connect(ui->line_GRUBfontfile,SIGNAL(textChanged(QString)),this,SLOT(GRUBchangedefaults()) );
33  connect(ui->spin_GRUBtimer,SIGNAL(valueChanged(int)),this,SLOT(GRUBchangedefaults()) );
34  connect(ui->check_GRUBshowcountdown,SIGNAL(stateChanged(int)),this,SLOT(GRUBchangedefaults()) );
35  connect(ui->text_GRUBentries,SIGNAL(textChanged()),this,SLOT(GRUBchangeentries()) );
36}
37
38mainUI::~mainUI(){
39  qDebug() << "Closing down pc-bootconfig normally...";
40  delete proc;
41}
42
43void mainUI::slotSingleInstance(){
44  this->raise();
45  this->show();
46}
47// =====================
48// === PRIVATE FUNCTIONS ===
49// =====================
50//Random utility functions
51int mainUI::getSelectedBE(){
52  if( ui->tree_BE->topLevelItemCount() < 1 ){ return -1; }
53  else{
54    return ui->tree_BE->indexOfTopLevelItem( ui->tree_BE->currentItem() );
55  }
56}
57
58bool mainUI::checkName(QString newname){
59  bool ok = true;
60  for( int i=0; i<ui->tree_BE->topLevelItemCount(); i++){
61    if(ui->tree_BE->topLevelItem(i)->text(0) == newname){ ok=false;  break; }
62  }
63  if(!ok){
64    QMessageBox::warning(this,tr("Invalid Name"), tr("A Boot Environment with that name already exists, please choose a different one."));
65  }
66  return ok;
67}
68
69void mainUI::runLongCMD(QString cmd, QString info){
70       
71  if(info.isEmpty()){ info = tr("Performing Boot Environment Changes. Please Wait."); }
72  //Initialize the Working Message Box
73  QMessageBox wrkmsg(this);
74    wrkmsg.setWindowTitle( tr("Working") );
75    wrkmsg.setText( info );
76    wrkmsg.setStandardButtons(0);
77    wrkmsg.setWindowModality(Qt::WindowModal);
78  //Show the message
79  QCoreApplication::processEvents();
80  wrkmsg.show();
81  QCoreApplication::processEvents();   
82  QCoreApplication::processEvents();   
83  //Run the command
84  system(cmd.toUtf8());
85  //Close the message box
86  wrkmsg.close();
87}
88
89//Boot Environment Management Functions
90void mainUI::beadmActivate(QString name){ 
91        //GRUB OVERRIDES THIS TYPE OF ACTIVATION!!! DO NOT USE!
92        qDebug() << "Activate BE:" << name;
93        QString cmd = "beadm activate "+name;
94        runLongCMD(cmd);
95}
96
97void mainUI::beadmCreate(QString name){ 
98        qDebug() << "Create BE:" << name;
99        QString cmd ="beadm create "+name;
100        runLongCMD(cmd);
101}
102
103void mainUI::beadmCopy(QString name, QString newname){ 
104        qDebug() << "Copy BE:" << name + " -> " + newname;
105        QString cmd ="beadm create -e "+name+" "+newname;
106        runLongCMD(cmd);
107}
108
109void mainUI::beadmRemove(QString name){ 
110        qDebug() << "Remove BE:" << name;
111        QString cmd ="beadm destroy -F "+name;
112        runLongCMD(cmd);
113}
114
115void mainUI::beadmRename(QString name, QString newname){ 
116        qDebug() << "Rename BE:" << name + " -> " + newname;   
117        QString cmd ="beadm rename "+name+" "+newname;
118        runLongCMD(cmd);
119}
120
121void mainUI::beadmMount(QString name, QString mntpt){ 
122        qDebug() << "Mount BE:" << name + " on " + mntpt;
123        QString cmd ="beadm mount "+name+" "+mntpt;
124        runLongCMD(cmd);
125}
126
127void mainUI::beadmUnmount(QString name){ 
128        qDebug() << "Unmount BE:" << name;
129        QString cmd ="beadm umount "+name;
130        runLongCMD(cmd);
131}
132
133QStringList mainUI::beadmList(){
134        //Output format (per line): <name>::<isrunning>::<isactivated>::<mountpoint>::<space>::<datecreated>::<timecreated>
135        qDebug() << "List BE's";
136        proc->start( "beadm list -H" );
137        proc->waitForFinished();
138        QStringList lines = QString(proc->readAllStandardOutput()).split("\n");
139        QStringList output;
140        //Format the output
141        for(int i=0; i<lines.length(); i++){
142          if( lines[i].isEmpty() ){ continue; }
143          QString active = lines[i].section("\t",1,1);
144          QString running, activated;
145          if(active=="NR"){ running="Yes"; activated="Yes"; }
146          else if(active=="N"){ running="Yes"; activated="No"; }
147          else if(active=="R"){ running="No"; activated="Yes"; }
148          else{ running="No"; activated="No"; }
149          QString newline = lines[i].replace("\t","::").replace("::"+active+"::", "::"+running+"::"+activated+"::");
150          output << newline;
151        }
152        return output;
153}
154
155//GRUB Configuration Management Functions
156bool mainUI::loadGRUBdefaults(QString &themefile, QString &fontfile, int &countdown, bool &showcountdown, int &defaultBE){
157  qDebug() << "Load GRUB defaults:" << file_GRUBdefaults;
158  QFile file(file_GRUBdefaults);
159  if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){ return false; }
160  QTextStream in(&file);
161  //initialize outputs
162  themefile.clear(); fontfile.clear();
163  int hcount = 0; //initilization
164  countdown = 0; //initialization
165  showcountdown = false;
166  defaultBE = 0;
167  while( !in.atEnd() ){
168    QString line = in.readLine();
169    QString var = line.section("=",0,0); //variable
170    QString val = line.section("=",1,10); //value
171    if(var == "GRUB_THEME"){ themefile.append(val); }
172    else if(var == "GRUB_FONT"){ fontfile.append(val); }
173    else if(var == "GRUB_HIDDEN_TIMEOUT"){ hcount = val.toInt(); }
174    else if(var == "GRUB_TIMEOUT"){ countdown = val.toInt(); }
175    else if(var == "GRUB_HIDDEN_TIMEOUT_QUIET"){ showcountdown = (val != "true"); }
176    else if(var == "GRUB_DEFAULT"){ defaultBE = val.toInt(); }
177  }
178  file.close();
179  //Check to determine which countdown procedure to use
180  //qDebug() << "GRUB defaults:" << themefile << fontfile << countdown << hcount << showcountdown;
181  if(!showcountdown){ countdown = hcount; } //use the hidden countdown time if hidden
182  return true; 
183}
184
185bool mainUI::saveGRUBdefaults(QString themefile, QString fontfile, int countdown, bool showcountdown, int defaultBE){
186  qDebug() << "Save GRUB defaults:" << file_GRUBdefaults;
187  QFile file(file_GRUBdefaults+".new");
188  if(!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)){ return false; }
189  QTextStream out(&file);
190  if(!themefile.isEmpty()){ out << "GRUB_THEME="+themefile+"\n"; }
191  if(!fontfile.isEmpty()){ out << "GRUB_FONT="+fontfile+"\n"; }
192 
193  if(showcountdown){ 
194    out << "GRUB_HIDDEN_TIMEOUT_QUIET=false\n"; 
195    out << "GRUB_TIMEOUT="+ QString::number(countdown)+"\n";
196  }else{ 
197    out << "GRUB_HIDDEN_TIMEOUT_QUIET=true\n"; 
198    out << "GRUB_HIDDEN_TIMEOUT="+ QString::number(countdown)+"\n";
199  }
200  if(defaultBE >= ui->tree_BE->topLevelItemCount()){ defaultBE = 0; }
201  if(defaultBE >= 0){ out << "GRUB_DEFAULT="+QString::number(defaultBE)+"\n"; }
202  file.close();
203  QString cmd="mv "+file_GRUBdefaults+".new "+file_GRUBdefaults;
204  system(cmd.toUtf8());
205  return true;         
206}
207
208bool mainUI::loadGRUBcustomentries(QStringList &filecontents){
209  qDebug() << "Load GRUB custom entries:" << file_GRUBentries;
210  filecontents.clear();
211  QFile file(file_GRUBentries);
212  if( !file.exists() ){ return true; }
213  if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){ return false; }
214  QTextStream in(&file);
215  while( !in.atEnd() ){
216    QString line = in.readLine();
217    filecontents << line;
218  }
219  file.close();
220  return true;
221}
222
223bool mainUI::saveGRUBcustomentries(QStringList filecontents){
224  qDebug() << "Save GRUB custom entries:" << file_GRUBentries;
225  QFile file(file_GRUBentries+".new");
226  if(!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)){ return false; }
227  QTextStream out(&file);
228  for(int i=0; i<filecontents.length(); i++){
229    out << filecontents[i]+"\n";
230  }
231  file.close();
232  QString cmd="mv "+file_GRUBentries+".new "+file_GRUBentries;
233  system(cmd.toUtf8());
234  return true; 
235}
236       
237// =====================
238// ===== PRIVATE SLOTS =====
239// =====================
240//UI update functions
241void mainUI::updateBEList(){
242  ui->tree_BE->clear();
243  QStringList blist = beadmList();
244  for(int i=0; i<blist.length(); i++){
245    //List all the data <name>::<isrunning>::<isactivated>::<mountpoint>::<space>::<datecreated>::<timecreated>
246    QStringList cols;
247      cols << blist[i].section("::",0,0); // [0] name
248      cols << blist[i].section("::",1,1); // [1] is running
249      // [2] is default for next boot
250      if(G_defaultBE == i){ cols << "Yes"; }
251      else{ cols << "No"; }
252      cols << blist[i].section("::",5,6); // [3] date
253      cols << blist[i].section("::",3,3); // [4] mountpoints
254      cols << blist[i].section("::",4,4); // [5] size
255    //Create the new treewidgetitem
256    QTreeWidgetItem *item = new QTreeWidgetItem(cols);
257         
258    //Add the item to the list
259    ui->tree_BE->addTopLevelItem(item);
260    //qDebug() << "BE Item:" << cols;
261  }
262  //Now re-size the columns appropriately
263  for(int i=0; i<6; i++){ ui->tree_BE->resizeColumnToContents(i); }
264}
265
266void mainUI::updateGRUBdefaults(){
267  if( G_goodLoad ){
268    //Load the info into the UI
269    ui->line_GRUBthemefile->setText(G_themeFile);
270    ui->line_GRUBfontfile->setText(G_fontFile);
271    ui->spin_GRUBtimer->setValue(G_timer);
272    ui->check_GRUBshowcountdown->setChecked(G_showMenu);
273    ui->group_GRUBsettings->setEnabled(true);
274  }else{
275    //Could not read the GRUB defaults file
276    ui->group_GRUBsettings->setEnabled(false);
277  }
278  if( ui->tree_BE->topLevelItemCount() > 1){
279    ui->check_GRUBshowcountdown->setVisible(false);
280    if(!G_showMenu){ 
281      G_showMenu=true; 
282      saveGRUBdefaults(G_themeFile, G_fontFile, G_timer, G_showMenu, G_defaultBE);
283    }
284  }else{
285    ui->check_GRUBshowcountdown->setVisible(true);
286  }
287  //Make sure that the save button is disabled - no changes yet
288  ui->tool_GRUBsavedefaults->setEnabled(false);
289  ui->tool_GRUBresetdefaults->setEnabled(false);
290}
291
292void mainUI::updateGRUBentries(){
293  QStringList entries;
294  if( loadGRUBcustomentries(entries) ){
295    ui->text_GRUBentries->clear();
296    if(!entries.isEmpty()){ ui->text_GRUBentries->setPlainText( entries.join("\n") ); }
297    ui->group_GRUBentries->setEnabled(true);
298  }else{
299    ui->group_GRUBentries->setEnabled(false);
300  }
301  //Make sure that the save button is disabled - no changes yet
302  ui->tool_GRUBsaveentries->setEnabled(false);
303  ui->tool_GRUBresetentries->setEnabled(false);
304}
305
306//UI Buttons - Boot Environments
307void mainUI::on_tool_BEadd_clicked(){
308  //Check to see if we need to reset the GRUB defaults afterwards
309  bool updateGRUB=false;
310  if( ui->tree_BE->topLevelItemCount() == 1){updateGRUB=true;} //moving from 1 to 2
311  //Get the new name from the user
312  bool ok;
313  QString newname = QInputDialog::getText( this, tr("New BE name"), tr("Choose a name for the new boot environment"), QLineEdit::Normal, "", &ok); 
314  if(ok && !newname.isEmpty()){
315    if( checkName(newname) ){
316      if(updateGRUB && !G_showMenu){ 
317        G_showMenu=true; 
318        saveGRUBdefaults(G_themeFile, G_fontFile, G_timer, G_showMenu, G_defaultBE); 
319      }
320      beadmCreate(newname);
321      updateBEList();
322      updateGRUBdefaults();
323    }
324  }     
325}
326
327void mainUI::on_tool_BEactivate_clicked(){
328  int index = getSelectedBE();
329  if(index != -1){
330    //Save the new defaults
331    G_defaultBE = index;
332    bool ok = saveGRUBdefaults(G_themeFile, G_fontFile, G_timer, G_showMenu, G_defaultBE);
333    //Update GRUB config
334    if(ok){ on_action_rebuildGRUBmenu_triggered(); }
335    //Update GUI
336    updateBEList();
337  }
338}
339
340void mainUI::on_tool_BEcp_clicked(){
341 int index = getSelectedBE();
342  if(index != -1){
343    if(ui->tree_BE->topLevelItem(index)->text(1).toLower() == "yes"){
344      QMessageBox::warning(this,tr("Running Boot Environment"),tr("You cannot make a copy of the currently running boot environment!") );
345      return;
346    }
347    bool updateGRUB=false;
348    if( ui->tree_BE->topLevelItemCount() == 1){updateGRUB=true;} //moving from 1 to 2
349    QString name = ui->tree_BE->topLevelItem(index)->text(0);
350    //Get the new name from the user
351    bool ok;
352    QString newname = QInputDialog::getText( this, tr("New BE name"), tr("Choose a name for the new boot environment"), QLineEdit::Normal, name, &ok); 
353    if(ok && !newname.isEmpty()){
354      if( checkName(newname) ){
355        if(updateGRUB && !G_showMenu){ 
356          G_showMenu=true; 
357          saveGRUBdefaults(G_themeFile, G_fontFile, G_timer, G_showMenu, G_defaultBE); 
358        }
359        beadmCopy(name,newname);
360        updateBEList();
361        updateGRUBdefaults();
362      }
363    }
364  }     
365}
366
367void mainUI::on_tool_BEmv_clicked(){
368  int index = getSelectedBE();
369  if(index != -1){
370    if(ui->tree_BE->topLevelItem(index)->text(1).toLower() == "yes"){
371      QMessageBox::warning(this,tr("Running Boot Environment"), tr("You cannot rename a boot environment that you are currently running!") );
372      return;
373    }
374    QString name = ui->tree_BE->topLevelItem(index)->text(0);
375    //Get the new name from the user
376    bool ok;
377    QString newname = QInputDialog::getText( this, tr("New BE name"), tr("Choose a new name for this boot environment"), QLineEdit::Normal, name, &ok); 
378    if(ok && !newname.isEmpty()){
379      if( checkName(newname) ){
380        beadmRename(name,newname);
381        updateBEList();
382      }
383    }
384  }
385}
386
387void mainUI::on_tool_BErem_clicked(){
388  int index = getSelectedBE();
389  if(index != -1){
390    qDebug() << "BE Rem num:" << ui->tree_BE->topLevelItemCount();
391    QString name = ui->tree_BE->topLevelItem(index)->text(0);
392    if(ui->tree_BE->topLevelItemCount() == 1){
393      QMessageBox::warning(this,tr("Single Boot Environment"), tr("You cannot remove your only boot environment!") );
394      return;
395    }
396    if(ui->tree_BE->topLevelItem(index)->text(1).toLower() == "yes"){
397      QMessageBox::warning(this,tr("Running Boot Environment"), tr("You cannot remove a boot environment that you are currently running!") );
398      return;
399    }
400    //Verify removal
401    if( QMessageBox::Yes == QMessageBox::question(this,tr("Verify BE Removal"),tr("Are you sure you want to delete the following boot environment?")+"\n\n"+name, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel) ){
402      if(index <= G_defaultBE){ 
403         if(index < G_defaultBE){ G_defaultBE--; }//make sure we keep the same default BE
404         else{ G_defaultBE=0; } //Removing the default BE
405         saveGRUBdefaults(G_themeFile, G_fontFile, G_timer, G_showMenu, G_defaultBE); 
406      }
407      beadmRemove(name);
408      updateBEList();
409      updateGRUBdefaults();
410    }
411  }     
412}
413
414//UI Buttons - GRUB Config
415void mainUI::on_tool_GRUBsavedefaults_clicked(){
416  //Get all the values
417  G_themeFile = ui->line_GRUBthemefile->text();
418  G_fontFile = ui->line_GRUBfontfile->text();
419  G_timer = ui->spin_GRUBtimer->value();
420  G_showMenu = ui->check_GRUBshowcountdown->isChecked();
421  //always show the countdown if more than one BE
422  if( ui->tree_BE->topLevelItemCount() > 1 ){ G_showMenu=true; }
423       
424  //Save the values to the file
425  bool ok = saveGRUBdefaults(G_themeFile,G_fontFile,G_timer,G_showMenu, G_defaultBE);
426  if(!ok){
427    qDebug() << "Unable to save the GRUB defaults to file:" << file_GRUBdefaults+".new";
428    G_goodLoad = loadGRUBdefaults(G_themeFile, G_fontFile, G_timer, G_showMenu, G_defaultBE); //reset values
429  }else{
430    on_action_rebuildGRUBmenu_triggered();
431    ui->tool_GRUBsavedefaults->setEnabled(false);
432    ui->tool_GRUBresetdefaults->setEnabled(false);   
433  }
434}
435
436void mainUI::on_tool_GRUBresetdefaults_clicked(){
437  G_goodLoad = loadGRUBdefaults(G_themeFile, G_fontFile, G_timer, G_showMenu, G_defaultBE);
438  updateGRUBdefaults();
439}
440
441void mainUI::on_tool_GRUBthemefile_clicked(){
442  QString thfile = QFileDialog::getOpenFileName(this, tr("Select a GRUB Theme File"), dir_GRUBthemes,tr("Theme File (theme.txt)") );
443  if( !thfile.isEmpty() ){
444    ui->line_GRUBthemefile->setText(thfile);
445  }
446}
447
448void mainUI::on_tool_GRUBfontfile_clicked(){
449  QString thfile = QFileDialog::getOpenFileName(this, tr("Select a GRUB Font File"), dir_GRUBfonts,tr("Font File (*.pf2)") );
450  if( !thfile.isEmpty() ){
451    ui->line_GRUBfontfile->setText(thfile);
452  }     
453}
454
455void mainUI::on_tool_GRUBsaveentries_clicked(){
456  //Get the current text
457  QStringList contents = ui->text_GRUBentries->toPlainText().split("\n");
458  bool ok = saveGRUBcustomentries(contents);
459  if(ok){ 
460          ui->tool_GRUBsaveentries->setEnabled(false);
461          ui->tool_GRUBresetentries->setEnabled(false);
462  }else{
463    qDebug() << "Error saving custom grub entries to file:" << file_GRUBentries+".new";
464  }
465}
466
467void mainUI::on_tool_GRUBresetentries_clicked(){
468  updateGRUBentries();
469}
470
471//UI Buttons - other
472void mainUI::on_actionClose_triggered(){
473  this->close();
474}
475
476void mainUI::on_action_rebuildGRUBmenu_triggered(){
477  //Rebuild the GRUB menu
478  QString cmd = "grub-mkconfig -o /boot/grub/grub.cfg";
479  QString info = tr("Rebuilding GRUB menu system. Please wait.");
480  runLongCMD(cmd, info);
481}
482
483void mainUI::on_action_restoreGRUBdefaults_triggered(){
484  QString cmd = "cp "+file_GRUBdefaults+".old "+file_GRUBdefaults;
485  system( cmd.toUtf8() );
486  //Now refresh the UI
487  updateGRUBdefaults(); //Update the display (load the file)
488  on_tool_GRUBsaveentries_clicked(); //make sure the defaults are valid for the number of BE's
489}
490
491void mainUI::GRUBchangedefaults(){
492  ui->tool_GRUBsavedefaults->setEnabled(true);
493  ui->tool_GRUBresetdefaults->setEnabled(true);
494}
495
496void mainUI::GRUBchangeentries(){
497    ui->tool_GRUBsaveentries->setEnabled(true);
498    ui->tool_GRUBresetentries->setEnabled(true);
499}
500
501// ===================
502// ===== PROTECTED =====
503// ===================
504void mainUI::closeEvent(QCloseEvent *event){
505  bool changes = ui->tool_GRUBsavedefaults->isEnabled() || ui->tool_GRUBsaveentries->isEnabled();
506  if(changes){
507    //Verify that they want to continue
508    QMessageBox::StandardButton button = QMessageBox::warning(this, tr("Unsaved Changes"), tr("You currently have unsaved changes in the GRUB configuration. Do you want to quit anyway?"), QMessageBox::Yes | QMessageBox::Cancel,QMessageBox::Cancel);
509    if(button != QMessageBox::Yes){ 
510      //Ignore close request
511      event->ignore();
512      return;
513    }
514  }
515  this->close();
516}
Note: See TracBrowser for help on using the repository browser.