source: src-qt4/EasyPBI/mainGUI.cpp @ 1f245a6

releng/10.0.1releng/10.0.2
Last change on this file since 1f245a6 was 1f245a6, checked in by Ken Moore <ken@…>, 6 months ago

A few bugfixes for EasyPBI:
1) Fix pkg info retrieval (pkg syntax changed)
2) Fix changing PBI_MAKEPORT in the module
3) Adjust default focus policies for the pkg selector GUI

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