source: src-qt4/EasyPBI/mainGUI.cpp @ 56d14dd

9.1-release9.2-releasereleng/10.0releng/10.0.1releng/10.0.2releng/10.0.3
Last change on this file since 56d14dd was 56d14dd, checked in by Ken Moore <ken@…>, 17 months ago

Give EasyPBI the ability to set desktop/menu entries as requiring root (using pc-su), add a menu button to re-load the current module, and fix a couple bugs with the xdg entry binary (used to crash if you gave it a path like "bin/app").

  • Property mode set to 100644
File size: 60.4 KB
Line 
1#include "mainGUI.h"
2#include "ui_mainGUI.h"
3#include "modBuild.h"
4#include "backend.h"
5#include "newModuleDialog.h"
6#include "preferencesDialog.h"
7#include "aboutDialog.h"
8#include "portsDialog.h"
9
10MainGUI::MainGUI(QWidget *parent) :
11    QMainWindow(parent),
12    ui(new Ui::MainGUI)
13{
14        // NOTE: "plus"/"minus" icons are set in QtDesigner using the current theme
15        //      since none are available in the Qt Embedded resources
16       
17       //Setup Initial state of GUI objects and connect signal/slots
18       ui->setupUi(this);  //load the mainGUI.ui file
19        // Create the module class as necessary
20        currentModule = new ModBuild();
21        // Create the config class
22        settings = new Config();
23        //Setup the Menu items
24        ui->actionExit->setIcon(Backend::icon("close"));
25        ui->actionRefresh_Module->setIcon(Backend::icon("refresh"));
26        //Setup the pushbutton menu lists
27        menu_elOpts.addAction("binary");
28        menu_elOpts.addAction("linux");
29        menu_elOpts.addAction("keep");
30        menu_elOpts.addAction("replace");
31        menu_elOpts.addAction("nocrash");
32        //Setup Toolbar
33        ui->actionNew_Module->setIcon(Backend::icon("new"));
34        ui->actionLoad_Module->setIcon(Backend::icon("load"));
35        line_module = new QLineEdit(this);
36        line_module->setPlaceholderText(tr("No Module Loaded"));
37        line_module->setReadOnly(TRUE);
38        line_module->setFocusPolicy(Qt::NoFocus);
39        ui->toolBar->addWidget(line_module);
40        ui->toolBar->addSeparator();
41        radio_module_port = new QRadioButton(tr("FreeBSD Port"),this);
42        radio_module_port->setEnabled(FALSE);
43        ui->toolBar->addWidget(radio_module_port);
44        radio_module_local = new QRadioButton(tr("Local Sources"),this);
45        radio_module_local->setEnabled(FALSE);
46        ui->toolBar->addWidget(radio_module_local);
47        //Setup Module Editor
48        connect(ui->tabWidget, SIGNAL(currentChanged(int)),this,SLOT(slotModTabChanged(int)) ); //setup to refresh each tab once it is selected
49        // -- pbi.conf tab --
50        ui->push_change_progdir->setIcon(Backend::icon("load"));
51        ui->push_change_makeport->setIcon(Backend::icon("file"));
52        ui->push_addmakeopt->setIcon(Backend::icon("left"));
53        ui->push_addmakeopt->setMenu(&menu_addOpt);
54        connect(&menu_addOpt,SIGNAL(triggered(QAction*)),this,SLOT(slotAddMakeOption(QAction*)) );
55        ui->push_config_save->setIcon(Backend::icon("save"));
56        // -- resources tab --
57        ui->push_resources_savewrapper->setIcon(Backend::icon("save"));
58        connect(ui->listw_resources, SIGNAL(itemSelectionChanged()), this, SLOT(slotResourceChanged()) );
59        connect(ui->push_resources_savewrapper, SIGNAL(clicked()), this, SLOT(slotResourceScriptSaved()) );
60        // -- XDG entries tab --
61        connect(ui->radio_xdg_desktop,SIGNAL(clicked()),this,SLOT(slotXdgTypeChanged()) );
62        connect(ui->radio_xdg_menu,SIGNAL(clicked()),this,SLOT(slotXdgTypeChanged()) );
63        connect(ui->list_xdg_files,SIGNAL(itemSelectionChanged()), this, SLOT(slotXdgFileChanged()) );
64        ui->push_xdg_refresh->setIcon(Backend::icon("refresh"));
65        connect(ui->push_xdg_refresh, SIGNAL(clicked()), this, SLOT(slotXdgTypeChanged()) );
66        ui->push_xdg_exec->setIcon(Backend::icon("left"));
67        ui->push_xdg_exec->setMenu(&menu_bins);
68        connect(&menu_bins, SIGNAL(triggered(QAction*)), this, SLOT(slotAddBin(QAction*)) );
69        ui->push_xdg_savechanges->setIcon(Backend::icon("save"));
70        ui->push_xdg_menu->setIcon(Backend::icon("left"));
71        ui->push_xdg_menu->setMenu(&menu_validMenuCats);
72        connect(&menu_validMenuCats,SIGNAL(triggered(QAction*)),this,SLOT(slotAddMenuCat(QAction*)) );
73        ui->push_xdg_clearentry->setIcon(Backend::icon("file"));
74       
75        // -- Scripts tab --
76        ui->push_scripts_save->setIcon(Backend::icon("save"));
77        ui->push_scripts_create->setIcon(Backend::icon("new"));
78        ui->list_scripts_file->addItems(QStringList() << " ---"+tr("Installation Scripts")+"---" << "pre-portmake.sh" << "post-portmake.sh" << "pre-pbicreate.sh" << "pre-install.sh" << "post-install.sh" << "pre-remove.sh" );
79        connect(ui->list_scripts_file, SIGNAL(currentIndexChanged(int)), this, SLOT(slotScriptChanged(int)) );
80        // -- External links tab --
81        ui->push_el_file->setIcon(Backend::icon("left"));
82        ui->push_el_file->setMenu(&menu_el_bins);
83        connect(&menu_el_bins,SIGNAL(triggered(QAction*)),this,SLOT(slotELSetFile(QAction*)) );
84        ui->push_el_filetype->setIcon(Backend::icon("left"));
85        ui->push_el_filetype->setMenu(&menu_elOpts);
86        connect(&menu_elOpts,SIGNAL(triggered(QAction*)),this,SLOT(slotELSetType(QAction*)) );
87        //Setup PBI Builder
88        ui->push_build_stop->setIcon(Backend::icon("close"));
89        ui->push_build_save->setIcon(Backend::icon("save"));
90       
91      SetupDefaults(); //load program defaults
92      refreshGUI("all"); //make items visible/invisible as necessary
93     
94}
95
96MainGUI::~MainGUI()
97{
98  qDebug() << "Shutting down EasyPBI normally";
99}
100
101void MainGUI::slotSingleInstance(){
102  this->showNormal();
103  this->activateWindow();
104  this->raise();
105}
106
107void MainGUI::SetupDefaults(){
108    qDebug() << "Starting up EasyPBI (version "+settings->value("version")+")"; 
109    //Make sure that the program is not being started with root permissions
110    QString id = QProcessEnvironment::systemEnvironment().toStringList().filter("HOME=").join(" ").simplified();
111    if( id.contains("root") ){
112      qDebug() << "EasyPBI should not be run with root permissions! exiting.....";
113      exit(1);
114    }
115
116    //Load the current configuration settings
117    settings->readMachineArch(); //set the 64-bit flag as appropriate
118    //Scan for the external utilities needed to build PBI's
119    settings->scanForExternalUtilities();
120    //Load Preferences file if possible
121    settings->loadSettingsFile();
122    //create the EasyPBI directory structure if needed
123    if( !settings->checkDirectoryStructure() ){
124        QMessageBox::warning(this,tr("Permissions Error"), tr("There was an error trying to create the local EasyPBI directory structure. Please check the permissions for your home directory and restart EasyPBI.") );
125        exit(1);
126    }
127    //Pop up a warning box if some external resources are not available
128    bool chkOK = (settings->check("isMakeportAvailable") && settings->check("iscreateAvailable") && settings->check("isSUavailable") );
129    if( !chkOK ){
130        QMessageBox::warning(this, tr("Resources Unavailable"), tr("Some external resources could not be found, so the EasyPBI services that use these resources have been deactivated.")+"\n"+tr("Please open up the EasyPBI preferences to correct this deficiency.") );
131    }
132    //Pop up a warning about a missing ports tree
133    if( !settings->check("isPortsAvailable") ){
134        QMessageBox::warning(this, tr("FreeBSD Ports Missing"), tr("The FreeBSD ports tree is missing from your system.")+"\n"+tr("Please open up the appropriate EasyPBI menu option to correct this deficiency.") );
135    }
136    //Set a couple more internal flags
137    PBI_BUILDING_NOW.clear();
138    PBI_BUILD_TERMINATED=FALSE;
139}
140
141bool MainGUI::isValidPort(QString pPath){
142  bool ok = FALSE;
143  if( QFile::exists(pPath) && QFile::exists(pPath+"/Makefile") && QFile::exists(pPath+"/distinfo") ){
144    ok = TRUE;
145  }
146  return ok;
147}
148
149void MainGUI::refreshGUI(QString item){
150  //Enable/disable the interface appropriately
151 
152  //Stupid check to make sure that a module is actually loaded
153  if( currentModule->path().isEmpty() ){ 
154    ui->actionPackage_Module->setEnabled(FALSE);
155    ui->actionRefresh_Module->setEnabled(FALSE);
156    if(PBI_BUILDING_NOW.isEmpty() ){ui->toolBox->setEnabled(FALSE); return; }
157    else{ 
158      ui->toolBox->setItemEnabled(0,FALSE);
159      ui->toolBox->setItemEnabled(1,TRUE);
160      ui->toolBox->setCurrentIndex(1); 
161      item="pbibuild";
162    }
163  }else{ 
164    ui->toolBox->setEnabled(TRUE); 
165    ui->actionPackage_Module->setEnabled(TRUE); 
166    ui->actionRefresh_Module->setEnabled(TRUE);
167  }
168  //Figure out the type of module that is loaded
169  bool isport = radio_module_port->isChecked();
170  //See if we should refresh everything (default) 
171  bool doall = ( (item == "all") || item.isEmpty() );
172  bool doeditor = (item == "editor"); //also add a flag to just refresh the editor
173  //Refresh the desired tab(s)
174  // ------PBI.CONF------
175  if( doall || doeditor || (item == "pbiconf")){
176    if(isport){
177        ui->line_progversion->setVisible(FALSE); ui->label_progversion->setVisible(FALSE);
178        ui->line_progdir->setVisible(FALSE); ui->push_change_progdir->setVisible(FALSE); ui->label_progdir->setVisible(FALSE);
179        ui->line_makeport->setVisible(TRUE); ui->push_change_makeport->setVisible(TRUE); ui->label_makeport->setVisible(TRUE);
180        ui->edit_makeopts->setVisible(TRUE); ui->push_addmakeopt->setVisible(TRUE); ui->label_makeopts->setVisible(TRUE);
181        ui->list_portbefore->setVisible(TRUE); ui->push_addportbefore->setVisible(TRUE); ui->push_rmportbefore->setVisible(TRUE);ui->label_portbefore->setVisible(TRUE);
182        ui->list_portafter->setVisible(TRUE); ui->push_addportafter->setVisible(TRUE); ui->push_rmportafter->setVisible(TRUE); ui->label_portafter->setVisible(TRUE);
183    }else{
184        ui->line_progversion->setVisible(TRUE); ui->label_progversion->setVisible(TRUE);
185        ui->line_progdir->setVisible(TRUE); ui->push_change_progdir->setVisible(TRUE); ui->label_progdir->setVisible(TRUE);
186        ui->line_makeport->setVisible(FALSE); ui->push_change_makeport->setVisible(FALSE); ui->label_makeport->setVisible(FALSE);
187        ui->edit_makeopts->setVisible(FALSE); ui->push_addmakeopt->setVisible(FALSE); ui->label_makeopts->setVisible(FALSE);
188        ui->list_portbefore->setVisible(FALSE); ui->push_addportbefore->setVisible(FALSE); ui->push_rmportbefore->setVisible(FALSE);ui->label_portbefore->setVisible(FALSE);
189        ui->list_portafter->setVisible(FALSE); ui->push_addportafter->setVisible(FALSE); ui->push_rmportafter->setVisible(FALSE); ui->label_portafter->setVisible(FALSE);
190    }
191    //Display the variables from the currentModule structure
192    // -- check boxes
193    QString chk = currentModule->readValue("requiresroot").toLower();
194    if( (chk=="true") || (chk=="yes") ){ ui->check_requiresroot->setChecked(TRUE); }
195    else{ ui->check_requiresroot->setChecked(FALSE); }
196    // -- line edits
197    ui->line_progname->setText(currentModule->readValue("progname"));
198    ui->line_progversion->setText(currentModule->readValue("progversion"));
199    ui->line_progweb->setText(currentModule->readValue("progweb"));
200    ui->line_progauthor->setText(currentModule->readValue("progauthor"));
201    ui->line_progdir->setText(currentModule->readValue("packagedir"));
202    ui->line_makeport->setText(currentModule->readValue("makeport"));
203    ui->edit_makeopts->setPlainText(currentModule->readValue("makeoptions"));
204    // -- combo boxes (lists)
205    ui->list_portbefore->clear(); ui->list_portafter->clear(); ui->list_progicon->clear();
206    ui->list_portbefore->addItems( currentModule->readValue("makeportbefore").split(" ") );
207    ui->list_portafter->addItems( currentModule->readValue("makeportafter").split(" ") );
208    QStringList icons = currentModule->currentIcons;
209    if(icons.length() > 0){
210      for(int i=0; i<icons.length(); i++){
211        ui->list_progicon->addItem(QIcon(currentModule->path()+"/resources/"+icons[i]),icons[i]);
212      }     
213      int cicon = icons.indexOf(currentModule->readValue("progicon"));
214      if( cicon == -1 ){ 
215              ui->list_progicon->addItem(currentModule->readValue("progicon")); 
216              cicon = icons.indexOf(currentModule->readValue("progicon"));
217      }
218      ui->list_progicon->setCurrentIndex(cicon);
219    }else{
220      ui->list_progicon->addItem(currentModule->readValue("progicon"));
221    }
222    menu_addOpt.clear();
223    QStringList opts = currentModule->readValue("portoptions").split(" ",QString::SkipEmptyParts);
224    if(!opts.isEmpty()){
225      for(int i=0; i<opts.length(); i++){
226        menu_addOpt.addAction(opts[i]);
227      }
228    }
229  }
230  // -----RESOURCES--------
231  if( doall || doeditor || (item == "resources")){
232    //Get the all the current files in the resources category and add them to the list
233    QStringList rs = currentModule->filesAvailable("resources");
234    //disconnect the signal/slot connection to make sure we don't get an extra phantom refresh
235    disconnect(ui->listw_resources, SIGNAL(itemSelectionChanged()), this, SLOT(slotResourceChanged()) );
236    //Update the Widget
237    ui->listw_resources->clear();
238    ui->listw_resources->addItems(rs);
239    //re-connect the signal/slot
240    connect(ui->listw_resources, SIGNAL(itemSelectionChanged()), this, SLOT(slotResourceChanged()) );
241    //Load the file into the viewers
242    slotResourceChanged();
243  }
244  //------XDG------
245  if( doall || doeditor || (item == "xdg")){
246    slotXdgTypeChanged();
247  }
248  //------SCRIPTS-----
249  if( doall || doeditor || (item == "scripts")){
250    //Update the list of available scripts and determine if one needs to be read
251    bool loadScript = FALSE;
252    QString path = currentModule->path()+"/scripts/";
253    int currentIndex = ui->list_scripts_file->currentIndex();
254    for(int i=1; i< ui->list_scripts_file->count(); i++){ //Skip the first item (is nothing)
255      if( QFile::exists( path+ui->list_scripts_file->itemText(i) ) ){
256        if(i == currentIndex){ loadScript = TRUE; }
257        ui->list_scripts_file->setItemIcon(i,Backend::icon("file"));
258      }else{
259        ui->list_scripts_file->setItemIcon(i,Backend::icon("close"));
260      }
261    }
262    //Update the GUI appropriately
263    if(loadScript){
264      //Read and display the script
265      QStringList contents = ModBuild::readFile(path+ui->list_scripts_file->currentText());
266      ui->text_scripts_edit->setPlainText(contents.join("\n"));
267      //Setup display items
268      ui->push_scripts_create->setVisible(FALSE);
269      ui->push_scripts_remove->setVisible(TRUE);
270      ui->push_scripts_save->setVisible(TRUE);
271      ui->text_scripts_edit->setVisible(TRUE);
272    }else{
273      //Setup display items
274      ui->push_scripts_create->setVisible(TRUE);
275      ui->push_scripts_remove->setVisible(FALSE);
276      ui->push_scripts_save->setVisible(FALSE);
277      ui->text_scripts_edit->setVisible(FALSE);
278    }
279    if(currentIndex == 0){ ui->push_scripts_create->setVisible(FALSE); }
280   
281  }
282  //------EXTERNAL-LINKS------
283  if( doall || doeditor || (item == "external-links")){
284    //nothing to make visible/invisible here
285    //Load the external-links file
286    ui->tree_el_view->clear();
287    QStringList cLinks = currentModule->externalLinks();
288    QStringList labels; labels << tr("File") << tr("Link To") << tr("File Type");
289    for( int i=0; i<cLinks.length(); i++ ){
290      QStringList link = cLinks[i].split("\t");
291      ui->tree_el_view->addTopLevelItem(new QTreeWidgetItem(link));
292    }
293    //Clear the input boxes
294    ui->line_el_file->clear();
295    ui->line_el_linkto->clear();
296    ui->line_el_filetype->clear();
297    //update the available binaries
298    menu_el_bins.clear();
299    QStringList cBins = currentModule->currentBins;
300    if(!cBins.isEmpty()){
301      for(int i=0; i<cBins.length(); i++){
302        menu_el_bins.addAction(cBins[i]);
303      } 
304    }
305  }
306  //------FREENAS PLUGINS-------
307  if( doall || doeditor || (item == "freenas")){
308    //nothing to make visible/invisible here
309  }
310  //------PBI BUILDER--------
311  if( doall || (item == "pbibuild")){
312    if(PBI_BUILDING_NOW.isEmpty()){
313      //only change things if there is nothing building at the moment
314      if(ui->text_build_log->toPlainText().isEmpty()){ ui->push_build_save->setEnabled(FALSE); }
315      else{ ui->push_build_save->setEnabled(TRUE); }
316    }
317    ui->push_build_start->setFocus();//make sure the focus starts out on the build button
318  }
319  //------OVERALL SETTINGS------
320  if( doall || doeditor ){
321    //Enable/disable the buttons that require the FreeBSD ports tree
322    if( settings->check("isportsavailable") ){
323      ui->push_change_makeport->setEnabled(TRUE);
324      ui->push_addportbefore->setEnabled(TRUE);
325      ui->push_addportafter->setEnabled(TRUE);
326    }else{
327      ui->push_change_makeport->setEnabled(FALSE);
328      ui->push_addportbefore->setEnabled(FALSE);
329      ui->push_addportafter->setEnabled(FALSE);
330    }
331    //Check for a 64-bit system to enable the 32-bit build option
332    if( settings->check("is64bit") && !currentModule->isLocalPBI ){ ui->check_build_32->setVisible(TRUE); }
333    else{ ui->check_build_32->setVisible(FALSE); ui->check_build_32->setChecked(FALSE); }
334    //Disable tabs that are not used when bulding local PBI's
335    if(currentModule->isLocalPBI){
336        ui->tabWidget->setTabEnabled(5,FALSE);
337    }else{
338        ui->tabWidget->setTabEnabled(5,TRUE);
339    }
340    //Set the default focus on the "load" button
341    this->setFocus();
342  }
343}
344/*----------------------------------
345   MENU OPTIONS
346  -----------------------------------
347*/
348void MainGUI::on_actionGet_Ports_triggered(){
349  portsDialog dlg(this,settings->value("progdir")+"/ports",settings->value("su_cmd") );
350  dlg.exec();
351}
352
353void MainGUI::on_actionExit_triggered(){
354  qDebug() << "Close EasyPBI requested";
355  this->close();
356}
357
358void MainGUI::on_actionPreferences_triggered(){
359  //Open up the preferences dialog
360  PreferencesDialog dlg(this);
361  //make the dialog modal and wait for it to close
362  dlg.exec(); 
363  //Now reload the saved settings
364  settings->loadSettingsFile();
365  //Now refresh the GUI
366  refreshGUI("all");
367}
368void MainGUI::on_actionPackage_Module_triggered(){
369   currentModule->compressModule();
370   QMessageBox::information(this,tr("Success"),tr("A copy of the current module has been successfully packaged  within the module directory.") );
371
372}
373
374void MainGUI::on_actionRefresh_Module_triggered(){
375  QString modSel = currentModule->path(); //re-load the current module
376  bool ok = currentModule->loadModule(modSel); 
377  if(ok){ 
378    qDebug() << "Loaded module:"<<modSel;         
379    line_module->setText(modSel.replace(QDir::homePath(),"~")); 
380    if(currentModule->isLocalPBI){ radio_module_local->toggle(); }
381    else{ 
382      radio_module_port->toggle(); //Port PBI
383      if( settings->check("isportsavailable") ){ 
384        currentModule->readPortInformation(settings->value("portsdir")+"/"+currentModule->readValue("makeport"));
385      }
386    }
387    refreshGUI("all");
388  }
389}
390
391void MainGUI::on_actionFreeBSD_Ports_triggered(){
392  QString port;
393  if(!line_module->text().isEmpty()){
394        //Get the currently selected port
395        port = currentModule->readValue("makeport");
396  }
397  QString target_url = "http://www.freshports.org/" + port;
398  qDebug() << "Opening URL:" << target_url; 
399  target_url.prepend("xdg-open ");
400  system(target_url.toUtf8()); 
401}
402
403void MainGUI::on_actionPBI_Modules_triggered(){
404  //Open the PC-BSD wiki to the module builders guide
405   QString target_url = "http://wiki.pcbsd.org/index.php/PBI_Module_Builder_Guide";
406   qDebug() << "Opening URL:" << target_url; 
407   target_url.prepend("xdg-open ");
408   system(target_url.toUtf8());
409}
410
411void MainGUI::on_actionAbout_EasyPBI_triggered(){
412  aboutDialog dlg(this,settings->value("version"));
413  dlg.exec();
414}
415
416
417/*----------------------------------
418   TOOLBAR OPTIONS
419  -----------------------------------
420*/
421void MainGUI::on_actionNew_Module_triggered(){
422  qDebug() << "New Module triggered";
423  //Create and run the new dialog
424  NewModuleDialog* dlg = new NewModuleDialog(this, settings->value("portsdir"));
425  dlg->setDefaultIconFile(settings->value("defaulticon"));
426  dlg->exec();
427  //Determine if the action was cancelled
428  if( dlg->isAccepted ){
429    //Now create the new module
430    QString modPath, modType, modBase, oldIconPath;
431    modType = dlg->moduleType;
432    modBase = dlg->moduleData;
433    oldIconPath = dlg->moduleIcon;
434    modPath = settings->value("moduledir")+"/"+modBase.section("/",-1).toLower();
435          //modPath ->full path, modType->"local"or "port", modBase->makeport or packagedir
436    bool ok = currentModule->createNewModule(modPath,modType,modBase);
437    if(!ok){
438      QMessageBox::warning(this,tr("EasyPBI: Permissions Error"), tr("Could not create PBI module. Please check the directory permissions and try again."));
439    }else{
440      //MODULE CREATED, NOW FILL IT APPROPRIATELY
441      //Icon
442      currentModule->addResource(FALSE, oldIconPath); //copy the icon file into the module
443      currentModule->writeValue("progicon", oldIconPath.section("/",-1) );
444      //Load Port info if appropriate
445      if(currentModule->isPortPBI){
446        radio_module_port->toggle();
447        //Use the port info if possible
448        if( settings->check("isportsAvailable") ){
449          currentModule->readPortInformation(settings->value("portsdir")+"/"+modBase);
450          //Now save the detected information into the module
451          currentModule->writeValue("progname", currentModule->readValue("portname"));
452          currentModule->writeValue("progweb", currentModule->readValue("portwebsite"));
453          currentModule->writeValue("progauthor", currentModule->readValue("portauthor"));
454          currentModule->writePBIconf();
455        }
456      }else if(currentModule->isLocalPBI){
457        radio_module_local->toggle();
458             
459      }
460      //Now let the UI reflect the new module
461      line_module->setText( currentModule->path().replace(QDir::homePath(),"~") );     
462    }
463  }
464  //Refresh the UI
465  refreshGUI("all");
466  delete dlg;
467}
468
469void MainGUI::on_actionLoad_Module_triggered(){
470  QString modSel = QFileDialog::getExistingDirectory(this, tr("Select Module"), settings->value("moduledir"));
471  if(modSel.isEmpty()){return;} //action cancelled or closed
472  bool ok = currentModule->loadModule(modSel);
473  if(ok){ 
474    qDebug() << "Loaded module:"<<modSel;         
475    line_module->setText(modSel.replace(QDir::homePath(),"~")); 
476    if(currentModule->isLocalPBI){ radio_module_local->toggle(); }
477    else{ 
478      radio_module_port->toggle(); //Port PBI
479      if( settings->check("isportsavailable") ){ 
480        currentModule->readPortInformation(settings->value("portsdir")+"/"+currentModule->readValue("makeport"));
481      }
482    }
483    refreshGUI("all");
484  }
485}
486
487/*----------------------------------
488   MODULE EDITOR OPTIONS
489  -----------------------------------
490*/
491void MainGUI::slotModTabChanged(int newtab){
492  switch(newtab){
493    case 0:
494            refreshGUI("pbiconf"); break;
495    case 1:
496            refreshGUI("resources"); break;
497    case 2:
498            refreshGUI("xdg"); break;
499    case 3:
500            refreshGUI("scripts"); break;
501    case 4:
502            refreshGUI("external-links"); break;
503    case 5:
504            refreshGUI("freenas"); break;
505    default:
506            refreshGUI("editor"); break; //do all the module editor tabs
507  }       
508}
509
510/*----------------------------------
511   PBI.CONF OPTIONS
512  -----------------------------------
513*/
514void MainGUI::on_push_change_makeport_clicked(){
515  if( !settings->check("isportsavailable") ){
516    //No ports tree available
517    QMessageBox::warning(this,tr("EasyPBI: No FreeBSD Ports"), tr("The FreeBSD Ports tree could not be found on your system. You may fetch the ports tree through the EasyPBI menu or manually set the path to the port tree in the EasyPBI preferences if it is installed in a non-standard location."));
518    return;
519  }
520  //Prompt for a new port
521  QString portSel = QFileDialog::getExistingDirectory(this, tr("Select Port"), settings->value("portsdir"));
522  if(portSel.isEmpty()){return;} //action cancelled or closed   
523  //Check if the port is valid
524  if( !isValidPort(portSel) ){
525    QMessageBox::warning(this,tr("EasyPBI: Invalid Port"), tr("The directory selected is not a valid FreeBSD port. Please select a port directory which contains the appropriate Makefile and distinfo."));
526    return;
527  }
528  //Save the port info to the GUI
529  ui->line_makeport->setText(portSel.remove(settings->value("portsdir")+"/"));
530}
531
532void MainGUI::on_push_change_progdir_clicked(){
533  //Prompt for a new directory
534  QString dirSel = QFileDialog::getExistingDirectory(this, tr("Select Package Directory"), QDir::homePath());
535  if(dirSel.isEmpty()){return;} //action cancelled or closed   
536  //Save the port info to the GUI
537  ui->line_progdir->setText(dirSel);
538}
539
540void MainGUI::slotAddMakeOption(QAction* act){
541  qDebug() << "Trying to add build option:" << act->text();
542  QString opt = act->text();
543  if(opt.isEmpty() ){ return; } //Do nothing if nothing selected
544  //Check whther the option is set or unset
545  QString typ = opt.section("_",0,0,QString::SectionSkipEmpty).toLower(); //get the type
546  opt = opt.section("_",1,50,QString::SectionSkipEmpty); //trim off the type of setting
547  QString chk = currentModule->readValue("makeport").section("/",-1);
548  bool isSet;
549  if(typ == "with"){chk.append("_SET"); isSet=TRUE;}
550  else if(typ=="without"){chk.append("_UNSET"); isSet=FALSE;}
551  else{ qDebug() << "Error: Unknown option type:"<<typ<<"option:"<<opt; return; }
552  //Now read the current option settings
553  QStringList curr = ui->edit_makeopts->toPlainText().split("\n"); //split according to lines
554  bool found = FALSE;
555  for(int i=0; i<curr.length(); i++){
556    if(curr[i].contains(chk) ){ //look for optionsNG framework
557      found = TRUE;         
558      QStringList cOpts = curr[i].split(" ",QString::SkipEmptyParts);
559      if( !cOpts.contains(opt) ){
560        //Not found, add it to the end of the list
561        cOpts << opt;
562        curr[i] = cOpts.join(" ");
563      }
564    }else if(curr[i].contains(opt)){ //look for legacy options framework
565      QStringList cOpts = curr[i].split(" ",QString::SkipEmptyParts);
566      int index = cOpts.indexOf(opt);
567      if(index != -1){ //option currently set somehow
568        found = TRUE; 
569        if(isSet){ //option should be set
570          if( cOpts[index].contains("WITH_"+opt) ){} //Already set
571          else if( cOpts[index].contains("WITHOUT_"+opt) ){ cOpts[index] = "WITH_"+opt+"=true"; }
572          else if( curr[i].contains(chk.replace("_SET","_UNSET")) ){ cOpts.removeAt(index); found=FALSE;} //Remove the inverse option if it is set
573        }else{ //options should be unset
574          if( cOpts[index].contains("WITHOUT_"+opt) ){} //Already set
575          else if( cOpts[index].contains("WITH_"+opt) ){ cOpts[index] = "WITHOUT_"+opt+"=true"; }
576          else if( curr[i].contains(chk.replace("_UNSET","_SET")) ){ cOpts.removeAt(index); found=FALSE;} //Remove the inverse option if it is set
577        }
578        curr[i] = cOpts.join(" "); //put the line back together
579      }
580    } //end checking different options frameworks
581  } // end loop over lines
582  if(!found){
583    //Append the option to the end on a new line
584    curr << chk+"= "+opt;
585  }
586  //Now put the new options list back onto the GUI
587  ui->edit_makeopts->setPlainText(curr.join("\n"));
588}
589
590void MainGUI::on_push_addportbefore_clicked(){
591  if( !settings->check("isportsavailable") ){
592    //No ports tree available
593    QMessageBox::warning(this,tr("EasyPBI: No FreeBSD Ports"), tr("The FreeBSD Ports tree could not be found on your system. You may fetch the ports tree through the EasyPBI menu or manually set the path to the port tree in the EasyPBI preferences if it is installed in a non-standard location."));
594  }
595  //Prompt for a new port
596  QString portSel = QFileDialog::getExistingDirectory(this, tr("Select Port"), settings->value("portsdir"));
597  if(portSel.isEmpty()){return;} //action cancelled or closed   
598  //Check if the port is valid
599  if( !isValidPort(portSel) ){
600    QMessageBox::warning(this,tr("EasyPBI: Invalid Port"), tr("The directory selected is not a valid FreeBSD port. Please select a port directory which contains the appropriate Makefile and distinfo files."));
601    return;
602  }
603  //Save the port info to the GUI
604  if(ui->list_portbefore->count() == 1 && ui->list_portbefore->currentText().isEmpty() ){ ui->list_portbefore->clear(); }
605  ui->list_portbefore->addItem(portSel.remove(settings->value("portsdir")+"/"));
606}
607
608void MainGUI::on_push_rmportbefore_clicked(){
609  int index = ui->list_portbefore->currentIndex();
610  if(index != -1){
611    ui->list_portbefore->removeItem(index);
612  }
613}
614
615void MainGUI::on_push_addportafter_clicked(){
616  if( !settings->check("isportsavailable") ){
617    //No ports tree available
618    QMessageBox::warning(this,tr("EasyPBI: No FreeBSD Ports"), tr("The FreeBSD Ports tree could not be found on your system. You may fetch the ports tree through the EasyPBI menu or manually set the path to the port tree in the EasyPBI preferences if it is installed in a non-standard location."));
619  }
620  //Prompt for a new port
621  QString portSel = QFileDialog::getExistingDirectory(this, tr("Select Port"), settings->value("portsdir"));
622  if(portSel.isEmpty()){return;} //action cancelled or closed   
623  //Check if the port is valid
624  if( !isValidPort(portSel) ){
625    QMessageBox::warning(this,tr("EasyPBI: Invalid Port"), tr("The directory selected is not a valid FreeBSD port. Please select a port directory which contains the appropriate Makefile and distinfo files."));
626    return;
627  }
628  //Save the port info to the GUI
629  if(ui->list_portafter->count() == 1 && ui->list_portafter->currentText().isEmpty() ){ ui->list_portafter->clear(); }
630  ui->list_portafter->addItem(portSel.remove(settings->value("portsdir")+"/"));
631}
632
633void MainGUI::on_push_rmportafter_clicked(){
634  int index = ui->list_portafter->currentIndex();
635  if(index != -1){
636    ui->list_portafter->removeItem(index);
637  }
638}
639
640void MainGUI::on_push_config_save_clicked(){
641  //Save the current settings to the backend structures
642    //global settings for all modules
643    currentModule->writeValue("progname",ui->line_progname->text());
644    currentModule->writeValue("progweb",ui->line_progweb->text());
645    currentModule->writeValue("progauthor",ui->line_progauthor->text());
646    currentModule->writeValue("progicon",ui->list_progicon->currentText());
647    if(ui->check_requiresroot->isChecked()){ currentModule->writeValue("requiresroot", "true"); }
648    else{ currentModule->writeValue("requiresroot","false"); }
649    //Module-dependant settings
650    bool newport = FALSE;
651    if( radio_module_port->isChecked() ){ //FreeBSD port module
652        if(currentModule->readValue("makeport") != ui->line_makeport->text()){ newport=TRUE; }
653        currentModule->writeValue("makeport",ui->line_makeport->text());
654        currentModule->writeValue("makeoptions",ui->edit_makeopts->toPlainText());
655        QString tmp;
656        for(int i=0; i < ui->list_portbefore->count(); i++){
657          tmp.append(" "+ui->list_portbefore->itemText(i) );
658        }
659        currentModule->writeValue("makeportbefore",tmp.simplified());
660        tmp.clear();
661        for(int i=0; i < ui->list_portafter->count(); i++){
662          tmp.append(" "+ui->list_portafter->itemText(i) );
663        }
664        currentModule->writeValue("makeportafter",tmp.simplified());
665       
666    }else{ //local sources module
667        currentModule->writeValue("packagedir",ui->line_progdir->text());
668        currentModule->writeValue("progversion",ui->line_progversion->text());
669    }
670  //save the new settings to pbi.conf
671  bool ok = currentModule->writePBIconf();
672  if(!ok){
673    //Display a warning that the file could not be saved
674    qDebug() << "Error: pbi.conf could not be written:" << currentModule->path()+"/pbi.conf";
675    QMessageBox::warning(this,tr("EasyPBI Error"), tr("The PBI configuration file could not be saved. Please check your file permissions before trying again."));
676  }else if(newport){
677    //Refresh the port information if the main port changed
678    currentModule->readPortInformation(settings->value("portsdir")+"/"+ui->line_makeport->text());
679    refreshGUI("pbiconf");
680  }
681}
682/*------------------------------------------------
683   RESOURCE EDITOR OPTIONS
684  -------------------------------------------------
685*/
686void MainGUI::slotResourceChanged(){
687  //Get the current file selected
688  QString cfile;
689  if(ui->listw_resources->currentRow() != -1){ cfile = ui->listw_resources->currentItem()->text(); }
690  if(cfile.isEmpty()){ //no item selected
691    ui->push_resources_savewrapper->setVisible(FALSE);
692    ui->text_resources_script->setVisible(FALSE);
693    ui->label_resources_description->setVisible(FALSE);
694    ui->label_resources_icon->setVisible(FALSE);
695         
696  }else{ //item selected
697    QString path = currentModule->path() + "/resources/";
698    if( cfile.endsWith(".png") || cfile.endsWith(".jpg") ){
699      //Image file, show full size
700      QPixmap img(path+cfile);
701      ui->label_resources_icon->setPixmap(img);
702      ui->label_resources_icon->setVisible(TRUE);
703      QString desc = QString::number(img.width()) +" x "+QString::number(img.height())+" "+cfile.section(".",-1).toUpper();
704      ui->label_resources_description->setText(desc);
705      ui->label_resources_description->setVisible(TRUE);
706      //hide the other widgets
707      ui->push_resources_savewrapper->setVisible(FALSE);
708      ui->text_resources_script->setVisible(FALSE);
709    }else{
710      ui->push_resources_savewrapper->setVisible(TRUE);
711      QStringList contents = ModBuild::readFile(path+cfile);
712      ui->text_resources_script->clear();
713      ui->text_resources_script->setText(contents.join("\n"));
714      ui->text_resources_script->setVisible(TRUE);
715      //hide the other widgets
716      ui->label_resources_description->setVisible(FALSE);
717      ui->label_resources_icon->setVisible(FALSE);
718    }
719  }       
720 
721}
722
723void MainGUI::on_push_resources_add_clicked(){
724  //Get the desired file
725  QStringList iFiles = QFileDialog::getOpenFileNames(this, tr("Select Resources"), settings->value("icondir") );
726  //Check that there were file selected
727  if(iFiles.isEmpty()){ return; }
728  //Now add these files to the module
729  for(int i=0; i<iFiles.length(); i++){
730    currentModule->addResource(FALSE,iFiles[i]);
731  }
732  //Now update the GUI
733  refreshGUI("resources");
734}
735
736void MainGUI::on_push_resources_remove_clicked(){
737  //Get the currently selected resource
738  QString cfile;
739  if(ui->listw_resources->currentRow() != -1){ cfile = ui->listw_resources->currentItem()->text(); }
740  //Check that there is something selected 
741  if(cfile.isEmpty()){ return; }
742  //Remove the resource
743  if(currentModule->removeResource(cfile)){
744      qDebug() << "Removed Resource:" << cfile;
745  }else{
746      qDebug() << "Error: Could not remove resource:"<<cfile;
747  }
748  //Refresh the GUI
749  refreshGUI("resources");
750}
751
752void MainGUI::on_push_resources_mkwrapper_clicked(){
753  //Get the desired filename for the wrapper script
754  bool ok;
755  QString cFile = QInputDialog::getText(this, tr("New Wrapper Script"), tr("Filename")+":", QLineEdit::Normal, "",&ok);
756  //Check for a valid input
757  if(!ok || cFile.isEmpty()){ return; }
758  //Now create the new file
759  currentModule->addResource(TRUE,cFile);
760  //Refresh the GUI
761  refreshGUI("resources");
762}
763
764void MainGUI::slotResourceScriptSaved(){
765  //get the current file and path
766  QString cfile;
767  if(ui->listw_resources->currentRow() != -1){ cfile = ui->listw_resources->currentItem()->text(); }
768  if(cfile.isEmpty()){ return; } // do nothing if no file selected
769  QString filePath = currentModule->path() + "/resources/" + cfile;
770  //Read the current text for the resource
771  QStringList contents = ui->text_resources_script->toPlainText().split("\n");
772  //overwrite the resource with the new contents
773  ModBuild::createFile(filePath,contents);
774}
775/*------------------------------------------------
776   XDG EDITOR OPTIONS
777  -------------------------------------------------
778*/
779void MainGUI::slotXdgTypeChanged(){
780  //Update the file list appropriately
781  if(ui->radio_xdg_desktop->isChecked()){
782    //update the files available
783    ui->list_xdg_files->clear();
784    ui->list_xdg_files->addItems(currentModule->filesAvailable("xdg-desktop"));
785    //Set the visibility
786        //Current file
787        ui->label_xdg_name->setVisible(TRUE); ui->line_xdg_name->setVisible(TRUE);
788        ui->label_xdg_exec->setVisible(TRUE); ui->line_xdg_exec->setVisible(TRUE); ui->push_xdg_exec->setVisible(TRUE);
789        ui->label_xdg_icon->setVisible(TRUE); ui->list_xdg_icon->setVisible(TRUE);
790        ui->label_xdg_menu->setVisible(FALSE); ui->line_xdg_menu->setVisible(FALSE); ui->push_xdg_menu->setVisible(FALSE);
791        ui->check_xdg_nodisplay->setVisible(TRUE);
792        ui->check_xdg_terminal->setVisible(TRUE);
793        ui->label_xdg_mimepatterns->setVisible(FALSE); ui->line_xdg_mimepatterns->setVisible(FALSE);
794       
795  }else if(ui->radio_xdg_menu->isChecked()){
796    //update the files available
797    ui->list_xdg_files->clear();
798    ui->list_xdg_files->addItems(currentModule->filesAvailable("xdg-menu"));     
799    //Set the visibility
800        //Current file
801        ui->label_xdg_name->setVisible(TRUE); ui->line_xdg_name->setVisible(TRUE);
802        ui->label_xdg_exec->setVisible(TRUE); ui->line_xdg_exec->setVisible(TRUE); ui->push_xdg_exec->setVisible(TRUE);
803        ui->label_xdg_icon->setVisible(TRUE); ui->list_xdg_icon->setVisible(TRUE);
804        ui->label_xdg_menu->setVisible(TRUE); ui->line_xdg_menu->setVisible(TRUE); ui->push_xdg_menu->setVisible(TRUE);
805        ui->check_xdg_nodisplay->setVisible(TRUE);
806        ui->check_xdg_terminal->setVisible(TRUE);
807        ui->label_xdg_mimepatterns->setVisible(TRUE); ui->line_xdg_mimepatterns->setVisible(TRUE);
808       
809  }
810  //Select the first file in the list if one is available
811  if( ui->list_xdg_files->count() > 0){ ui->list_xdg_files->setCurrentRow(0); }
812  //Update the program icon list for new entries
813  //QStringList icons = currentModule->currentIcons;
814
815  //Update the buttons that only need a refresh when the type changes (such as menu's)
816  //Available binaries pushbuttons
817  menu_bins.clear();
818  QStringList cBins = currentModule->currentBins;
819  if(!cBins.isEmpty()){
820    for(int i=0; i<cBins.length(); i++){
821      menu_bins.addAction(cBins[i]);
822    } 
823  }
824  //Menu categories
825  QString recMenu = currentModule->readValue("portmenucategory");
826  QStringList cats = currentModule->validMenuCategories;
827  menu_validMenuCats.clear();
828  for(int i=0; i<cats.length(); i++){
829    if(recMenu==cats[i]){ //Add an icon showing the recommended menu category
830      menu_validMenuCats.addAction(Backend::icon("start"),cats[i]);     
831    }else{
832      menu_validMenuCats.addAction(cats[i]);
833    }
834  }
835  //Now update read the currently selected file
836  slotXdgFileChanged();
837}
838
839void MainGUI::slotXdgFileChanged(){     
840  bool clearUI =FALSE;
841  if(ui->list_xdg_files->currentRow() == -1){ clearUI=TRUE; }
842
843  //Reset the icon list
844  ui->list_xdg_icon->clear();
845  QStringList icons = currentModule->currentIcons;
846  if(icons.length() > 0){
847      for(int i=0; i<icons.length(); i++){
848        ui->list_xdg_icon->addItem(QIcon(currentModule->path()+"/resources/"+icons[i]),icons[i]);
849      }     
850  }
851  //Get the selected file
852  QString file;
853  if( !clearUI ){ file = ui->list_xdg_files->currentItem()->text(); }
854  if( clearUI || file.isEmpty() ){
855    //Clear the UI lines
856    ui->line_xdg_name->clear();
857    ui->line_xdg_exec->clear();
858    ui->line_xdg_menu->clear();
859    ui->line_xdg_mimepatterns->clear();
860    ui->check_xdg_terminal->setChecked(FALSE);
861    ui->check_xdg_nodisplay->setChecked(FALSE);
862    ui->check_requiresroot->setChecked(FALSE);
863    ui->push_xdg_savechanges->setEnabled(FALSE);
864    //Make sure we don't have any of the structures loaded from previously
865    currentModule->loadDesktop("");
866    currentModule->loadMenu("");
867    currentModule->loadMime("");
868    //Now return
869    return; 
870  }
871  ui->push_xdg_savechanges->setEnabled(TRUE);
872  //Now setup the UI as appropriate
873  if(ui->radio_xdg_desktop->isChecked()){
874    //Load the file
875    currentModule->loadDesktop(file);
876    //update the file info on the GUI
877    ui->line_xdg_name->setText( currentModule->readValue("desktopname") );
878    ui->line_xdg_exec->setText( currentModule->readValue("desktopexec") ); 
879    //comboboxes
880    int cicon = icons.indexOf(currentModule->readValue("desktopicon"));
881    if( cicon == -1 ){ 
882      ui->list_xdg_icon->addItem(currentModule->readValue("desktopicon")); 
883      cicon = icons.indexOf(currentModule->readValue("desktopicon"));
884    }
885    ui->list_xdg_icon->setCurrentIndex(cicon);
886
887    //Checkboxes
888    QString chk = currentModule->readValue("desktopterminal").toLower();
889    if( (chk == "true") || (chk=="yes") ){ ui->check_xdg_terminal->setChecked(TRUE); }
890    else{ ui->check_xdg_terminal->setChecked(FALSE); }
891    chk = currentModule->readValue("desktopnodisplay").toLower();
892    if( (chk == "true") || (chk=="yes") ){ ui->check_xdg_nodisplay->setChecked(TRUE); }
893    else{ ui->check_xdg_nodisplay->setChecked(FALSE); }
894    chk = currentModule->readValue("desktoprequiresroot").toLower();
895    if( (chk == "true") || (chk=="yes") ){ ui->check_xdg_requiresroot->setChecked(TRUE); }
896    else{ ui->check_xdg_requiresroot->setChecked(FALSE); }
897       
898  }else if(ui->radio_xdg_menu->isChecked()){
899    //Load the file
900    currentModule->loadMenu(file);
901    //update the file info on the GUI
902    ui->line_xdg_name->setText( currentModule->readValue("menuname") );
903    ui->line_xdg_exec->setText( currentModule->readValue("menuexec") ); 
904    ui->line_xdg_menu->setText( currentModule->readValue("menucategories") );
905    //comboboxes
906          //icons
907    int cicon = icons.indexOf(currentModule->readValue("menuicon"));
908    if( cicon == -1 ){ 
909      ui->list_xdg_icon->addItem(currentModule->readValue("menuicon")); 
910      cicon = icons.indexOf(currentModule->readValue("menuicon"));
911    }
912    ui->list_xdg_icon->setCurrentIndex(cicon);
913   
914    //Checkboxes
915    QString chk = currentModule->readValue("menuterminal").toLower();
916    if( (chk == "true") || (chk=="yes") ){ ui->check_xdg_terminal->setChecked(TRUE); }
917    else{ ui->check_xdg_terminal->setChecked(FALSE); }
918    chk = currentModule->readValue("menunodisplay").toLower();
919    if( (chk == "true") || (chk=="yes") ){ ui->check_xdg_nodisplay->setChecked(TRUE); }
920    else{ ui->check_xdg_nodisplay->setChecked(FALSE); }
921    chk = currentModule->readValue("menurequiresroot").toLower();
922    if( (chk == "true") || (chk=="yes") ){ ui->check_xdg_requiresroot->setChecked(TRUE); }
923    else{ ui->check_xdg_requiresroot->setChecked(FALSE); }
924   
925    //Load the XDG-MIME file associations
926    QString mime = currentModule->readValue("menumimetype");
927    QStringList mimeavailable = currentModule->filesAvailable("xdg-mime");
928    bool found = FALSE;
929    for( int i=0; i<mimeavailable.length(); i++){
930      currentModule->loadMime(mimeavailable[i]);
931      if(currentModule->readValue("mimetype") == mime){
932        found = TRUE;
933        break;
934      }
935    }
936    //qDebug() << "mimetype detected:" << mime;
937    if(found){
938      ui->line_xdg_mimepatterns->setText( currentModule->readValue("mimepatterns") ); 
939    }else{
940      currentModule->loadMime(""); //Make sure we don't have any mime file loaded
941      ui->line_xdg_mimepatterns->clear();
942    }
943   
944  }else{
945    //do nothing, unknown radio button selected (or none)
946  }
947}
948
949void MainGUI::slotAddMenuCat(QAction* act){
950  //get the selected menu category
951  QString newcat = act->text();
952  //Read the current categories
953  QStringList oldcats = ui->line_xdg_menu->text().split(";", QString::SkipEmptyParts);
954  for(int i=0; i<oldcats.length(); i++){
955    oldcats[i] = oldcats[i].simplified();
956    if(oldcats[i] == newcat){return;} //category already in the list, do nothing
957  }
958  //Add the item
959  oldcats << newcat;
960  //Now replace the line onto the GUI
961  ui->line_xdg_menu->setText(oldcats.join("; "));
962}
963
964void MainGUI::slotAddBin(QAction* act){
965  //replace the current executable with the new one
966  ui->line_xdg_exec->setText(act->text().section("/",-1) );     
967}
968
969void MainGUI::on_push_xdg_remove_clicked(){
970  //Figure out if a file is selected
971  if( ui->list_xdg_files->currentItem()->text().isEmpty() ){ return; }
972  //Now remove the file
973  bool ok = FALSE;
974  if( ui->radio_xdg_desktop->isChecked() ){
975    ok = currentModule->removeDesktop();
976  }else if( ui->radio_xdg_menu->isChecked() ){
977    ok = currentModule->removeMenu();
978  }
979  //Now inform the user if there was an error
980  if(!ok){
981    QMessageBox::warning(this, tr("EasyPBI Error"), tr("Could not remove the XDG entry.")+"\n"+tr("Check the file permissions and try again") );
982  }
983  //Now refresh the GUI
984  refreshGUI("xdg");
985 
986}
987
988void MainGUI::on_push_xdg_savechanges_clicked(){
989  //save the current UI settings to the module structure then save the file
990  bool ok = FALSE;
991  if( ui->radio_xdg_desktop->isChecked() ){
992    currentModule->writeValue("desktopname",ui->line_xdg_name->text());
993    currentModule->writeValue("desktopgenericname",ui->line_xdg_name->text().toLower());
994    currentModule->writeValue("desktopexec",ui->line_xdg_exec->text());
995    currentModule->writeValue("desktopicon",ui->list_xdg_icon->currentText());
996    QString checked = "false";
997    if(ui->check_xdg_terminal->isChecked()){ checked="true"; }
998    currentModule->writeValue("desktopterminal",checked);
999    checked = "false";
1000    if(ui->check_xdg_nodisplay->isChecked()){ checked="true"; }
1001    currentModule->writeValue("desktopnodisplay",checked);
1002    checked = "false";
1003    if(ui->check_xdg_requiresroot->isChecked()){ checked="true"; }
1004    currentModule->writeValue("desktoprequiresroot", checked);
1005    //Now save the file
1006    ok = currentModule->writeDesktop();
1007   
1008  }else if( ui->radio_xdg_menu->isChecked() ){
1009    currentModule->writeValue("menuname",ui->line_xdg_name->text());
1010    currentModule->writeValue("menugenericname",ui->line_xdg_name->text().toLower());
1011    currentModule->writeValue("menuexec",ui->line_xdg_exec->text());
1012    currentModule->writeValue("menuicon",ui->list_xdg_icon->currentText());
1013    currentModule->writeValue("menucategories", ui->line_xdg_menu->text());
1014    QString checked = "false";
1015    if(ui->check_xdg_terminal->isChecked()){ checked="true"; }
1016    currentModule->writeValue("menuterminal",checked);
1017    checked = "false";
1018    if(ui->check_xdg_nodisplay->isChecked()){ checked="true"; }
1019    currentModule->writeValue("menunodisplay",checked);
1020    checked = "false";
1021    if(ui->check_xdg_requiresroot->isChecked()){ checked="true"; }
1022    currentModule->writeValue("menurequiresroot", checked);
1023    //Setup the mime type associations as appropriate
1024    checkMime();
1025    //Now save the file
1026    ok = currentModule->writeMenu();   
1027  }
1028  //Now inform the user if there was an error
1029  if(!ok){
1030    QMessageBox::warning(this, tr("EasyPBI Error"), tr("Could not save the changes to the XDG entry.")+"\n"+tr("Check the file permissions and try again") );
1031  }
1032  //Now refresh the GUI
1033  //refreshGUI("xdg"); //refresh the entire tab
1034  slotXdgFileChanged(); //only update the proper half of the tab
1035}
1036
1037void MainGUI::on_push_xdg_savenew_clicked(){
1038  //Get the filename we want to save
1039  QString filename;
1040  //Now check that the filename does not already exist
1041  QStringList cFiles;
1042  if(ui->radio_xdg_desktop->isChecked() ){
1043    filename = ui->line_xdg_exec->text().section("/",-1);
1044    cFiles = currentModule->filesAvailable("xdg-desktop").replaceInStrings(".desktop","");
1045  }else if(ui->radio_xdg_menu->isChecked() ){
1046    filename = ui->line_xdg_exec->text().section("/",-1);
1047    cFiles = currentModule->filesAvailable("xdg-menu").replaceInStrings(".desktop","");
1048  }
1049  if(filename.isEmpty()){ return;}
1050 
1051  if(cFiles.indexOf(filename) != -1){
1052    int num = 1;
1053    while(cFiles.indexOf(filename+QString::number(num)) != -1){ num++; }
1054    filename.append( QString::number(num) );
1055  }
1056  //save the current UI settings to the module structure then save the file
1057  bool ok = FALSE;
1058  if( ui->radio_xdg_desktop->isChecked() ){
1059    currentModule->loadDesktop(filename+".desktop"); //get the new file ready
1060    currentModule->writeValue("desktopname",ui->line_xdg_name->text());
1061    currentModule->writeValue("desktopgenericname",ui->line_xdg_name->text().toLower());
1062    currentModule->writeValue("desktopexec",ui->line_xdg_exec->text());
1063    currentModule->writeValue("desktopicon",ui->list_xdg_icon->currentText());
1064    QString checked = "false";
1065    if(ui->check_xdg_terminal->isChecked()){ checked="true"; }
1066    currentModule->writeValue("desktopterminal",checked);
1067    checked = "false";
1068    if(ui->check_xdg_nodisplay->isChecked()){ checked="true"; }
1069    currentModule->writeValue("desktopnodisplay",checked);
1070    checked = "false";
1071    if(ui->check_xdg_requiresroot->isChecked()){ checked="true"; }
1072    currentModule->writeValue("desktoprequiresroot", checked);
1073    //Now save the file
1074    ok = currentModule->writeDesktop();
1075   
1076  }else if( ui->radio_xdg_menu->isChecked() ){
1077    currentModule->loadMenu(filename+".desktop"); //get the new file ready
1078    //Update the MIME associations
1079    checkMime();
1080    //Save the MENU values
1081    currentModule->writeValue("menuname",ui->line_xdg_name->text());
1082    currentModule->writeValue("menugenericname",ui->line_xdg_name->text().toLower());
1083    currentModule->writeValue("menuexec",ui->line_xdg_exec->text());
1084    currentModule->writeValue("menuicon",ui->list_xdg_icon->currentText());
1085    currentModule->writeValue("menucategories", ui->line_xdg_menu->text());
1086    QString checked = "false";
1087    if(ui->check_xdg_terminal->isChecked()){ checked="true"; }
1088    currentModule->writeValue("menuterminal",checked);
1089    checked = "false";
1090    if(ui->check_xdg_nodisplay->isChecked()){ checked="true"; }
1091    currentModule->writeValue("menunodisplay",checked);
1092    checked = "false";
1093    if(ui->check_xdg_requiresroot->isChecked()){ checked="true"; }
1094    currentModule->writeValue("menurequiresroot", checked);
1095    //Now save the file
1096    ok = currentModule->writeMenu();   
1097  }
1098  //Now inform the user if there was an error
1099  if(!ok){
1100    QMessageBox::warning(this, tr("EasyPBI Error"), tr("Could not save the changes to the XDG entry.")+"\n"+tr("Check the file permissions and try again") );
1101  }
1102  //Now refresh the GUI
1103  refreshGUI("xdg");
1104}
1105
1106void MainGUI::on_push_xdg_clearentry_clicked(){
1107  //Clear the UI
1108        //reset the item selected to nothing
1109        ui->list_xdg_files->setCurrentRow(-1);
1110        //De-activate the "save" button
1111        ui->push_xdg_savechanges->setEnabled(FALSE);
1112        //Now clear the
1113        slotXdgFileChanged();
1114}
1115
1116void MainGUI::checkMime(){
1117    //This function will check the UI for differences in the MIME patterns
1118      // and update/create the MIME file appropriately
1119      // The MENU mime type will also be appropriately set
1120       
1121    QString menumimetype = currentModule->readValue("menumimetype");
1122    QString menumimepat = ui->line_xdg_mimepatterns->text();
1123    QString cmimetype = currentModule->readValue("mimetype");
1124    QString cmimepat = currentModule->readValue("mimepatterns");
1125    if( menumimepat != cmimepat ){ //something different about the mime patterns
1126        //  ---- Change the MIME file as well ----
1127          //Delete MIME file
1128        if(menumimepat.isEmpty()){
1129          currentModule->removeMime();
1130          currentModule->writeValue("menumimetype",""); //set MENU value
1131               
1132          //Create new MIME file
1133        }else if( cmimetype.isEmpty() || (ui->line_xdg_exec->text() != currentModule->readValue("menuexec")) ){
1134          QString exec = ui->line_xdg_exec->text().simplified();
1135          menumimetype = "application/x-"+exec;
1136          QString newfile = exec+"-xdg.xml";
1137          currentModule->loadMime(newfile); //setup structure
1138          currentModule->writeValue("mimetype",menumimetype); //set mime type
1139          currentModule->writeValue("mimepatterns",menumimepat); //set mime patterns
1140          currentModule->writeMime(); //save the MIME file (using default mime info)
1141               
1142          currentModule->writeValue("menumimetype",menumimetype); //set MENU value
1143               
1144          //Overwrite existing MIME file
1145        }else{
1146          currentModule->writeValue("mimepatterns", menumimepat); //overwrite mime patterns
1147          currentModule->writeMime(); //overwrite the MIME file
1148               
1149          currentModule->writeValue("menumimetype",cmimetype); //set MENU value
1150        }
1151    }
1152}
1153
1154/*------------------------------------------------
1155   SCRIPTS EDITOR OPTIONS
1156  -------------------------------------------------
1157*/
1158void MainGUI::slotScriptChanged(int index){
1159  index=0; //just to remove the warning about unused variables
1160  refreshGUI("scripts");
1161}
1162
1163void MainGUI::on_push_scripts_create_clicked(){
1164  //Setup display items
1165  ui->push_scripts_create->setVisible(FALSE);
1166  ui->push_scripts_remove->setVisible(FALSE);
1167  ui->push_scripts_save->setVisible(TRUE);
1168  ui->text_scripts_edit->setVisible(TRUE);
1169  ui->text_scripts_edit->clear();
1170}
1171
1172void MainGUI::on_push_scripts_remove_clicked(){
1173  //Get the current file
1174  QString filename = ui->list_scripts_file->currentText();
1175  //Remove the file
1176  QDir dir(currentModule->path()+"/scripts");
1177  dir.remove(filename);
1178  //refresh the UI
1179  refreshGUI("scripts");
1180}
1181
1182void MainGUI::on_push_scripts_save_clicked(){
1183  //Get the current file text
1184  QStringList contents = ui->text_scripts_edit->toPlainText().split("\n");
1185  //get the current file
1186  QString filename = currentModule->path() + "/scripts/"+ui->list_scripts_file->currentText();
1187  //Save the file
1188  bool ok = ModBuild::createFile(filename,contents);
1189  //display a warning if error
1190  if(!ok){
1191    QMessageBox::warning(this,tr("Error Saving File"), tr("Could not save the script")+"\n"+tr("Please check the file permissions and try again") );
1192  }
1193  //Now refresh the UI
1194  refreshGUI("scripts");
1195}
1196/*------------------------------------------------
1197   EXTERNAL-LINKS EDITOR OPTIONS
1198  -------------------------------------------------
1199*/
1200void MainGUI::on_push_el_add_clicked(){
1201  //Read the user inputs
1202  QString file = ui->line_el_file->text();
1203  QString linkto = ui->line_el_linkto->text();
1204  QString opts = ui->line_el_filetype->text();
1205  //check for valid inputs
1206  if( file.isEmpty() || linkto.isEmpty() || opts.isEmpty() ){ return; }
1207  //Add the link
1208  currentModule->addExternalLink(file, linkto, opts.split(",") );
1209  //Save the file
1210  currentModule->writeExternalLinks();
1211  //Refresh the UI
1212  refreshGUI("external-links");
1213}
1214
1215void MainGUI::on_push_el_remove_clicked(){
1216  //Get the currently selected link
1217  QTreeWidgetItem *line = ui->tree_el_view->currentItem();
1218  if(line->columnCount() != 3){ return; }
1219  QString file = line->text(0);
1220  QString linkto = line->text(1);
1221  //Remove the link
1222  currentModule->removeExternalLink(file,linkto);
1223  //Save the file
1224  currentModule->writeExternalLinks();
1225  //Refresh the UI
1226  refreshGUI("external-links");
1227}
1228
1229void MainGUI::slotELSetFile(QAction* act){
1230  //get the selected file and set it in the UI
1231  ui->line_el_file->setText( act->text() );
1232  ui->line_el_linkto->setText( act->text() );
1233}
1234
1235void MainGUI::slotELSetType(QAction* act){
1236  //Get the current types
1237  QStringList types = ui->line_el_filetype->text().split(",", QString::SkipEmptyParts);
1238  //get the new type
1239  QString ntype  = act->text();
1240  //Now properly add the type as appropriate
1241  bool ok = FALSE;
1242  for(int i=0; i<types.length(); i++){
1243    //Check for special cases
1244    if( (types[i] == "keep") && (ntype=="replace") ){
1245      types[i] = ntype;
1246      ok = TRUE;
1247      break;
1248    }else if( (types[i] == "replace") && (ntype=="keep") ){
1249      types[i] = ntype;
1250      ok = TRUE;
1251      break;
1252    }else if( (types[i]=="binary") && (ntype=="linux") ){
1253      types[i] = ntype;
1254      ok = TRUE;
1255      break;
1256    }else if( (types[i]=="linux") && (ntype=="binary") ){
1257      types[i] = ntype;
1258      ok = TRUE;
1259      break;
1260    }else if( types[i] == ntype ){
1261      ok=TRUE;
1262      break;
1263    }
1264  }
1265  if(!ok){ types << ntype; } //append the type to the list
1266  //Add the new types to the UI
1267  ui->line_el_filetype->setText( types.join(",") );
1268}
1269/*------------------------------------------------
1270   FREENAS PLUGINS EDITOR OPTIONS
1271  -------------------------------------------------
1272*/
1273
1274
1275/*------------------------------------------------
1276   PBI BUILDER OPTIONS
1277  -------------------------------------------------
1278*/
1279void MainGUI::on_push_build_start_clicked(){
1280  //Check GUI to make sure settings are set before running
1281  bool gostatus = TRUE;
1282  QString outdir = settings->value("pbidir");
1283  if (outdir.isEmpty() ){gostatus=FALSE;}
1284  //QString sigfile = "";ui->linePBIDigSigFile->text(); //this one can be empty
1285  QString modDir = currentModule->path();
1286  if(modDir.isEmpty()){gostatus=FALSE;}
1287  if(!gostatus){
1288    QMessageBox::warning(this,tr("Error"),tr("Invalid PBI Settings"));
1289    return;
1290  }
1291 
1292  //Generate the PBI build command
1293  QString cmd;
1294  // -- PBI from ports
1295  if(radio_module_port->isChecked()){
1296    //Check that the ports tree is available
1297    if( !settings->check("isportsavailable") ){ 
1298      qDebug() << "Cannot build a PBI from ports without the FreeBSD ports tree available";
1299      return;
1300    }
1301    //Setup the pbi_makeport command from GUI settings
1302    cmd = settings->value("pbi_makeport");
1303    if(ui->check_build_32->isChecked()){ cmd += " -32"; }
1304    cmd += " -c " + modDir;
1305    if(settings->value("portsdir") != "/usr/ports"){ cmd += " -d " + settings->value("portsdir"); }
1306    cmd += " -o " + outdir;
1307    cmd += " --delbuild";
1308    if( settings->check("usetmpfs") ){ cmd += " --tmpfs"; }
1309    if( settings->check("usecache") ){ 
1310      cmd += " --pkgdir " + settings->value("cachedir");
1311      //Remove known "bad" packages (ones that routinely cause failures)
1312      QDir cDir( settings->value("cachedir") );
1313      QStringList filters = settings->list("skippkgs");
1314      QStringList badFiles = cDir.entryList(filters, QDir::Files | QDir:: NoDotAndDotDot);
1315      for(int i=0; i<badFiles.length(); i++){ cDir.remove(badFiles[i]); }
1316    }
1317    if( settings->check("usesignature") && QFile::exists(settings->value("sigfile")) ){ cmd += " --sign " + settings->value("sigfile"); }
1318   
1319  // -- PBI from local directory
1320  }else if(radio_module_local->isChecked() ){
1321        //get the base command
1322        cmd = settings->value("pbi_create");
1323        //Setup the ports options if non-standard port location
1324        if(settings->value("portsdir") != "/usr/ports"){ cmd += " -d " + settings->value("portsdir"); }
1325        //Setup the output directory
1326        cmd += " -o "+outdir;
1327        //Load the module
1328        cmd += " -c "+modDir;
1329        //Sign the PBI
1330        if( settings->check("usesignature") && QFile::exists(settings->value("sigfile")) ){ cmd += " --sign " + settings->value("sigfile"); }
1331        //Now setup the directory to package
1332        cmd += " "+ currentModule->readValue("packagedir");
1333  }
1334  //Display the command created in hte terminal
1335  qDebug() << "Build PBI command created:"<<cmd;
1336 
1337  //Receive User verification before beginning build process due to:
1338  //  -- long time required, internet connection required, root permissions required
1339  QMessageBox verify(this);
1340  verify.setText(tr("Are you sure you wish to start the PBI build?"));
1341  verify.setInformativeText(tr("This requires an active internet connection and root permissions. The time required to build a PBI varies depending upon system specifications and ports to be compiled."));
1342  verify.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
1343  verify.setDefaultButton(QMessageBox::Yes);
1344  int ret = verify.exec();
1345  if(ret != QMessageBox::Yes){return;}
1346
1347  //Add the necessary glue to the command to run the pbi build
1348  cmd.prepend(settings->value("su_cmd")+" \"");
1349  cmd.append("\"");
1350  qDebug() << "Actual command used:" << cmd;
1351
1352  //Setup the displays
1353  ui->push_build_stop->setEnabled(TRUE);
1354  ui->push_build_save->setEnabled(FALSE);
1355  ui->check_build_32->setEnabled(FALSE);
1356  ui->push_build_start->setEnabled(FALSE); //disable the button so they do not start more than 1 build at a time
1357  ui->text_build_log->clear(); //clear the display in case this is not the first run
1358  ui->line_build_module->setText(currentModule->path());
1359  ui->line_build_outputdir->setText(settings->value("pbidir"));
1360  //Setup Process connections
1361  p = new QProcess(this);
1362  p->setProcessChannelMode(QProcess::MergedChannels);
1363  p->setProcessEnvironment( QProcessEnvironment::systemEnvironment() );
1364  connect(p,SIGNAL(readyReadStandardOutput()),this,SLOT(slotUpdatePBIBuild()) );
1365  connect(p,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(slotPBIbuildFinished(int,QProcess::ExitStatus)) );
1366  connect(p,SIGNAL(error(QProcess::ProcessError)),this,SLOT(slotBuildError(QProcess::ProcessError)) );
1367  //Setup the flag for the finishing checks
1368  PBI_BUILDING_NOW=outdir+":::"+currentModule->readValue("progname");
1369  //Start the Process
1370  qDebug() << "Starting the PBI build process...";
1371  ui->toolBox->setItemText(0,tr("PBI Builder (Working)"));
1372  p->start(cmd);
1373}
1374
1375void MainGUI::on_push_build_stop_clicked(){
1376  slotKillPBIBuild();
1377}
1378
1379void MainGUI::on_push_build_save_clicked(){
1380  //Have user select a filename/location to save the log
1381  QString filename = QFileDialog::getSaveFileName(this,tr("Save Log"),settings->value("progdir")+"/build.log",tr("Log Files")+" (*.log *.txt)");
1382  if(filename.isEmpty()){return;} //User cancelled the process
1383  //Open the file (as new)
1384  QFile *file = new QFile(filename);
1385  file->open(QIODevice::WriteOnly);
1386  //Save the log into the file
1387  file->write(ui->text_build_log->toPlainText().toUtf8());
1388  file->close();
1389}
1390
1391void MainGUI::slotUpdatePBIBuild(){
1392  QString tmp = p->readAllStandardOutput();
1393  if( tmp.startsWith("\n") ){tmp.remove(0,0);} //remove newline at the beginning (too much whitespace in log)
1394  if( tmp.endsWith("\n") ){tmp.chop(1);} //remove newline at the end (already accounted for by appending)
1395  if(!tmp.isEmpty()){ ui->text_build_log->append( tmp ); }
1396  //qDebug() << "Update output: " << tmp;
1397}
1398
1399void MainGUI::slotPBIbuildFinished(int exitCode,QProcess::ExitStatus exitStatus){
1400  //Check to see if the PBI process finished successfully
1401  qDebug() << "PBI build process Finished" << exitStatus << exitCode;
1402  //Check that the new PBI exists
1403  QDir outdir( PBI_BUILDING_NOW.section(":::",0,0) );
1404  QString pbiname= PBI_BUILDING_NOW.section(":::",1,1).toLower().remove(" ");
1405  QFileInfoList fL = outdir.entryInfoList( QStringList() << pbiname+"*.pbi" ,QDir::Files | QDir::NoSymLinks);
1406  bool success = FALSE;
1407  for(int i=0; i<fL.length(); i++){
1408          qint64 msdiff = QDateTime::currentMSecsSinceEpoch() - fL[i].created().toMSecsSinceEpoch();
1409          if(msdiff < 30000){ success = true; break; } //if less than a 30sec since creation of file - success
1410  }
1411 
1412  if(exitCode == 0 && success){
1413      QMessageBox::information(this,tr("PBI Build Success"),tr("The PBI finished building successfully"));
1414  }else if(exitCode == 0 && PBI_BUILD_TERMINATED){
1415      //The user killed the process - No Message
1416  }else{
1417    QMessageBox::warning(this,tr("PBI Build Failure"),tr("The PBI failed to build.")+"\n"+tr("Please check the build log to find the cause of the failure and adjust the module accordingly"));
1418  }
1419  ui->push_build_start->setEnabled(TRUE);
1420  ui->push_build_save->setEnabled(TRUE);
1421  ui->push_build_stop->setEnabled(FALSE);
1422  ui->check_build_32->setEnabled(TRUE);
1423  p->close();
1424  PBI_BUILDING_NOW.clear();
1425  PBI_BUILD_TERMINATED=FALSE;
1426  ui->toolBox->setItemText(0,tr("PBI Builder (Finished)"));
1427  delete p;
1428}
1429
1430void MainGUI::slotKillPBIBuild(){
1431  if( p->state()==QProcess::Running ){
1432    //qDebug() << "Process PID:" << p->pid();
1433    PBI_BUILD_TERMINATED=TRUE;   
1434    p->terminate();
1435    ui->text_build_log->append("---PBI Build Terminated---");
1436  }
1437}
1438
1439void MainGUI::slotBuildError(QProcess::ProcessError error){
1440  qDebug() << "QProcess PBI Build error#" << error;
1441}
Note: See TracBrowser for help on using the repository browser.