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

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

Add a bunch of error loggin to the backend processes, and also add a new dialog for displaying these error logs. Also fix the detection of an update failure.

  • Property mode set to 100644
File size: 37.3 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("Upgrade"), 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    //Now setup the action button
155    ui->tool_install_performaction->setMenu(actionMenu);
156    ui->tool_install_performaction->setPopupMode(QToolButton::InstantPopup);
157    //Now setup any defaults for the installed tab
158    ui->tool_install_gotobrowserpage->setEnabled(FALSE); //disable it until the browser is ready
159    ui->tree_install_apps->setIconSize(QSize(22,22));
160    slotRefreshInstallTab();
161}
162
163void MainUI::formatInstalledItemDisplay(QTreeWidgetItem *item){
164  //simplification function for filling the tree widget item with the appropriate information about the PBI
165  QString ID = item->whatsThis(0);
166  if(item->text(0).isEmpty()){  //new entry - get everything
167    QStringList vals; vals <<"name"<<"version"<<"status"; //same as column order
168    if(!vals.isEmpty()){
169      vals = PBI->PBIInfo(ID, vals);
170      for(int i=0; i<vals.length(); i++){ item->setText(i,vals[i]); }
171      QString icon = PBI->PBIInfo(ID, QStringList("icon")).join("");
172        //Load a default icon if none found
173      if(icon.isEmpty()){ icon = defaultIcon; }
174      item->setIcon(0,QIcon(icon) );
175      item->setCheckState(0,Qt::Unchecked);
176    }
177  }else{ // Just update the necesary info
178    QStringList vals; vals << "version" << "status";
179    vals = PBI->PBIInfo(ID,vals);
180    if(!vals.isEmpty()){ item->setText(1,vals[0]); item->setText(2,vals[1]); }
181  }
182}
183
184QStringList MainUI::getCheckedItems(){
185  //Return the pbiID's of all the checked items
186  QStringList output;
187  for(int i=0; i<ui->tree_install_apps->topLevelItemCount(); i++){
188    if(ui->tree_install_apps->topLevelItem(i)->checkState(0) == Qt::Checked){
189      output << ui->tree_install_apps->topLevelItem(i)->whatsThis(0);
190    }
191  }
192  //If no items checked, use the item that is selected instead
193  if(output.isEmpty()){
194    //Make sure that an item is selected
195    if(ui->tree_install_apps->topLevelItemCount() >0){
196      output << ui->tree_install_apps->currentItem()->whatsThis(0); 
197    }
198  }
199  return output;       
200}
201
202// === SLOTS ===
203void MainUI::slotRefreshInstallTab(){
204  //Update the list of installed PBI's w/o clearing the list (loses selections)
205   //Get the list we need (in order)
206  QStringList installList = PBI->installedList();
207  installList.sort(); //sort in ascending order
208   //Get the list we have now
209  QStringList cList;
210  for(int i=0; i<ui->tree_install_apps->topLevelItemCount(); i++){
211    cList << ui->tree_install_apps->topLevelItem(i)->whatsThis(0);
212  }
213  //Quick finish if no items installed
214  if(installList.isEmpty()){
215    ui->tree_install_apps->clear();
216  }else{
217    //Now make adjustments as necessary
218    for(int i=0; i<installList.length(); i++){
219      //Detemine what action should be done with this item location
220      int todo = 0; //0=insert new item, 1=update current item, 2=remove current item
221      if(i < cList.length()){
222        if(installList[i] == cList[i]){ todo=1; }
223        else if( installList.contains(cList[i]) && !cList.contains(installList[i]) ){ todo=0; } //new item to be inserted here
224        else if( !installList.contains(cList[i]) ){ todo=2; } //current item in this location should be removed
225      }
226      //Now perform the action on this location
227      if(todo==0){ 
228        //insert new item
229        QTreeWidgetItem *item = new QTreeWidgetItem; //create the item
230        item->setWhatsThis(0,installList[i]);
231        //Now format the display
232        formatInstalledItemDisplay(item);
233        //Now insert this item onto the list
234        ui->tree_install_apps->insertTopLevelItem(i,item);
235        cList.insert(i,installList[i]); //reflect this inclusion into the current list
236      }else if(todo==1){
237        //Update current item
238        formatInstalledItemDisplay( ui->tree_install_apps->topLevelItem(i) );
239      }else{
240        //Remove current item
241        ui->tree_install_apps->takeTopLevelItem(i);
242        cList.removeAt(i); //reflect the change to the current list
243        i--; //Re-check the item that should be in this location
244      }
245    }
246    //Now makesure that there are no extra items at the end
247    int il = installList.length();
248    while(il < cList.length()){
249      ui->tree_install_apps->takeTopLevelItem(il);
250      cList.removeAt(il); //reflect the change to the current list
251    }
252  } //end of empty list check
253 
254  //Make sure that there is an item selected
255  if(ui->tree_install_apps->topLevelItemCount() > 0 ){
256    if( ui->tree_install_apps->selectedItems().isEmpty() ){
257      ui->tree_install_apps->setCurrentItem( ui->tree_install_apps->topLevelItem(0) );
258    }
259    //Now re-size the columns to the minimum required width
260    for(int i=0; i<3; i++){
261      ui->tree_install_apps->resizeColumnToContents(i);
262    } 
263  }
264  on_tree_install_apps_itemSelectionChanged(); //Update the info boxes
265  slotDisplayStats();
266}
267void MainUI::slotPBIStatusUpdate(QString pbiID){
268  for(int i=0; i<ui->tree_install_apps->topLevelItemCount(); i++){
269    QString itemID = ui->tree_install_apps->topLevelItem(i)->whatsThis(0);
270    if(itemID == pbiID){
271      QString stat = PBI->PBIInfo(pbiID,QStringList()<<"status").join("");
272      ui->tree_install_apps->topLevelItem(i)->setText(2,stat);
273    }
274  }
275}
276
277void MainUI::on_group_install_showinfo_toggled(bool show){
278  if(ui->tree_install_apps->topLevelItemCount() > 0){
279    ui->group_install_info->setVisible(show);
280  }else{
281    ui->group_install_info->setVisible(FALSE);   
282  }
283}
284
285void MainUI::on_tool_install_gotobrowserpage_clicked(){
286  //When you want to open up the browser page for an application
287  QString appID = Extras::nameToID( ui->tree_install_apps->currentItem()->text(0) );
288  slotGoToApp(appID);
289}
290
291void MainUI::on_tool_install_toggleall_clicked(){
292  //Determine if the current item is checked or unchecked
293  bool checkall = (ui->tree_install_apps->currentItem()->checkState(0) == Qt::Unchecked);
294  for(int i=0; i<ui->tree_install_apps->topLevelItemCount(); i++){
295    if(checkall){ ui->tree_install_apps->topLevelItem(i)->setCheckState(0,Qt::Checked); }
296    else{ui->tree_install_apps->topLevelItem(i)->setCheckState(0,Qt::Unchecked); }
297  }
298}
299
300void MainUI::on_tree_install_apps_itemSelectionChanged(){
301  //When an installed PBI is clicked on
302  QString appID;
303  if(ui->tree_install_apps->topLevelItemCount() > 0){
304    appID = ui->tree_install_apps->currentItem()->whatsThis(0);
305  }
306  if(appID.isEmpty()){
307    ui->group_install_info->setVisible(FALSE);
308    return;
309  }else{
310    ui->group_install_info->setVisible( ui->group_install_showinfo->isChecked() );       
311  }
312  //Get the PBI info for that item
313  QStringList vals; 
314  vals << "name" << "icon" << "author" << "website" << "version" << "license";
315  QStringList bools;
316  bools << "autoupdate" << "hasdesktopicons" << "hasmenuicons" << "requiresroot";
317  vals = PBI->PBIInfo(appID,vals);
318  bools = PBI->PBIInfo(appID,bools);
319  //Make sure the info lists are not empty
320  if(vals.isEmpty() || bools.isEmpty()){
321    ui->group_install_info->setVisible(FALSE);
322    return; 
323  }
324  //Load a default icon if none found
325  if(vals[1].isEmpty()){ vals[1] = defaultIcon; }
326  //Now set the info on the UI
327  bool desktopSC = (bools[1] == "true"); // XDG desktop entries available
328  bool menuSC= (bools[2] == "true");     // XDG menu entries available
329  bool autoupdate = (bools[0] == "true"); //auto-update enabled
330  bool rootonly = (bools[3] == "true"); //requires root
331  //Create the shortcuts string
332  QString shortcuts;
333    if(desktopSC && menuSC){ shortcuts = tr("Desktop/Menu"); }
334    else if(desktopSC){ shortcuts = tr("Desktop"); }
335    else if(menuSC){ shortcuts = tr("Menu"); }
336    else{ shortcuts = tr("None"); }
337  //Now display that info on the UI
338  ui->label_install_app->setText(vals[0]);
339  ui->label_install_icon->setPixmap( QPixmap(vals[1]) );
340  if(vals[3].isEmpty()){ 
341    ui->label_install_author->setText(vals[2]); 
342    ui->label_install_author->setToolTip("");
343  }else{ 
344    ui->label_install_author->setText("<a href="+vals[3]+">"+vals[2]+"</a>"); 
345    ui->label_install_author->setToolTip(vals[3]); //show website URL as tooltip
346  }
347  ui->label_install_license->setText(vals[5]);
348  ui->label_install_version->setText(vals[4]);
349  ui->label_install_shortcuts->setText(shortcuts);
350  ui->check_install_autoupdate->setChecked(autoupdate);
351 
352  //Adjust the quick action buttons as necessary
353  if(!PBI->currentAppStatus(appID).isEmpty()){
354    //Actions pending/working only show cancel button
355    ui->tool_install_cancel->setVisible(TRUE);
356    ui->tool_install_remove->setVisible(FALSE);
357    ui->tool_install_update->setVisible(FALSE);
358  }else{
359    //Nothing pending
360    ui->tool_install_cancel->setVisible(FALSE);
361    if( !PBI->isInstalled(appID).isEmpty() ){ 
362      //Remove Button
363      ui->tool_install_remove->setVisible(TRUE);
364      if(rootonly){ ui->tool_install_remove->setIcon(QIcon(":icons/remove-root.png")); }
365      else{ ui->tool_install_remove->setIcon(QIcon(":icons/remove.png")); }
366      //Upgrade button
367      if(PBI->upgradeAvailable(appID).isEmpty()){ ui->tool_install_update->setVisible(FALSE); }
368      else{
369        ui->tool_install_update->setVisible(TRUE); 
370        if(rootonly){ ui->tool_install_update->setIcon(QIcon(":icons/app_upgrade_small-root.png")); }
371        else{ ui->tool_install_update->setIcon(QIcon(":icons/app_upgrade_small.png")); }
372      }
373    }else{ 
374      ui->tool_install_remove->setVisible(FALSE); 
375      ui->tool_install_update->setVisible(FALSE); 
376    }   
377  }
378 
379}
380
381void MainUI::on_check_install_autoupdate_clicked(){
382  //Get the current item
383  QString appID;
384  if(ui->tree_install_apps->topLevelItemCount() > 0){
385    appID = ui->tree_install_apps->currentItem()->whatsThis(0);
386  }
387  if(appID.isEmpty()){return;}
388  //Now determine the current state of the checkbox
389  bool enabled = ui->check_install_autoupdate->isChecked();
390  //Now have the backend make the change
391  PBI->enableAutoUpdate(appID, enabled);
392}
393
394void MainUI::on_tool_install_update_clicked(){
395  //Get the current item
396  QString appID;
397  if(ui->tree_install_apps->topLevelItemCount() > 0){
398    appID = ui->tree_install_apps->currentItem()->whatsThis(0);
399  }
400  if(appID.isEmpty()){return;}
401  PBI->upgradePBI(QStringList() << appID);
402}
403
404void MainUI::on_tool_install_remove_clicked(){
405  //Get the current item
406  QString appID;
407  if(ui->tree_install_apps->topLevelItemCount() > 0){
408    appID = ui->tree_install_apps->currentItem()->whatsThis(0);
409  }
410  if(appID.isEmpty()){return;}
411  //Verify removal
412  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) ){
413    PBI->removePBI(QStringList() << appID);
414  }
415}
416
417void MainUI::on_tool_install_cancel_clicked(){
418  //Get the current item
419  QString appID;
420  if(ui->tree_install_apps->topLevelItemCount() > 0){
421    appID = ui->tree_install_apps->currentItem()->whatsThis(0);
422  }
423  if(appID.isEmpty()){return;}
424  PBI->cancelActions(QStringList() << appID);
425 
426}
427
428// === SELECTED PBI ACTIONS ===
429void MainUI::slotActionAddDesktop(){
430  QStringList items = getCheckedItems();
431  PBI->addDesktopIcons(items,FALSE); //only for current user
432}
433
434void MainUI::slotActionRemoveDesktop(){
435  QStringList items = getCheckedItems();
436  PBI->rmDesktopIcons(items,FALSE);  //Only for current user
437}
438
439void MainUI::slotActionAddPath(){
440  QStringList items = getCheckedItems();
441  PBI->addPaths(items,FALSE);  //Only for current user 
442}
443
444void MainUI::slotActionRemovePath(){
445  QStringList items = getCheckedItems();
446  PBI->rmPaths(items,FALSE);  //Only for current user
447}
448
449void MainUI::slotActionAddPathAll(){
450  QStringList items = getCheckedItems();
451  PBI->addPaths(items,TRUE);  //For all users (root permissions required)
452}
453
454void MainUI::slotActionAddMenu(){
455  QStringList items = getCheckedItems();
456  PBI->addMenuIcons(items,FALSE);  //Only for current user
457}
458
459void MainUI::slotActionRemoveMenu(){
460  QStringList items = getCheckedItems();
461  PBI->rmMenuIcons(items,FALSE);  //Only for current user       
462}
463
464void MainUI::slotActionAddMenuAll(){
465  QStringList items = getCheckedItems();
466  PBI->addMenuIcons(items,TRUE);  //For all users (root permissions required)   
467}
468
469void MainUI::slotActionAddMime(){
470  QStringList items = getCheckedItems();
471  PBI->addMimeTypes(items,FALSE);  //Only for current user     
472}
473
474void MainUI::slotActionRemoveMime(){
475  QStringList items = getCheckedItems();
476  PBI->rmMimeTypes(items,FALSE);  //Only for current user       
477}
478
479void MainUI::slotActionAddMimeAll(){
480    QStringList items = getCheckedItems();
481  PBI->addMimeTypes(items,TRUE);  //For all users (root permissions required)   
482}
483
484void MainUI::slotActionUpdate(){
485  QStringList checkedID = getCheckedItems();
486  if(!checkedID.isEmpty()){
487    PBI->upgradePBI(checkedID); 
488  }
489}
490
491void MainUI::slotActionRemove(){
492  QStringList checkedID = getCheckedItems();
493  if(!checkedID.isEmpty()){
494    //Verify that the user really wants to remove these apps
495    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) ){
496      PBI->removePBI(checkedID);
497    }
498  }
499}
500
501void MainUI::slotActionCancel(){
502  QStringList checkedID = getCheckedItems();
503  if(!checkedID.isEmpty()){
504    PBI->cancelActions(checkedID); 
505  }
506}
507
508
509// ==========================
510// ====== BROWSER TAB =======
511// ==========================
512void MainUI::initializeBrowserTab(){
513  ui->tab_browse->setEnabled(FALSE);
514  //Always make sure that the browser starts off on the "home" page
515  ui->stacked_browser->setCurrentWidget(ui->page_home);
516  //With invisible shortcut buttons
517  ui->tool_browse_cat->setVisible(FALSE);
518  ui->tool_browse_app->setVisible(FALSE);
519  //Clear any items left over from the designer form
520  clearScrollArea(ui->scroll_br_home_newapps);
521  clearScrollArea(ui->scroll_br_home_cats);
522  //Search functionality
523  searchTimer = new QTimer();
524    searchTimer->setSingleShot(TRUE);
525    searchTimer->setInterval(300); // 0.3 sec wait before a search
526    connect(searchTimer,SIGNAL(timeout()),this,SLOT(slotGoToSearch()) );
527  connect(ui->tool_browse_search,SIGNAL(clicked()),this,SLOT(slotGoToSearch()) );
528  connect(ui->line_browse_searchbar,SIGNAL(returnPressed()),this,SLOT(slotGoToSearch()) );
529}
530
531// === SLOTS ===
532void MainUI::slotDisableBrowser(bool shownotification){
533  if(shownotification){ qDebug() << "No Repo Available: De-activating the Browser"; }
534  ui->tabWidget->setCurrentWidget(ui->tab_installed);
535  ui->tool_install_gotobrowserpage->setEnabled(FALSE);
536  ui->tab_browse->setEnabled(FALSE);
537  slotDisplayStats();
538}
539
540void MainUI::slotEnableBrowser(){
541  qDebug() << "Repo Ready: - generating browser home page";
542  //Now create the browser home page
543  slotUpdateBrowserHome();
544  //And allow the user to go there
545  ui->tool_install_gotobrowserpage->setEnabled(TRUE);
546  ui->tab_browse->setEnabled(TRUE);
547  slotDisplayStats();
548}
549
550void MainUI::slotUpdateBrowserHome(){
551  //Load the Categories
552  QStringList cats = PBI->browserCategories();
553  clearScrollArea(ui->scroll_br_home_cats);
554  QVBoxLayout *catlayout = new QVBoxLayout;
555  QStringList info; info << "name" << "description" << "icon";
556  cats.sort(); //sort them alphabetically
557  for(int i=0; i<cats.length(); i++){
558    QStringList data = PBI->CatInfo(cats[i],info);
559    if(!data.isEmpty()){
560      LargeItemWidget *item = new LargeItemWidget(cats[i],data[0],data[1],data[2]);
561      connect(item,SIGNAL(appClicked(QString)),this,SLOT(slotGoToCategory(QString)) );
562      catlayout->addWidget(item);
563    }
564  }
565  catlayout->addStretch(); //add a spacer to the end
566  ui->scroll_br_home_cats->widget()->setLayout(catlayout);
567  //Load the newest applications
568  clearScrollArea(ui->scroll_br_home_newapps);
569  QHBoxLayout *newapplayout = new QHBoxLayout;
570  QStringList newapps = PBI->getRecentApps();
571  for(int i=0; i<newapps.length(); i++){
572    QStringList appdata = PBI->AppInfo(newapps[i],QStringList() << "name" << "icon" << "latestversion");
573    if(!appdata.isEmpty()){
574      SmallItemWidget *item = new SmallItemWidget(newapps[i],appdata[0],appdata[1],appdata[2]);
575      connect(item,SIGNAL(appClicked(QString)),this,SLOT(slotGoToApp(QString)) );
576      newapplayout->addWidget(item);
577    }
578  }
579  newapplayout->addStretch(); //add a spacer to the end
580  newapplayout->setContentsMargins(0,0,0,0);
581  newapplayout->setSpacing(0);
582  ui->scroll_br_home_newapps->widget()->setLayout(newapplayout);
583  //Make sure that the newapps scrollarea is the proper fit vertically (no vertical scrolling)
584  ui->scroll_br_home_newapps->setMinimumHeight(ui->scroll_br_home_newapps->widget()->minimumSizeHint().height()+ui->scroll_br_home_newapps->horizontalScrollBar()->height());
585 
586  //Make sure the new apps area is invisible if no items available
587  if(newapps.isEmpty()){ ui->group_br_home_newapps->setVisible(FALSE); }
588  else{ ui->group_br_home_newapps->setVisible(TRUE); }
589  //make sure the home page is visible in the browser (slotGoToHome without changing tabs)
590  ui->stacked_browser->setCurrentWidget(ui->page_home); 
591  //Make sure the shortcut buttons are disabled
592  ui->tool_browse_cat->setVisible(FALSE);
593  ui->tool_browse_app->setVisible(FALSE); 
594 
595}
596
597void MainUI::slotGoToHome(){
598  ui->tabWidget->setCurrentWidget(ui->tab_browse);
599  ui->stacked_browser->setCurrentWidget(ui->page_home); 
600  //Make sure the shortcut buttons are disabled
601  ui->tool_browse_cat->setVisible(FALSE);
602  ui->tool_browse_app->setVisible(FALSE);
603}
604
605void MainUI::slotGoToCategory(QString cat){
606  qDebug() << "Show Category:" << cat;
607  //Get the apps in this category
608  QStringList apps = PBI->browserApps(cat);
609  if(apps.isEmpty()){
610    qDebug() << "Invalid category:" << cat;
611    return;
612  }
613  clearScrollArea(ui->scroll_br_cat_apps);
614  apps.sort();
615  QVBoxLayout *applayout = new QVBoxLayout;
616  QStringList info; info << "name" << "description" << "icon";
617  for(int i=0; i<apps.length(); i++){
618    QStringList data = PBI->AppInfo(apps[i],info);
619    if(!data.isEmpty()){
620      //Trim the description if necessary
621      if(data[1].size()>100){ data[1] = data[1].left(100).append("..."); }
622      LargeItemWidget *item = new LargeItemWidget(apps[i],data[0],data[1],data[2]);
623      connect(item,SIGNAL(appClicked(QString)),this,SLOT(slotGoToApp(QString)) );
624      applayout->addWidget(item); 
625    }
626  }
627  applayout->addStretch();
628  ui->scroll_br_cat_apps->widget()->setLayout(applayout);
629  //Now enable/disable the shortcut buttons
630  ui->tool_browse_app->setVisible(FALSE);
631  ui->tool_browse_cat->setVisible(TRUE);
632    QStringList catinfo = PBI->CatInfo(cat,QStringList() << "name" << "icon");
633    ui->tool_browse_cat->setText(catinfo[0]);
634    if(catinfo[1].isEmpty()){ catinfo[1] = defaultIcon; }
635    ui->tool_browse_cat->setIcon(QIcon(catinfo[1]));
636  ui->tabWidget->setCurrentWidget(ui->tab_browse);
637  ui->stacked_browser->setCurrentWidget(ui->page_cat);
638  //Now save that this category is currently displayed
639  cCat = cat;
640}
641
642void MainUI::slotGoToApp(QString appID){
643  qDebug() << "Show App:" << appID;
644  //Get the general application info
645  QStringList data; 
646  data << "name" << "icon" << "author" << "website" << "license" << "type" << "description" \
647       << "category" << "requiresroot" << "latestversion" << "latestarch" <<"latestsize" \
648       << "backupversion" << "backuparch" << "backupsize";
649  data = PBI->AppInfo(appID,data);
650  if(data.isEmpty()){
651    qDebug() << "Invalid App:" << appID;
652    return;
653  }
654  //Start the search for similar apps
655  PBI->searchSimilar = appID;
656  ui->group_bapp_similar->setVisible(FALSE);
657  QTimer::singleShot(0,PBI,SLOT(startSimilarSearch()));
658  //Now Check icon
659  if(data[1].isEmpty()){ data[1] = defaultIcon; }
660  //Now fill the UI with the data
661  ui->label_bapp_name->setText(data[0]);
662  ui->label_bapp_icon->setPixmap(QPixmap(data[1]));
663  if(data[3].isEmpty()){ ui->label_bapp_authorweb->setText(data[2]); }
664  else{ ui->label_bapp_authorweb->setText("<a href="+data[3]+">"+data[2]+"</a>"); }
665  ui->label_bapp_authorweb->setToolTip(data[3]);
666  ui->label_bapp_license->setText(data[4]);
667  ui->label_bapp_type->setText(data[5]);
668  ui->text_bapp_description->setText(data[6]);
669  //Now determine the appropriate version info
670  QString pbiID = PBI->isInstalled(appID); //get pbiID
671  QString cVer;
672  if(!pbiID.isEmpty()){ cVer = PBI->PBIInfo(pbiID,QStringList("version")).join(""); }
673  bool useLatest=FALSE;
674  bool nobackup = data[12].isEmpty();
675  if(cVer.isEmpty()){ useLatest=TRUE; } //not currently installed
676  else if(cVer != data[9]){ useLatest=TRUE;} //not the latest version
677  //Now put the proper version info on the UI
678  if(useLatest || nobackup){
679    ui->label_bapp_version->setText(data[9]);
680    ui->label_bapp_arch->setText(data[10]);
681    if(data[11].isEmpty()){ ui->label_bapp_size->setText(tr("Unknown")); }
682    else{ ui->label_bapp_size->setText( Extras::sizeKToDisplay(data[11]) ); }
683  }else{
684    ui->label_bapp_version->setText(data[12]);
685    ui->label_bapp_arch->setText(data[13]);
686    if(data[14].isEmpty()){ ui->label_bapp_size->setText(tr("Unknown")); }
687    else{ ui->label_bapp_size->setText( Extras::sizeKToDisplay(data[14]) ); }
688  }
689  //Now update the download button appropriately
690  QString ico;
691  QString working = PBI->currentAppStatus(appID);
692  if(!working.isEmpty()){ //app currently pending or actually doing something
693    ui->tool_bapp_download->setText(working);
694    ui->tool_bapp_download->setIcon(QIcon(":icons/working.png"));
695    ui->tool_bapp_download->setEnabled(FALSE);
696  }else if(useLatest && cVer.isEmpty()){ //new installation
697    ui->tool_bapp_download->setText(tr("Install Now!"));
698    ico = ":icons/app_download.png";
699    ui->tool_bapp_download->setEnabled(TRUE);
700  }else if(useLatest){ //Upgrade available
701    ui->tool_bapp_download->setText(tr("Upgrade"));
702    ico = ":icons/app_upgrade.png";
703    ui->tool_bapp_download->setEnabled(TRUE);
704  }else if(!nobackup){  //Downgrade available
705    ui->tool_bapp_download->setText(tr("Downgrade"));
706    ico = ":icons/app_downgrade.png";
707    ui->tool_bapp_download->setEnabled(TRUE);
708  }else{ //already installed (no downgrade available)
709    ui->tool_bapp_download->setText(tr("Installed"));
710    ui->tool_bapp_download->setIcon(QIcon(":icons/dialog-ok.png"));
711    ui->tool_bapp_download->setEnabled(FALSE);
712  }
713  //Now set the icon appropriately if it requires root permissions
714  if(!ico.isEmpty()){
715    if(data[8]=="true"){ //requires root permissions to install
716      ico.replace(".png","-root.png");
717    }
718    ui->tool_bapp_download->setIcon(QIcon(ico));
719  }
720  ui->tool_bapp_download->setWhatsThis(appID); //set for slot
721  //Now enable/disable the shortcut buttons
722  ui->tool_browse_app->setVisible(TRUE);
723    ui->tool_browse_app->setText(data[0]);
724    ui->tool_browse_app->setIcon(QIcon(data[1]));
725  QStringList catinfo = PBI->CatInfo(Extras::nameToID(data[7]),QStringList() << "name" << "icon");
726  if(!catinfo.isEmpty()){
727    ui->tool_browse_cat->setVisible(TRUE);
728    ui->tool_browse_cat->setText(catinfo[0]);
729    if(catinfo[1].isEmpty()){ catinfo[1] = defaultIcon; }
730    ui->tool_browse_cat->setIcon(QIcon(catinfo[1]));
731  }
732  ui->tabWidget->setCurrentWidget(ui->tab_browse);
733  ui->stacked_browser->setCurrentWidget(ui->page_app);
734       
735}
736
737void MainUI::slotGoToSearch(){
738  searchTimer->stop(); //just in case "return" was pressed to start the search
739  QString search = ui->line_browse_searchbar->text();
740  if(search.isEmpty()){ return; }
741  PBI->searchTerm = search;
742  QTimer::singleShot(1,PBI,SLOT(startAppSearch()));
743  ui->label_bsearch_info->setText( tr("Searching the application database. Please Wait....") );
744    ui->label_bsearch_info->setVisible(TRUE);
745    ui->group_bsearch_best->setVisible(FALSE);
746    ui->group_bsearch_other->setVisible(FALSE);
747 
748}
749       
750void MainUI::slotShowSimilarApps(QStringList apps){
751  qDebug() << " - Similar applications:" << apps;
752  if(apps.isEmpty()){ ui->group_bapp_similar->setVisible(FALSE); }
753  else{
754    clearScrollArea(ui->scroll_bapp_similar);
755    QHBoxLayout *layout = new QHBoxLayout;
756    for(int i=0; i<apps.length(); i++){
757      QStringList appdata = PBI->AppInfo(apps[i],QStringList() << "name" << "icon");
758      if(!appdata.isEmpty()){
759        SmallItemWidget *item = new SmallItemWidget(apps[i],appdata[0],appdata[1],"");
760        connect(item,SIGNAL(appClicked(QString)),this,SLOT(slotGoToApp(QString)) );
761        layout->addWidget(item);
762      }
763    }
764    layout->addStretch(); //add a spacer to the end
765    layout->setContentsMargins(1,1,1,1);
766    ui->scroll_bapp_similar->widget()->setLayout(layout);
767    //Make sure that the similar scrollarea is the proper fit vertically (no vertical scrolling)
768    ui->scroll_bapp_similar->setMinimumHeight(ui->scroll_bapp_similar->widget()->minimumSizeHint().height()+ui->scroll_bapp_similar->horizontalScrollBar()->height());
769    //Now make the group visible as appropriate
770    ui->group_bapp_similar->setVisible(TRUE);
771    if(ui->group_bapp_similar->isChecked()){ ui->scroll_bapp_similar->setVisible(TRUE); }
772    else{ ui->scroll_bapp_similar->setVisible(FALSE); }
773    //Now make sure the app page has the proper layout dimensions
774    ui->page_app->updateGeometry();
775  }
776}
777
778void MainUI::slotShowSearchResults(QStringList best, QStringList rest){
779  //Now display the search results
780  if(best.isEmpty()){
781    ui->label_bsearch_info->setText( QString(tr("No Search Results Found for the term: %1")).arg(ui->line_browse_searchbar->text()) );
782    ui->label_bsearch_info->setVisible(TRUE);
783    ui->group_bsearch_best->setVisible(FALSE);
784    ui->group_bsearch_other->setVisible(FALSE);
785  }else{
786    ui->label_bsearch_info->setVisible(FALSE);
787    //Now fill the "best" section
788    clearScrollArea(ui->scroll_bsearch_best);
789    QVBoxLayout *layout = new QVBoxLayout;
790    QStringList info; info << "name" << "description" << "icon";
791    for(int i=0; i<best.length(); i++){
792      QStringList data = PBI->AppInfo(best[i],info);
793      if(!data.isEmpty()){
794        //Trim the description if necessary
795        if(data[1].size()>100){ data[1] = data[1].left(100).append("..."); }
796        LargeItemWidget *item = new LargeItemWidget(best[i],data[0],data[1],data[2]);
797        connect(item,SIGNAL(appClicked(QString)),this,SLOT(slotGoToApp(QString)) );
798        layout->addWidget(item); 
799      }
800    }
801    layout->addStretch();
802    ui->scroll_bsearch_best->widget()->setLayout(layout);
803    ui->group_bsearch_best->setVisible(TRUE);
804   
805    //Now fill the other results
806    if(rest.isEmpty()){ ui->group_bsearch_other->setVisible(FALSE); }
807    else{
808      ui->group_bsearch_other->setVisible(TRUE);
809      clearScrollArea(ui->scroll_bsearch_other);
810      QVBoxLayout *layout2 = new QVBoxLayout;
811      for(int i=0; i<rest.length(); i++){
812        QStringList data = PBI->AppInfo(rest[i],info);
813        if(!data.isEmpty()){
814          //Trim the description if necessary
815          if(data[1].size()>100){ data[1] = data[1].left(100).append("..."); }
816          LargeItemWidget *item = new LargeItemWidget(rest[i],data[0],data[1],data[2]);
817          connect(item,SIGNAL(appClicked(QString)),this,SLOT(slotGoToApp(QString)) );
818          layout2->addWidget(item); 
819        }
820      }
821      layout2->addStretch();
822      ui->scroll_bsearch_other->widget()->setLayout(layout2);
823    }
824  }
825       
826  //need to make sure the search bar still has keyboard focus (just in case)
827  ui->tabWidget->setCurrentWidget(ui->tab_browse);
828  ui->stacked_browser->setCurrentWidget(ui->page_search);
829 
830}
831
832void MainUI::on_tabWidget_currentChanged(){
833  if(ui->tabWidget->currentWidget() == ui->tab_browse){
834    //Refresh the app page if that is the one currently showing
835    if(ui->stacked_browser->currentWidget() == ui->page_app){ on_tool_browse_app_clicked(); }     
836  }
837}
838
839void MainUI::on_tool_browse_home_clicked(){
840  slotGoToHome();
841}
842
843void MainUI::on_tool_browse_cat_clicked(){
844  QString cat = Extras::nameToID(ui->tool_browse_cat->text());
845  if(cCat == cat){ //already loaded - just show it (prevents resetting scroll positions)
846    ui->stacked_browser->setCurrentWidget(ui->page_cat);
847  }else{ //load and show the category
848    slotGoToCategory(cat);
849  }
850}
851
852void MainUI::on_tool_browse_app_clicked(){
853  QString appID = Extras::nameToID(ui->tool_browse_app->text());
854  slotGoToApp(appID);
855}
856
857void MainUI::on_line_browse_searchbar_textChanged(){
858  //Connect this to a singleshot timer, so the search functionality is only
859  //  run once after a short wait rather than every time a new character is typed
860 
861  //Live search only after 3 characters have been typed
862  if(ui->line_browse_searchbar->text().length() > 2){
863    searchTimer->start();
864  }else{
865    searchTimer->stop();         
866  }
867}
868
869void MainUI::on_tool_bapp_download_clicked(){
870  QString appID = ui->tool_bapp_download->whatsThis();
871  PBI->installApp(QStringList() << appID);
872  ui->tool_bapp_download->setEnabled(FALSE); //make sure it cannot be clicked more than once before page refresh
873  //Now show the Installed tab
874  ui->tabWidget->setCurrentWidget(ui->tab_installed);
875}
876
877void MainUI::on_group_br_home_newapps_toggled(bool show){
878  ui->scroll_br_home_newapps->setVisible(show);
879}
880
881void MainUI::on_group_bapp_similar_toggled(bool show){
882  ui->scroll_bapp_similar->setVisible(show);
883}
884
885// ================================
886// ==========  OTHER ==============
887// ================================
888void MainUI::clearScrollArea(QScrollArea* area){
889  QWidget *wgt = area->takeWidget();
890  delete wgt; //delete the widget and all children
891  area->setWidget( new QWidget() ); //create a new widget in the scroll area
892  area->widget()->setContentsMargins(0,0,0,0);
893}
894
895void MainUI::slotDisplayError(QString title,QString message,QStringList log){
896  ErrorDialog *dlg = new ErrorDialog(this);
897  dlg->setDLGTitle(title);
898  dlg->setDLGMessage(message);
899  dlg->setDLGLog(log);
900  dlg->exec();
901  //QMessageBox::warning(this,title,message+"\n\n"+log.join("\n"));
902}
903
904void MainUI::slotDisplayStats(){
905  int avail = PBI->numAvailable;
906  int installed = PBI->numInstalled;
907  QString text;
908  if(avail == -1){
909    text = QString(tr("Installed: %1")).arg(QString::number(installed)); 
910  }else{
911    text = QString(tr("Installed: %1")+"\t"+tr("Available: %2")).arg(QString::number(installed), QString::number(avail)); 
912  }
913  //Get the number of installed/available applications and display it
914  statusLabel->setText(text);   
915}
Note: See TracBrowser for help on using the repository browser.