source: src-qt4/pc-softwaremanager/mainUI.cpp @ da39501

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

Make sure that empty entries are not put into the AppCafe? installed list (this rerely happened expect for a second when installing a PBI that had already been downloaded for some reason).

  • Property mode set to 100644
File size: 40.7 KB
Line 
1/***************************************************************************
2 *   Copyright (C) 2011 - iXsystems                                       *
3 *   kris@pcbsd.org  *
4 *   tim@pcbsd.org   *
5 *   ken@pcbsd.org   *
6 *                                                                         *
7 *   Permission is hereby granted, free of charge, to any person obtaining *
8 *   a copy of this software and associated documentation files (the       *
9 *   "Software"), to deal in the Software without restriction, including   *
10 *   without limitation the rights to use, copy, modify, merge, publish,   *
11 *   distribute, sublicense, and/or sell copies of the Software, and to    *
12 *   permit persons to whom the Software is furnished to do so, subject to *
13 *   the following conditions:                                             *
14 *                                                                         *
15 *   The above copyright notice and this permission notice shall be        *
16 *   included in all copies or substantial portions of the Software.       *
17 *                                                                         *
18 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
19 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
20 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
21 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
22 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
23 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
24 *   OTHER DEALINGS IN THE SOFTWARE.                                       *
25 ***************************************************************************/
26#include "mainUI.h"
27#include "ui_mainUI.h"
28
29MainUI::MainUI(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainUI){
30  //initialization function
31  ui->setupUi(this); //load the Qt-Designer file
32  defaultIcon = ":/application.png";
33  statusLabel = new QLabel();
34  ui->statusbar->addWidget(statusLabel);
35}
36
37void MainUI::setWardenMode(QString dir, QString ip){
38  wardenDir = dir; wardenIP = ip;
39}
40
41void MainUI::ProgramInit()
42{ 
43   qDebug("Application starting...");
44   //Initial Checks
45     bool wardenMode = !wardenDir.isEmpty();
46     bool ok = Extras::checkUser(wardenMode);
47     if(!ok && wardenMode){  //Not root
48       QMessageBox::information( this, tr("Error!"), tr("The AppCafe must be run as root when in Warden compatibility mode") );
49       close();     
50     }else if( !ok && !wardenMode){
51       QMessageBox::information( this, tr("Error!"), tr("The AppCafe must be started with user permissions!")+"\n"+tr("The user must also be a part of the \"operator\" group") );
52       close();
53     }
54   
55   //Initialize the backend worker class
56   //qDebug() << "Initialize Backend";
57   PBI = new PBIBackend();
58     if(wardenMode){ PBI->setWardenMode(wardenDir, wardenIP); }
59     
60   //Initialize the Installed tab
61   //qDebug() << "Initialize Installed Tab";
62   initializeInstalledTab();
63   //Initialize the PBI Browser
64   //qDebug() << "Initialize Browser Tab";
65   initializeBrowserTab();
66   
67   //Now startup the backend
68   //qDebug() << "Startup Backend";
69     connect(PBI,SIGNAL(LocalPBIChanges()),this,SLOT(slotRefreshInstallTab()) );
70     connect(PBI,SIGNAL(PBIStatusChange(QString)),this,SLOT(slotPBIStatusUpdate(QString)) );
71     connect(PBI,SIGNAL(RepositoryInfoReady()),this,SLOT(slotEnableBrowser()) );
72     connect(PBI,SIGNAL(NoRepoAvailable()),this,SLOT(slotDisableBrowser()) );
73     connect(PBI,SIGNAL(SearchComplete(QStringList,QStringList)),this,SLOT(slotShowSearchResults(QStringList, QStringList)) );
74     connect(PBI,SIGNAL(SimilarFound(QStringList)),this,SLOT(slotShowSimilarApps(QStringList)) );
75     connect(PBI,SIGNAL(Error(QString,QString,QStringList)),this,SLOT(slotDisplayError(QString,QString,QStringList)) );
76     PBI->start();
77
78   //Make sure we start on the installed tab
79   ui->tabWidget->setCurrentWidget(ui->tab_installed);
80}
81
82void MainUI::slotSingleInstance(){
83  this->raise();
84  this->showNormal();
85  this->activateWindow();
86}
87
88void MainUI::closeEvent(QCloseEvent *event){
89  bool safe = PBI->safeToQuit();
90  if(!safe){
91    //Verify that they want to continue
92    QMessageBox::StandardButton button = QMessageBox::warning(this, tr("AppCafe Processes Running"), tr("The AppCafe currently has actions pending. Do you want to cancel all running processes and quit anyway?"), QMessageBox::Yes | QMessageBox::Cancel,QMessageBox::Cancel);
93    if(button == QMessageBox::Yes){ //close down
94      PBI->cancelActions( PBI->installedList() ); //close down safely
95    }else{
96      event->ignore();
97      return;
98    }
99  }
100  this->close();
101}
102// ========================
103// ===== MENU OPTIONS =====
104// ========================
105void MainUI::on_actionImport_PBI_List_triggered(){
106  QString file = QFileDialog::getOpenFileName( this, tr("Import PBI File List"), QDir::homePath(), tr("PBI List (*.pbilist)"));
107  if(file.isEmpty()){ return; } //action cancelled
108  bool ok = PBI->importPbiListFromFile(file);
109  if(!ok){ qDebug() << QMessageBox::warning(this,tr("Import Error"),tr("There was an error importing the PBI list")+"\n"+tr("Please make sure that the file has not been corrupted and try again")); }
110}
111
112void MainUI::on_actionExport_PBI_List_triggered(){
113  QString file = QFileDialog::getSaveFileName( this, tr("Export PBI File List"), QDir::homePath()+"/exportfile.pbilist", tr("PBI List (*.pbilist)"));
114  if(file.isEmpty()){ return; } //action cancelled
115  bool ok = PBI->exportPbiListToFile(file);
116  if(!ok){ qDebug() << QMessageBox::warning(this,tr("Export Error"),tr("There was an error exporting the PBI list")+"\n"+tr("Please make sure that you have the proper directory permissions and try again")); }
117}
118
119void MainUI::on_actionQuit_triggered(){
120  this->close();
121}
122
123void MainUI::on_actionAppCafe_Settings_triggered(){
124  PBI->openConfigurationDialog();
125}
126
127// =========================
128// ===== INSTALLED TAB =====
129// =========================
130void MainUI::initializeInstalledTab(){
131  //Setup the action menu for installed applications
132  actionMenu = new QMenu();
133    actionMenu->addAction( QIcon(":icons/view-refresh.png"), tr("Update"), this, SLOT(slotActionUpdate()) );
134    actionMenu->addSeparator();
135    QMenu *dmenu = actionMenu->addMenu( QIcon(":icons/xdg_desktop.png"), tr("Desktop Icons"));
136      dmenu->addAction( QIcon(":icons/add.png"),tr("Add"),this,SLOT(slotActionAddDesktop()) );
137      dmenu->addAction( QIcon(":icons/remove.png"),tr("Remove"),this,SLOT(slotActionRemoveDesktop()) );
138    QMenu *mmenu = actionMenu->addMenu( QIcon(":icons/xdg_menu.png"), tr("Menu Icons"));
139      mmenu->addAction( QIcon(":icons/add.png"),tr("Add"),this,SLOT(slotActionAddMenu()) );
140      mmenu->addAction( QIcon(":icons/remove.png"),tr("Remove"),this,SLOT(slotActionRemoveMenu()) ); 
141      mmenu->addAction( QIcon(":icons/add-root.png"),tr("Add (All Users)"),this,SLOT(slotActionAddMenuAll()) );
142    QMenu *pmenu = actionMenu->addMenu( QIcon(":icons/xdg_paths.png"), tr("Path Links"));
143      pmenu->addAction( QIcon(":icons/add.png"),tr("Add"),this,SLOT(slotActionAddPath()) );
144      pmenu->addAction( QIcon(":icons/remove.png"),tr("Remove"),this,SLOT(slotActionRemovePath()) ); 
145      pmenu->addAction( QIcon(":icons/add-root.png"),tr("Add (All Users)"),this,SLOT(slotActionAddPathAll()) );
146    QMenu *fmenu = actionMenu->addMenu( QIcon(":icons/xdg_mime.png"), tr("File Associations"));
147      fmenu->addAction( QIcon(":icons/add.png"),tr("Add"),this,SLOT(slotActionAddMime()) );
148      fmenu->addAction( QIcon(":icons/remove.png"),tr("Remove"),this,SLOT(slotActionRemoveMime()) ); 
149      fmenu->addAction( QIcon(":icons/add-root.png"),tr("Add (All Users)"),this,SLOT(slotActionAddMimeAll()) );
150    actionMenu->addSeparator();
151    actionMenu->addAction( QIcon(":icons/remove.png"), tr("Uninstall"), this, SLOT(slotActionRemove()) );
152    actionMenu->addSeparator();
153    actionMenu->addAction( QIcon(":icons/dialog-cancel.png"), tr("Cancel Actions"), this, SLOT(slotActionCancel()) );
154  //Setup the binary menu for installed applications
155  appBinMenu = new QMenu();
156  ui->tool_install_startApp->setMenu(appBinMenu);
157    connect(appBinMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotStartApp(QAction*)) );
158  //Now setup the action button
159  ui->tool_install_performaction->setMenu(actionMenu);
160  ui->tool_install_performaction->setPopupMode(QToolButton::InstantPopup);
161  //Now setup any defaults for the installed tab
162  ui->tool_install_gotobrowserpage->setEnabled(FALSE); //disable it until the browser is ready
163  ui->tree_install_apps->setIconSize(QSize(22,22));
164  slotRefreshInstallTab();
165}
166
167void MainUI::formatInstalledItemDisplay(QTreeWidgetItem *item){
168  //simplification function for filling the tree widget item with the appropriate information about the PBI
169  QString ID = item->whatsThis(0);
170  if(item->text(0).isEmpty()){  //new entry - get everything
171    QStringList vals; vals <<"name"<<"version"<<"status"; //same as column order
172    if(!vals.isEmpty()){
173      vals = PBI->PBIInfo(ID, vals);
174      for(int i=0; i<vals.length(); i++){ item->setText(i,vals[i]); }
175      QString icon = PBI->PBIInfo(ID, QStringList("icon")).join("");
176        //Load a default icon if none found
177      if(icon.isEmpty()){ icon = defaultIcon; }
178      item->setIcon(0,QIcon(icon) );
179      item->setCheckState(0,Qt::Unchecked);
180    }
181  }else{ // Just update the necesary info
182    QStringList vals; vals << "version" << "status";
183    vals = PBI->PBIInfo(ID,vals);
184    if(!vals.isEmpty()){ item->setText(1,vals[0]); item->setText(2,vals[1]); }
185  }
186}
187
188QStringList MainUI::getCheckedItems(){
189  //Return the pbiID's of all the checked items
190  QStringList output;
191  for(int i=0; i<ui->tree_install_apps->topLevelItemCount(); i++){
192    if(ui->tree_install_apps->topLevelItem(i)->checkState(0) == Qt::Checked){
193      output << ui->tree_install_apps->topLevelItem(i)->whatsThis(0);
194    }
195  }
196  //If no items checked, use the item that is selected instead
197  if(output.isEmpty()){
198    //Make sure that an item is selected
199    if(ui->tree_install_apps->topLevelItemCount() >0){
200      output << ui->tree_install_apps->currentItem()->whatsThis(0); 
201    }
202  }
203  return output;       
204}
205
206// === SLOTS ===
207void MainUI::slotRefreshInstallTab(){
208  //Update the list of installed PBI's w/o clearing the list (loses selections)
209   //Get the list we need (in order)
210  QStringList installList = PBI->installedList();
211  installList.sort(); //sort in ascending order
212   //Get the list we have now
213  QStringList cList;
214  for(int i=0; i<ui->tree_install_apps->topLevelItemCount(); i++){
215    cList << ui->tree_install_apps->topLevelItem(i)->whatsThis(0);
216  }
217  //Quick finish if no items installed
218  if(installList.isEmpty()){
219    ui->tree_install_apps->clear();
220  }else{
221    //Now make adjustments as necessary
222    for(int i=0; i<installList.length(); i++){
223      //Detemine what action should be done with this item location
224      int todo = 0; //0=insert new item, 1=update current item, 2=remove current item
225      if(i < cList.length()){
226        if(installList[i] == cList[i]){ todo=1; }
227        else if( installList.contains(cList[i]) && !cList.contains(installList[i]) ){ todo=0; } //new item to be inserted here
228        else if( !installList.contains(cList[i]) ){ todo=2; } //current item in this location should be removed
229      }
230      //Now perform the action on this location
231      if(todo==0){ 
232        //insert new item
233        QTreeWidgetItem *item = new QTreeWidgetItem; //create the item
234        item->setWhatsThis(0,installList[i]);
235        //Now format the display
236        formatInstalledItemDisplay(item);
237        if(item->text(0).isEmpty()){
238          //Do not put empty items into the display
239          delete item;
240        }else{
241          //Now insert this item onto the list
242          ui->tree_install_apps->insertTopLevelItem(i,item);
243          cList.insert(i,installList[i]); //reflect this inclusion into the current list
244        }
245      }else if(todo==1){
246        //Update current item
247        formatInstalledItemDisplay( ui->tree_install_apps->topLevelItem(i) );
248      }else{
249        //Remove current item
250        ui->tree_install_apps->takeTopLevelItem(i);
251        cList.removeAt(i); //reflect the change to the current list
252        i--; //Re-check the item that should be in this location
253      }
254    }
255    //Now makesure that there are no extra items at the end
256    int il = installList.length();
257    while(il < cList.length()){
258      ui->tree_install_apps->takeTopLevelItem(il);
259      cList.removeAt(il); //reflect the change to the current list
260    }
261  } //end of empty list check
262 
263  //Make sure that there is an item selected
264  if(ui->tree_install_apps->topLevelItemCount() > 0 ){
265    if( ui->tree_install_apps->selectedItems().isEmpty() ){
266      ui->tree_install_apps->setCurrentItem( ui->tree_install_apps->topLevelItem(0) );
267    }
268    //Now re-size the columns to the minimum required width
269    for(int i=0; i<3; i++){
270      ui->tree_install_apps->resizeColumnToContents(i);
271    } 
272  }
273  slotUpdateSelectedPBI();; //Update the info boxes
274  slotDisplayStats();
275}
276
277void MainUI::slotPBIStatusUpdate(QString pbiID){
278  for(int i=0; i<ui->tree_install_apps->topLevelItemCount(); i++){
279    QString itemID = ui->tree_install_apps->topLevelItem(i)->whatsThis(0);
280    if(itemID == pbiID){
281      QString stat = PBI->PBIInfo(pbiID,QStringList()<<"status").join("");
282      ui->tree_install_apps->topLevelItem(i)->setText(2,stat);
283      // See if we need to update the download progress bar
284      QString appID;
285      if(ui->tree_install_apps->topLevelItemCount() > 0){
286         appID = ui->tree_install_apps->currentItem()->whatsThis(0);
287      }
288      if ( appID == pbiID ) {
289        slotUpdateSelectedPBI(true);; //only update status
290      }
291      return; // Found our match, we can return now
292    }
293  }
294}
295
296void MainUI::on_group_install_showinfo_toggled(bool show){
297  if(ui->tree_install_apps->topLevelItemCount() > 0){
298    ui->group_install_info->setVisible(show);
299  }else{
300    ui->group_install_info->setVisible(FALSE);   
301  }
302}
303
304void MainUI::on_tool_install_gotobrowserpage_clicked(){
305  //When you want to open up the browser page for an application
306  QString appID = Extras::nameToID( ui->tree_install_apps->currentItem()->text(0) );
307  slotGoToApp(appID);
308}
309
310void MainUI::on_tool_install_toggleall_clicked(){
311  //Determine if the current item is checked or unchecked
312  bool checkall = (ui->tree_install_apps->currentItem()->checkState(0) == Qt::Unchecked);
313  for(int i=0; i<ui->tree_install_apps->topLevelItemCount(); i++){
314    if(checkall){ ui->tree_install_apps->topLevelItem(i)->setCheckState(0,Qt::Checked); }
315    else{ui->tree_install_apps->topLevelItem(i)->setCheckState(0,Qt::Unchecked); }
316  }
317}
318
319void MainUI::on_tree_install_apps_itemSelectionChanged(){
320  //When an installed PBI is clicked on
321  slotUpdateSelectedPBI();
322}
323
324void MainUI::on_check_install_autoupdate_clicked(){
325  //Get the current item
326  QString appID;
327  if(ui->tree_install_apps->topLevelItemCount() > 0){
328    appID = ui->tree_install_apps->currentItem()->whatsThis(0);
329  }
330  if(appID.isEmpty()){return;}
331  //Now determine the current state of the checkbox
332  bool enabled = ui->check_install_autoupdate->isChecked();
333  //Now have the backend make the change
334  PBI->enableAutoUpdate(appID, enabled);
335}
336
337void MainUI::on_tool_install_update_clicked(){
338  //Get the current item
339  QString appID;
340  if(ui->tree_install_apps->topLevelItemCount() > 0){
341    appID = ui->tree_install_apps->currentItem()->whatsThis(0);
342  }
343  if(appID.isEmpty()){return;}
344  PBI->upgradePBI(QStringList() << appID);
345}
346
347void MainUI::on_tool_install_remove_clicked(){
348  //Get the current item
349  QString appID;
350  if(ui->tree_install_apps->topLevelItemCount() > 0){
351    appID = ui->tree_install_apps->currentItem()->whatsThis(0);
352  }
353  if(appID.isEmpty()){return;}
354  //Verify removal
355  if( QMessageBox::Yes == QMessageBox::question(this,tr("Verify PBI Removal"), tr("Are you sure you wish to remove this application?")+"\n\n"+appID,QMessageBox::Yes | QMessageBox::Cancel,QMessageBox::Cancel) ){
356    PBI->removePBI(QStringList() << appID);
357  }
358}
359
360void MainUI::on_tool_install_cancel_clicked(){
361  //Get the current item
362  QString appID;
363  if(ui->tree_install_apps->topLevelItemCount() > 0){
364    appID = ui->tree_install_apps->currentItem()->whatsThis(0);
365  }
366  if(appID.isEmpty()){return;}
367  PBI->cancelActions(QStringList() << appID);
368 
369}
370
371// === SELECTED PBI ACTIONS ===
372void MainUI::slotActionAddDesktop(){
373  QStringList items = getCheckedItems();
374  PBI->addDesktopIcons(items,FALSE); //only for current user
375}
376
377void MainUI::slotActionRemoveDesktop(){
378  QStringList items = getCheckedItems();
379  PBI->rmDesktopIcons(items,FALSE);  //Only for current user
380}
381
382void MainUI::slotActionAddPath(){
383  QStringList items = getCheckedItems();
384  PBI->addPaths(items,FALSE);  //Only for current user 
385}
386
387void MainUI::slotActionRemovePath(){
388  QStringList items = getCheckedItems();
389  PBI->rmPaths(items,FALSE);  //Only for current user
390}
391
392void MainUI::slotActionAddPathAll(){
393  QStringList items = getCheckedItems();
394  PBI->addPaths(items,TRUE);  //For all users (root permissions required)
395}
396
397void MainUI::slotActionAddMenu(){
398  QStringList items = getCheckedItems();
399  PBI->addMenuIcons(items,FALSE);  //Only for current user
400}
401
402void MainUI::slotActionRemoveMenu(){
403  QStringList items = getCheckedItems();
404  PBI->rmMenuIcons(items,FALSE);  //Only for current user       
405}
406
407void MainUI::slotActionAddMenuAll(){
408  QStringList items = getCheckedItems();
409  PBI->addMenuIcons(items,TRUE);  //For all users (root permissions required)   
410}
411
412void MainUI::slotActionAddMime(){
413  QStringList items = getCheckedItems();
414  PBI->addMimeTypes(items,FALSE);  //Only for current user     
415}
416
417void MainUI::slotActionRemoveMime(){
418  QStringList items = getCheckedItems();
419  PBI->rmMimeTypes(items,FALSE);  //Only for current user       
420}
421
422void MainUI::slotActionAddMimeAll(){
423    QStringList items = getCheckedItems();
424  PBI->addMimeTypes(items,TRUE);  //For all users (root permissions required)   
425}
426
427void MainUI::slotActionUpdate(){
428  QStringList checkedID = getCheckedItems();
429  if(!checkedID.isEmpty()){
430    PBI->upgradePBI(checkedID); 
431  }
432}
433
434void MainUI::slotActionRemove(){
435  QStringList checkedID = getCheckedItems();
436  if(!checkedID.isEmpty()){
437    //Verify that the user really wants to remove these apps
438    if( QMessageBox::Yes == QMessageBox::question(this,tr("Verify PBI Removal"), tr("Are you sure you wish to remove these applications?")+"\n\n"+checkedID.join("\n"),QMessageBox::Yes | QMessageBox::Cancel,QMessageBox::Cancel) ){
439      PBI->removePBI(checkedID);
440    }
441  }
442}
443
444void MainUI::slotActionCancel(){
445  QStringList checkedID = getCheckedItems();
446  if(!checkedID.isEmpty()){
447    PBI->cancelActions(checkedID); 
448  }
449}
450
451void MainUI::slotStartApp(QAction* act){
452  qDebug() << "Starting external application:" << act->text();
453  //Get the command from the action
454  QString desktopfile = act->whatsThis();
455  QString cmd = "xdg-open "+desktopfile;
456  //Startup the command externally
457  QProcess::startDetached(cmd);
458}
459
460void MainUI::slotUpdateSelectedPBI(bool statusonly){
461  QString appID;
462  if(ui->tree_install_apps->topLevelItemCount() > 0){
463    appID = ui->tree_install_apps->currentItem()->whatsThis(0);
464  }
465  if(appID.isEmpty()){
466    ui->group_install_info->setVisible(FALSE);
467    return;
468  }else{
469    ui->group_install_info->setVisible( ui->group_install_showinfo->isChecked() );       
470  }
471  if(!statusonly){
472    //Get the PBI info for that item
473    QStringList vals; 
474    vals << "name" << "icon" << "author" << "website" << "version" << "license";
475    QStringList bools;
476    bools << "autoupdate" << "hasdesktopicons" << "hasmenuicons" << "requiresroot";
477    vals = PBI->PBIInfo(appID,vals);
478    bools = PBI->PBIInfo(appID,bools);
479    //Make sure the info lists are not empty
480    if(vals.isEmpty() || bools.isEmpty()){
481      ui->group_install_info->setVisible(FALSE);
482      return; 
483    }
484    //Load a default icon if none found
485    if(vals[1].isEmpty()){ vals[1] = defaultIcon; }
486    //Now set the info on the UI
487    bool desktopSC = (bools[1] == "true"); // XDG desktop entries available
488    bool menuSC= (bools[2] == "true");   // XDG menu entries available
489    bool autoupdate = (bools[0] == "true"); //auto-update enabled
490    bool rootonly = (bools[3] == "true"); //requires root
491    //Create the shortcuts string
492    QString shortcuts;
493      if(desktopSC && menuSC){ shortcuts = tr("Desktop/Menu"); }
494      else if(desktopSC){ shortcuts = tr("Desktop"); }
495      else if(menuSC){ shortcuts = tr("Menu"); }
496      else{ shortcuts = tr("None"); }
497    //Now display that info on the UI
498    ui->label_install_app->setText(vals[0]);
499    ui->label_install_icon->setPixmap( QPixmap(vals[1]) );
500    if(vals[3].isEmpty()){ 
501      ui->label_install_author->setText(vals[2]); 
502      ui->label_install_author->setToolTip("");
503    }else{ 
504      ui->label_install_author->setText("<a href="+vals[3]+">"+vals[2]+"</a>"); 
505      ui->label_install_author->setToolTip(vals[3]); //show website URL as tooltip
506    }
507    ui->label_install_license->setText(vals[5]);
508    ui->label_install_version->setText(vals[4]);
509    ui->label_install_shortcuts->setText(shortcuts);
510    ui->check_install_autoupdate->setChecked(autoupdate);
511 
512    //Adjust the quick action buttons as necessary
513    if( PBI->isWorking(appID) ){
514      //Actions pending/working only show cancel button
515      ui->tool_install_cancel->setVisible(TRUE);
516      ui->tool_install_remove->setVisible(FALSE);
517      ui->tool_install_update->setVisible(FALSE);
518      ui->tool_install_startApp->setVisible(FALSE);
519    }else{
520      //Nothing pending
521      ui->tool_install_cancel->setVisible(FALSE);
522      if( !PBI->isInstalled(appID).isEmpty() ){ 
523        //Remove Button
524        ui->tool_install_remove->setVisible(TRUE);
525        if(rootonly){ ui->tool_install_remove->setIcon(QIcon(":icons/remove-root.png")); }
526        else{ ui->tool_install_remove->setIcon(QIcon(":icons/remove.png")); }
527        //Update
528        if(PBI->upgradeAvailable(appID).isEmpty()){ ui->tool_install_update->setVisible(FALSE); }
529        else{
530          ui->tool_install_update->setVisible(TRUE); 
531          if(rootonly){ ui->tool_install_update->setIcon(QIcon(":icons/app_upgrade_small-root.png")); }
532          else{ ui->tool_install_update->setIcon(QIcon(":icons/app_upgrade_small.png")); }
533        }
534        //Start Application binaries
535        QStringList bins = PBI->pbiBinList(appID);
536        appBinMenu->clear();
537        for(int i=0; i<bins.length(); i++){
538          QAction *act = new QAction(this);
539            act->setText(bins[i].section("::::",0,0)); //set name
540            act->setWhatsThis(bins[i].section("::::",1,10)); //set command string
541          appBinMenu->addAction(act);
542        }
543        if(appBinMenu->isEmpty()){ ui->tool_install_startApp->setVisible(FALSE); }
544        else{ ui->tool_install_startApp->setVisible(TRUE); }
545      }else{ 
546        ui->tool_install_remove->setVisible(FALSE); 
547        ui->tool_install_update->setVisible(FALSE); 
548        ui->tool_install_startApp->setVisible(FALSE);
549      }   
550    }
551  }
552  //Update the current status indicators
553  QString stat = PBI->currentAppStatus(appID,true); //get the raw status
554  if(stat.isEmpty() || stat == "DLSTART"  || stat == "DLDONE"){
555    //Not currently running - hide the display indicators
556    ui->group_install_appStat->setVisible(FALSE);
557  }else if(stat.startsWith("DLSTAT::")){
558    //Currently downloading - show download status indicators
559    QString percent = stat.section("::",1,1);
560    QString total = stat.section("::",2,2);
561    QString speed = stat.section("::",3,3);
562    ui->group_install_appStat->setVisible(TRUE);
563      ui->progress_install_DL->setVisible(TRUE);
564    if(total == "??"){ ui->label_install_status->setText( tr("Downloading file:") ); }
565    else{ ui->label_install_status->setText( QString(tr("Downloading %1 file:")).arg(total) ); }
566    if(percent == "??"){
567      ui->progress_install_DL->setMinimum(0); ui->progress_install_DL->setMaximum(0);
568    }else{
569      ui->progress_install_DL->setMinimum(0); ui->progress_install_DL->setMaximum(100);
570      ui->progress_install_DL->setValue( int(percent.toFloat()) );
571    }
572    if(speed == "??"){ ui->label_install_DL->setVisible(FALSE); }
573    else{
574      ui->label_install_DL->setVisible(TRUE);
575      ui->label_install_DL->setText(speed);
576    }
577  }else{
578    //Currently installing/removing/updating - show last message from process
579    ui->label_install_status->setText(stat);
580    ui->group_install_appStat->setVisible(TRUE);
581      ui->progress_install_DL->setVisible(FALSE);
582      ui->label_install_DL->setVisible(FALSE);
583  }
584}
585
586// ==========================
587// ====== BROWSER TAB =======
588// ==========================
589void MainUI::initializeBrowserTab(){
590  ui->tab_browse->setEnabled(FALSE);
591  //Always make sure that the browser starts off on the "home" page
592  ui->stacked_browser->setCurrentWidget(ui->page_home);
593  //With invisible shortcut buttons
594  ui->tool_browse_cat->setVisible(FALSE);
595  ui->tool_browse_app->setVisible(FALSE);
596  //Clear any items left over from the designer form
597  clearScrollArea(ui->scroll_br_home_newapps);
598  clearScrollArea(ui->scroll_br_home_cats);
599  //Search functionality
600  searchTimer = new QTimer();
601    searchTimer->setSingleShot(TRUE);
602    searchTimer->setInterval(300); // 0.3 sec wait before a search
603    connect(searchTimer,SIGNAL(timeout()),this,SLOT(slotGoToSearch()) );
604  connect(ui->tool_browse_search,SIGNAL(clicked()),this,SLOT(slotGoToSearch()) );
605  connect(ui->line_browse_searchbar,SIGNAL(returnPressed()),this,SLOT(slotGoToSearch()) );
606}
607
608// === SLOTS ===
609void MainUI::slotDisableBrowser(bool shownotification){
610  if(shownotification){ qDebug() << "No Repo Available: De-activating the Browser"; }
611  ui->tabWidget->setCurrentWidget(ui->tab_installed);
612  ui->tool_install_gotobrowserpage->setEnabled(FALSE);
613  ui->tab_browse->setEnabled(FALSE);
614  slotDisplayStats();
615}
616
617void MainUI::slotEnableBrowser(){
618  qDebug() << "Repo Ready: - generating browser home page";
619  //Now create the browser home page
620  slotUpdateBrowserHome();
621  //And allow the user to go there
622  ui->tool_install_gotobrowserpage->setEnabled(TRUE);
623  ui->tab_browse->setEnabled(TRUE);
624  slotDisplayStats();
625}
626
627void MainUI::slotUpdateBrowserHome(){
628  //Load the Categories
629  QStringList cats = PBI->browserCategories();
630  clearScrollArea(ui->scroll_br_home_cats);
631  QVBoxLayout *catlayout = new QVBoxLayout;
632  QStringList info; info << "name" << "description" << "icon";
633  cats.sort(); //sort them alphabetically
634  for(int i=0; i<cats.length(); i++){
635    QStringList data = PBI->CatInfo(cats[i],info);
636    if(!data.isEmpty()){
637      LargeItemWidget *item = new LargeItemWidget(cats[i],data[0],data[1],data[2]);
638      connect(item,SIGNAL(appClicked(QString)),this,SLOT(slotGoToCategory(QString)) );
639      catlayout->addWidget(item);
640    }
641  }
642  catlayout->addStretch(); //add a spacer to the end
643  ui->scroll_br_home_cats->widget()->setLayout(catlayout);
644  //Load the newest applications
645  clearScrollArea(ui->scroll_br_home_newapps);
646  QHBoxLayout *newapplayout = new QHBoxLayout;
647  QStringList newapps = PBI->getRecentApps();
648  for(int i=0; i<newapps.length(); i++){
649    QStringList appdata = PBI->AppInfo(newapps[i],QStringList() << "name" << "icon" << "latestversion");
650    if(!appdata.isEmpty()){
651      SmallItemWidget *item = new SmallItemWidget(newapps[i],appdata[0],appdata[1],appdata[2]);
652      connect(item,SIGNAL(appClicked(QString)),this,SLOT(slotGoToApp(QString)) );
653      newapplayout->addWidget(item);
654    }
655  }
656  newapplayout->addStretch(); //add a spacer to the end
657  newapplayout->setContentsMargins(0,0,0,0);
658  newapplayout->setSpacing(0);
659  ui->scroll_br_home_newapps->widget()->setLayout(newapplayout);
660  //Make sure that the newapps scrollarea is the proper fit vertically (no vertical scrolling)
661  ui->scroll_br_home_newapps->setMinimumHeight(ui->scroll_br_home_newapps->widget()->minimumSizeHint().height()+ui->scroll_br_home_newapps->horizontalScrollBar()->height());
662 
663  //Make sure the new apps area is invisible if no items available
664  if(newapps.isEmpty()){ ui->group_br_home_newapps->setVisible(FALSE); }
665  else{ ui->group_br_home_newapps->setVisible(TRUE); }
666  //make sure the home page is visible in the browser (slotGoToHome without changing tabs)
667  ui->stacked_browser->setCurrentWidget(ui->page_home); 
668  //Make sure the shortcut buttons are disabled
669  ui->tool_browse_cat->setVisible(FALSE);
670  ui->tool_browse_app->setVisible(FALSE); 
671 
672}
673
674void MainUI::slotGoToHome(){
675  ui->tabWidget->setCurrentWidget(ui->tab_browse);
676  ui->stacked_browser->setCurrentWidget(ui->page_home); 
677  //Make sure the shortcut buttons are disabled
678  ui->tool_browse_cat->setVisible(FALSE);
679  ui->tool_browse_app->setVisible(FALSE);
680}
681
682void MainUI::slotGoToCategory(QString cat){
683  qDebug() << "Show Category:" << cat;
684  //Get the apps in this category
685  QStringList apps = PBI->browserApps(cat);
686  if(apps.isEmpty()){
687    qDebug() << "Invalid category:" << cat;
688    return;
689  }
690  clearScrollArea(ui->scroll_br_cat_apps);
691  apps.sort();
692  QVBoxLayout *applayout = new QVBoxLayout;
693  QStringList info; info << "name" << "description" << "icon";
694  for(int i=0; i<apps.length(); i++){
695    QStringList data = PBI->AppInfo(apps[i],info);
696    if(!data.isEmpty()){
697      //Trim the description if necessary
698      if(data[1].size()>100){ data[1] = data[1].left(100).append("..."); }
699      LargeItemWidget *item = new LargeItemWidget(apps[i],data[0],data[1],data[2]);
700      connect(item,SIGNAL(appClicked(QString)),this,SLOT(slotGoToApp(QString)) );
701      applayout->addWidget(item); 
702    }
703  }
704  applayout->addStretch();
705  ui->scroll_br_cat_apps->widget()->setLayout(applayout);
706  //Now enable/disable the shortcut buttons
707  ui->tool_browse_app->setVisible(FALSE);
708  ui->tool_browse_cat->setVisible(TRUE);
709    QStringList catinfo = PBI->CatInfo(cat,QStringList() << "name" << "icon");
710    ui->tool_browse_cat->setText(catinfo[0]);
711    if(catinfo[1].isEmpty()){ catinfo[1] = defaultIcon; }
712    ui->tool_browse_cat->setIcon(QIcon(catinfo[1]));
713  ui->tabWidget->setCurrentWidget(ui->tab_browse);
714  ui->stacked_browser->setCurrentWidget(ui->page_cat);
715  //Now save that this category is currently displayed
716  cCat = cat;
717}
718
719void MainUI::slotGoToApp(QString appID){
720  qDebug() << "Show App:" << appID;
721  //Get the general application info
722  QStringList data; 
723  data << "name" << "icon" << "author" << "website" << "license" << "type" << "description" \
724       << "category" << "requiresroot" << "latestversion" << "latestarch" <<"latestsize" \
725       << "backupversion" << "backuparch" << "backupsize";
726  data = PBI->AppInfo(appID,data);
727  if(data.isEmpty()){
728    qDebug() << "Invalid App:" << appID;
729    return;
730  }
731  //Start the search for similar apps
732  PBI->searchSimilar = appID;
733  ui->group_bapp_similar->setVisible(FALSE);
734  QTimer::singleShot(0,PBI,SLOT(startSimilarSearch()));
735  //Now Check icon
736  if(data[1].isEmpty()){ data[1] = defaultIcon; }
737  //Now fill the UI with the data
738  ui->label_bapp_name->setText(data[0]);
739  ui->label_bapp_icon->setPixmap(QPixmap(data[1]));
740  if(data[3].isEmpty()){ ui->label_bapp_authorweb->setText(data[2]); }
741  else{ ui->label_bapp_authorweb->setText("<a href="+data[3]+">"+data[2]+"</a>"); }
742  ui->label_bapp_authorweb->setToolTip(data[3]);
743  ui->label_bapp_license->setText(data[4]);
744  ui->label_bapp_type->setText(data[5]);
745  ui->text_bapp_description->setText(data[6]);
746  //Now determine the appropriate version info
747  QString pbiID = PBI->isInstalled(appID); //get pbiID
748  QString cVer;
749  if(!pbiID.isEmpty()){ cVer = PBI->PBIInfo(pbiID,QStringList("version")).join(""); }
750  bool useLatest=FALSE;
751  bool nobackup = data[12].isEmpty();
752  if(cVer.isEmpty()){ useLatest=TRUE; } //not currently installed
753  else if(cVer != data[9]){ useLatest=TRUE;} //not the latest version
754  //Now put the proper version info on the UI
755  if(useLatest || nobackup){
756    ui->label_bapp_version->setText(data[9]);
757    ui->label_bapp_arch->setText(data[10]);
758    if(data[11].isEmpty()){ ui->label_bapp_size->setText(tr("Unknown")); }
759    else{ ui->label_bapp_size->setText( Extras::sizeKToDisplay(data[11]) ); }
760  }else{
761    ui->label_bapp_version->setText(data[12]);
762    ui->label_bapp_arch->setText(data[13]);
763    if(data[14].isEmpty()){ ui->label_bapp_size->setText(tr("Unknown")); }
764    else{ ui->label_bapp_size->setText( Extras::sizeKToDisplay(data[14]) ); }
765  }
766  //Now update the download button appropriately
767  QString ico;
768  QString working = PBI->currentAppStatus(appID);
769  if(!working.isEmpty()){ //app currently pending or actually doing something
770    ui->tool_bapp_download->setText(working);
771    ui->tool_bapp_download->setIcon(QIcon(":icons/working.png"));
772    ui->tool_bapp_download->setEnabled(FALSE);
773  }else if(useLatest && cVer.isEmpty()){ //new installation
774    ui->tool_bapp_download->setText(tr("Install Now!"));
775    ico = ":icons/app_download.png";
776    ui->tool_bapp_download->setEnabled(TRUE);
777  }else if(useLatest){ //Update available
778    ui->tool_bapp_download->setText(tr("Update"));
779    ico = ":icons/app_upgrade.png";
780    ui->tool_bapp_download->setEnabled(TRUE);
781  }else if(!nobackup){  //Downgrade available
782    ui->tool_bapp_download->setText(tr("Downgrade"));
783    ico = ":icons/app_downgrade.png";
784    ui->tool_bapp_download->setEnabled(TRUE);
785  }else{ //already installed (no downgrade available)
786    ui->tool_bapp_download->setText(tr("Installed"));
787    ui->tool_bapp_download->setIcon(QIcon(":icons/dialog-ok.png"));
788    ui->tool_bapp_download->setEnabled(FALSE);
789  }
790  //Now set the icon appropriately if it requires root permissions
791  if(!ico.isEmpty()){
792    if(data[8]=="true"){ //requires root permissions to install
793      ico.replace(".png","-root.png");
794    }
795    ui->tool_bapp_download->setIcon(QIcon(ico));
796  }
797  ui->tool_bapp_download->setWhatsThis(appID); //set for slot
798  //Now enable/disable the shortcut buttons
799  ui->tool_browse_app->setVisible(TRUE);
800    ui->tool_browse_app->setText(data[0]);
801    ui->tool_browse_app->setIcon(QIcon(data[1]));
802  QStringList catinfo = PBI->CatInfo(Extras::nameToID(data[7]),QStringList() << "name" << "icon");
803  if(!catinfo.isEmpty()){
804    ui->tool_browse_cat->setVisible(TRUE);
805    ui->tool_browse_cat->setText(catinfo[0]);
806    if(catinfo[1].isEmpty()){ catinfo[1] = defaultIcon; }
807    ui->tool_browse_cat->setIcon(QIcon(catinfo[1]));
808  }
809  ui->tabWidget->setCurrentWidget(ui->tab_browse);
810  ui->stacked_browser->setCurrentWidget(ui->page_app);
811       
812}
813
814void MainUI::slotGoToSearch(){
815  searchTimer->stop(); //just in case "return" was pressed to start the search
816  QString search = ui->line_browse_searchbar->text();
817  if(search.isEmpty()){ return; }
818  PBI->searchTerm = search;
819  QTimer::singleShot(1,PBI,SLOT(startAppSearch()));
820  ui->label_bsearch_info->setText( tr("Searching the application database. Please Wait....") );
821    ui->label_bsearch_info->setVisible(TRUE);
822    ui->group_bsearch_best->setVisible(FALSE);
823    ui->group_bsearch_other->setVisible(FALSE);
824 
825}
826       
827void MainUI::slotShowSimilarApps(QStringList apps){
828  qDebug() << " - Similar applications:" << apps;
829  if(apps.isEmpty()){ ui->group_bapp_similar->setVisible(FALSE); }
830  else{
831    clearScrollArea(ui->scroll_bapp_similar);
832    QHBoxLayout *layout = new QHBoxLayout;
833    for(int i=0; i<apps.length(); i++){
834      QStringList appdata = PBI->AppInfo(apps[i],QStringList() << "name" << "icon");
835      if(!appdata.isEmpty()){
836        SmallItemWidget *item = new SmallItemWidget(apps[i],appdata[0],appdata[1],"");
837        connect(item,SIGNAL(appClicked(QString)),this,SLOT(slotGoToApp(QString)) );
838        layout->addWidget(item);
839      }
840    }
841    layout->addStretch(); //add a spacer to the end
842    layout->setContentsMargins(1,1,1,1);
843    ui->scroll_bapp_similar->widget()->setLayout(layout);
844    //Make sure that the similar scrollarea is the proper fit vertically (no vertical scrolling)
845    ui->scroll_bapp_similar->setMinimumHeight(ui->scroll_bapp_similar->widget()->minimumSizeHint().height()+ui->scroll_bapp_similar->horizontalScrollBar()->height());
846    //Now make the group visible as appropriate
847    ui->group_bapp_similar->setVisible(TRUE);
848    if(ui->group_bapp_similar->isChecked()){ ui->scroll_bapp_similar->setVisible(TRUE); }
849    else{ ui->scroll_bapp_similar->setVisible(FALSE); }
850    //Now make sure the app page has the proper layout dimensions
851    ui->page_app->updateGeometry();
852  }
853}
854
855void MainUI::slotShowSearchResults(QStringList best, QStringList rest){
856  //Now display the search results
857  if(best.isEmpty()){
858    ui->label_bsearch_info->setText( QString(tr("No Search Results Found for the term: %1")).arg(ui->line_browse_searchbar->text()) );
859    ui->label_bsearch_info->setVisible(TRUE);
860    ui->group_bsearch_best->setVisible(FALSE);
861    ui->group_bsearch_other->setVisible(FALSE);
862  }else{
863    ui->label_bsearch_info->setVisible(FALSE);
864    //Now fill the "best" section
865    clearScrollArea(ui->scroll_bsearch_best);
866    QVBoxLayout *layout = new QVBoxLayout;
867    QStringList info; info << "name" << "description" << "icon";
868    for(int i=0; i<best.length(); i++){
869      QStringList data = PBI->AppInfo(best[i],info);
870      if(!data.isEmpty()){
871        //Trim the description if necessary
872        if(data[1].size()>100){ data[1] = data[1].left(100).append("..."); }
873        LargeItemWidget *item = new LargeItemWidget(best[i],data[0],data[1],data[2]);
874        connect(item,SIGNAL(appClicked(QString)),this,SLOT(slotGoToApp(QString)) );
875        layout->addWidget(item); 
876      }
877    }
878    layout->addStretch();
879    ui->scroll_bsearch_best->widget()->setLayout(layout);
880    ui->group_bsearch_best->setVisible(TRUE);
881   
882    //Now fill the other results
883    if(rest.isEmpty()){ ui->group_bsearch_other->setVisible(FALSE); }
884    else{
885      ui->group_bsearch_other->setVisible(TRUE);
886      clearScrollArea(ui->scroll_bsearch_other);
887      QVBoxLayout *layout2 = new QVBoxLayout;
888      for(int i=0; i<rest.length(); i++){
889        QStringList data = PBI->AppInfo(rest[i],info);
890        if(!data.isEmpty()){
891          //Trim the description if necessary
892          if(data[1].size()>100){ data[1] = data[1].left(100).append("..."); }
893          LargeItemWidget *item = new LargeItemWidget(rest[i],data[0],data[1],data[2]);
894          connect(item,SIGNAL(appClicked(QString)),this,SLOT(slotGoToApp(QString)) );
895          layout2->addWidget(item); 
896        }
897      }
898      layout2->addStretch();
899      ui->scroll_bsearch_other->widget()->setLayout(layout2);
900    }
901  }
902       
903  //need to make sure the search bar still has keyboard focus (just in case)
904  ui->tabWidget->setCurrentWidget(ui->tab_browse);
905  ui->stacked_browser->setCurrentWidget(ui->page_search);
906 
907}
908
909void MainUI::on_tabWidget_currentChanged(){
910  if(ui->tabWidget->currentWidget() == ui->tab_browse){
911    //Refresh the app page if that is the one currently showing
912    if(ui->stacked_browser->currentWidget() == ui->page_app){ on_tool_browse_app_clicked(); }     
913  }
914}
915
916void MainUI::on_tool_browse_home_clicked(){
917  slotGoToHome();
918}
919
920void MainUI::on_tool_browse_cat_clicked(){
921  QString cat = Extras::nameToID(ui->tool_browse_cat->text());
922  if(cCat == cat){ //already loaded - just show it (prevents resetting scroll positions)
923    ui->stacked_browser->setCurrentWidget(ui->page_cat);
924  }else{ //load and show the category
925    slotGoToCategory(cat);
926  }
927}
928
929void MainUI::on_tool_browse_app_clicked(){
930  QString appID = Extras::nameToID(ui->tool_browse_app->text());
931  slotGoToApp(appID);
932}
933
934void MainUI::on_line_browse_searchbar_textChanged(){
935  //Connect this to a singleshot timer, so the search functionality is only
936  //  run once after a short wait rather than every time a new character is typed
937 
938  //Live search only after 3 characters have been typed
939  if(ui->line_browse_searchbar->text().length() > 2){
940    searchTimer->start();
941  }else{
942    searchTimer->stop();         
943  }
944}
945
946void MainUI::on_tool_bapp_download_clicked(){
947  QString appID = ui->tool_bapp_download->whatsThis();
948  //Verify the app installation
949  if( QMessageBox::Yes != QMessageBox::question(this,tr("Verify Installation"), tr("Are you sure you want to install this application?")+"\n\n"+appID,QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)){
950    return;
951  }
952  PBI->installApp(QStringList() << appID);
953  ui->tool_bapp_download->setEnabled(FALSE); //make sure it cannot be clicked more than once before page refresh
954  //Now show the Installed tab
955  ui->tabWidget->setCurrentWidget(ui->tab_installed);
956}
957
958void MainUI::on_group_br_home_newapps_toggled(bool show){
959  ui->scroll_br_home_newapps->setVisible(show);
960}
961
962void MainUI::on_group_bapp_similar_toggled(bool show){
963  ui->scroll_bapp_similar->setVisible(show);
964}
965
966// ================================
967// ==========  OTHER ==============
968// ================================
969void MainUI::clearScrollArea(QScrollArea* area){
970  QWidget *wgt = area->takeWidget();
971  delete wgt; //delete the widget and all children
972  area->setWidget( new QWidget() ); //create a new widget in the scroll area
973  area->widget()->setContentsMargins(0,0,0,0);
974}
975
976void MainUI::slotDisplayError(QString title,QString message,QStringList log){
977  QMessageBox *dlg = new QMessageBox(this);
978    dlg->setWindowTitle(title);
979    dlg->setText(message);
980    dlg->setDetailedText(log.join("\n"));
981  dlg->exec();
982}
983
984void MainUI::slotDisplayStats(){
985  int avail = PBI->numAvailable;
986  int installed = PBI->numInstalled;
987  QString text;
988  if(avail == -1){
989    text = QString(tr("Installed: %1")).arg(QString::number(installed)); 
990  }else{
991    text = QString(tr("Installed: %1")+"\t"+tr("Available: %2")).arg(QString::number(installed), QString::number(avail)); 
992  }
993  //Get the number of installed/available applications and display it
994  statusLabel->setText(text);   
995}
Note: See TracBrowser for help on using the repository browser.