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

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

Update the AppCafe? Installed tab to take advantage of the new info available for 10.x PBI's.
Changes Include:
1) Move currently installed app info to a seperate page, that can be opened by either double-clicking on an installed application or clicking the "details" button at the bottom of the main page.
2) Update the "actions" button to be actively enabled/disabled depending on whether any items are currently checked.
3) Add ability to start composing an email (in the DE's default email client) to the port maintainer for an installed PBI. This email template also includes all the important info regarding the PBI in question (build date, architecture, FreeBSD version, version number).
4) Fix a bug with setting/unsetting the "auto-update" status for a PBI.
5) Clean up application descriptions a bit better now (affects both installed and browser tabs).

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