' Gambas class file PUBLIC sBaseDir AS String = "/usr/share/vine-app-install-data/" PUBLIC sPathTmpLst AS String = Temp$("v-a-i-List") PUBLIC sPathTmpRes AS String = Temp$("v-a-i-Result") PUBLIC sIconDir AS String = "/usr/share/icons/gnome/24x24/categories/" PUBLIC iHeightHBox AS Integer = Desktop.Scale * 5 ' default row height of gridview PUBLIC cApplications AS NEW Collection ' store application information (multi dimension), = Name PUBLIC sAppName AS String ' store app name globaly (used for reading apt-cache's output) PUBLIC iCount AS Integer ' for progress bar PUBLIC sSearchTerm AS String ' store search term PUBLIC sSelectedApp AS String ' store selected app (already shown in detail pane) ' PUBLIC bScriptError AS Boolean = FALSE ' set TRUE if apt-get script outputs any error messages PUBLIC idSumm AS Integer = 0 ' : Summary PUBLIC idDesc AS Integer = 1 ' : Description PUBLIC idCat AS Integer = 2 ' : Category PUBLIC idStat AS Integer = 3 ' : State (Installed/NotInstalled) PUBLIC idCkBox AS Integer = 4 ' : Checkbox State (On / Off) PUBLIC idVersion AS Integer = 5 PUBLIC idInstSize AS Integer = 6 PUBLIC idDLSize AS Integer = 7 PUBLIC SUB Form_Open() ' enable main form whlie adding categories (workaround for ) FMain.Enabled = TRUE 'setup left(category) panel hspMain.Layout = "180," & CStr(hspMain.Width - 180) AddCategory("Accessories", ("Accessories"), Picture[sIconDir & "applications-accessories.png"]) AddCategory("Internet", ("Internet"), Picture[sIconDir & "applications-internet.png"]) AddCategory("Office", ("Office"), Picture[sIconDir & "applications-office.png"]) AddCategory("Graphics", ("Graphics"), Picture[sIconDir & "applications-graphics.png"]) AddCategory("Multimedia", ("Multimedia"), Picture[sIconDir & "applications-multimedia.png"]) AddCategory("Games", ("Games"), Picture[sIconDir & "applications-games.png"]) AddCategory("System", ("System"), Picture[sIconDir & "applications-system.png"]) AddCategory("Development", ("Development"), Picture[sIconDir & "applications-development.png"]) AddCategory("Other", ("Other"), Picture[sIconDir & "applications-other.png"]) AddCategory("Tasks", ("Tasks"), Stock["24/component"]) AddCategory("Fonts", ("Fonts"), Stock["24/font"]) AddCategory("Restricted", ("Restricted"), Stock["24/lock"]) ' adjust some widgets size according to it's font size ''' bottom buttons btnHelp.Width = btnHelp.Font.Width(btnHelp.Text) + 20 btnSwitch.Width = btnSwitch.Font.Width(btnSwitch.Text) + 20 btnClose.Width = btnClose.Font.Width(btnClose.Text) + 20 btnSwitch.Width = btnSwitch.Font.Width(btnSwitch.Text) + 20 btnThumb.Height = btnThumb.Font.Height(btnThumb.Text) + 8 hbxBottom.Height = btnClose.Font.Height(btnClose.Text) + 12 ''' top combo box and serarch area hbxTop.Height = tbxSearch.Font.Height(tbxSearch.Text) + 12 ''' keep search button square btnSearch.Width = btnSearch.Height ' disable main form after categories added (workaround for ) FMain.Enabled = FALSE END PUBLIC SUB Form_Show() ' a bit wait for widget drawing WAIT 1 LoadAppData() END PUBLIC SUB Form_Close() ' remove temporary files IF Exist(sPathTmpLst) THEN KILL sPathTmpLst IF Exist(sPathTmpRes) THEN KILL sPathTmpRes END PUBLIC SUB btnClose_Click() ME.Close END PUBLIC SUB lctApps_Click() DIM iSsHeight AS Integer DIM hPict AS Picture DIM sURL AS String ' store URL extract from rpm database ' return immediately while loading the app list IF lctApps.Current = NULL THEN RETURN 'make visible and expand the detail pane IF svwDetail.Visible = FALSE THEN svwDetail.Visible = TRUE vspRight.Layout = "0, " & CStr(vspRight.Height / 2) & "," & CStr(vspRight.Height / 2) ENDIF ' set description of selected package sSelectedApp = lctApps.Current.Name tlbAppName.Text = "" & sSelectedApp & "" tlbAppDesc.Text = Replace(cApplications[sSelectedApp][idDesc], "

", "
", gb.Text) tlbAppDesc.Text &= " " & ("Version: ") & cApplications[sSelectedApp][idVersion] & "
" tlbAppDesc.Text &= " " & ("Install Size: ") & ConvUnit(cApplications[sSelectedApp][idInstSize]) & "" tlbAppDesc.Text &= " (" & ("Download Size: ") & ConvUnit(cApplications[sSelectedApp][idDLSize]) & ")" ' set icon(large) of selected package IF Exist(sBaseDir &/ cApplications[sSelectedApp][idCat] &/ "icons" &/ sSelectedApp & ".png") = TRUE THEN pbxDetail.Picture = Image.Load(sBaseDir &/ cApplications[sSelectedApp][idCat] &/ "icons" &/ sSelectedApp & ".png").stretch(48, 48).Picture ELSE pbxDetail.Picture = Picture["noicon.png"] ENDIF ' set screenshot if available IF Exist(sBaseDir &/ cApplications[sSelectedApp][idCat] &/ "screenshots" &/ sSelectedApp & "_small.jpg") = TRUE THEN pbxThumb.Picture = Picture[sBaseDir &/ cApplications[sSelectedApp][idCat] &/ "screenshots" &/ sSelectedApp & "_small.jpg"] pbxThumb.Height = pbxThumb.Picture.Height pbxThumb.Mouse = Mouse.Pointing pbxThumb.Visible = TRUE btnThumb.Visible = TRUE vbxThumb.Visible = TRUE ELSE pbxThumb.Mouse = Mouse.Default pbxThumb.Visible = FALSE btnThumb.Visible = FALSE vbxThumb.Visible = FALSE ENDIF ' set button text and width IF cApplications[sSelectedApp][idStat] = "NotInstalled" THEN btnApply.Text = ("Install") btnApply.Picture = Stock["24/add"] ELSE btnApply.Text = ("Uninstall") btnApply.Picture = Stock["24/remove"] ENDIF btnApply.Height = btnApply.Font.Height(btnApply.Text) + 16 vbxButton.Width = btnApply.Font.Width(btnApply.Text) + 36 ' scroll back to top svwDetail.Scroll(0, 0) END PUBLIC SUB pbxThumb_MouseUp() DIM sName AS String DIM iRet AS Integer DIM hProcess AS Stream ' return immediately if no app is selected in listview IF lctApps.Current = NULL THEN RETURN sName = lctApps.Current.Name IF Exist(sBaseDir &/ cApplications[sName][idCat] &/ "screenshots" &/ sName & ".png") THEN EXEC ["xdg-open", sBaseDir &/ cApplications[sName][idCat] &/ "screenshots" &/ sName & ".png"] ELSE ' prompt to install vine-app-install-data-screenshots if no screenshots available iRet = Message.Question(("There is no screenshot available.\n\nYou should install additional package \n(vine-app-install-data-screenshots) to show the screenshot.\n\nWolud you like to download and install it?"), ("&Cancel"), ("&OK")) IF iRet = 2 THEN FMain.Enabled = FALSE FMain.Mouse = Mouse.Wait hProcess = EXEC ["synaptic", "--non-interactive", "--hide-main-window", "--set-selections", "<"] FOR WRITE AS "ShellSynapticSS" PRINT #hProcess, "vine-app-install-data-screenshots install\n"; CLOSE #hProcess ENDIF ENDIF END PUBLIC SUB ShellSynapticSS_kill() ' re-enable main form after screenshot data is installed FMain.Mouse = Mouse.Default FMain.Enabled = TRUE END PUBLIC SUB lctCategory_Click() ' hide welcome screen and show application list IF vbxMessage.Visible = TRUE THEN vbxMessage.Visible = FALSE lctApps.Visible = TRUE ENDIF FilterLctApps() END PUBLIC SUB cbxState_Click() FilterLctApps() END PUBLIC SUB btnHelp_Click() ' show html help EXEC ["xdg-open", "/usr/share/doc/vine-app-install-" & Application.Version & "/help/index.html"] END PUBLIC SUB btnSearch_Click() DIM hSep AS Separator DIM sRes AS String btnSearch.SetFocus IF (tbxSearch.Text <> ("Enter search term") AND tbxSearch.Text <> "") THEN ' store search term in variable sSearchTerm = tbxSearch.Text ' if category not exist and search term is entererd, then create category IF FindCategory("Search") = -1 THEN ' add separator hSep = NEW Separator(lctCategory) hSep.Height = 4 hSep.Enabled = FALSE AddCategory("Search", ("Search result"), Stock["24/find"]) ENDIF TRY sRes = lctCategory.Current.Name IF sRes = "Search" THEN FilterLctApps() ELSE lctCategory.Select(lctCategory.Children[FindCategory("Search")]) ENDIF ENDIF END PUBLIC SUB btnApply_Click() DIM sSelection AS String DIM hProcess AS Stream ' prepare selection string IF cApplications[sSelectedApp][idStat] = "NotInstalled" THEN sSelection = sSelectedApp & " " & "install" ELSE sSelection = sSelectedApp & " " & "delete" ENDIF ' do install or uninstall FMain.Enabled = FALSE FMain.Mouse = Mouse.Wait hProcess = EXEC ["synaptic", "--non-interactive", "--hide-main-window", "-o", "Synaptic::AskRelated=false", "--set-selections", "<"] FOR WRITE AS "ShellSynaptic" PRINT #hProcess, sSelection; CLOSE #hProcess END PUBLIC SUB ShellSynaptic_kill() LoadAppData() END PUBLIC SUB tbxSearch_GotFocus() IF tbxSearch.Text = ("Enter search term") THEN tbxSearch.Clear tbxSearch.Foreground = Color.TextForeground ELSE tbxSearch.SelectAll ENDIF END PUBLIC SUB tbxSearch_LostFocus() IF tbxSearch.Text = "" THEN tbxSearch.Foreground = Val("&HA0A0A0&") tbxSearch.Text = ("Enter search term") ENDIF END ' This does not work with gb.gtk in gambas2-2.23.0, So disable it. ' PUBLIC SUB Form_KeyPress() ' ' ' set focus on search field when Ctrl + K pressed ' IF Key.Control = TRUE AND Key.Text = "k" THEN tbxSearch.SetFocus ' ' END ' PUBLIC SUB tbxSearch_KeyPress() ' press enter key then start serch IF Key.Code = Key.Return THEN btnSearch_Click() END PUBLIC SUB btnThumb_Click() pbxThumb_MouseUp() END PUBLIC SUB btnSwitch_Click() DIM iBtn AS Integer iBtn = Message.Question(("Do you want to switch to synaptic package manager?"), ("&No"), ("&Yes")) IF iBtn = 2 THEN EXEC ["gksu", "-D", "\"synaptic\"", "synaptic"] ME.Close ENDIF END ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' '' procedures and functions (including process event) '' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' PUBLIC SUB AddCategory(sName AS String, sText AS String, pIcon AS Picture) ' add set of HBox, PictureBox and TextLabel in list container DIM hBox AS HBox DIM hLabel AS Label DIM hPict AS PictureBox ' create HBox hBox = NEW HBox(lctCategory) hBox.Padding = 4 hBox.Spacing = 8 hBox.Height = Desktop.Scale * 4 hBox.Name = sName ' create PictureBox for icon hPict = NEW PictureBox(hBox) hPict.Picture = pIcon hPict.Resize(24, 24) ' create TextLaber for group name hLabel = NEW Label(hBox) hLabel.Expand = TRUE hLabel.Text = sText END PUBLIC SUB LoadAppData() DIM hFile AS File ' handler for temporary file DIM aFileAndDir AS NEW String[] ' used for sorting DIM sAppList AS String ' list of application names DIM sDir AS String DIM sFile AS String DIM i AS Integer ' setup progress bar and counter iCount = 1 pgbProgress.Value = 0 pgbProgress.Visible = TRUE ' get file name & dirctory and sort them by file name (*not directory name) FOR EACH sDir IN Dir(sBaseDir, "*", gb.Directory) FOR EACH sFile IN Dir(sBaseDir &/ sDir, "*", gb.File) aFileAndDir.Add(sFile & ":" & sDir) sAppList &= sFile & " " NEXT NEXT aFileAndDir.Sort ' store name & category into collection (also reload it) IF cApplications.Count > 0 THEN cApplications.Clear FOR i = 0 TO aFileAndDir.Max cApplications.Add(["", "", Split(aFileAndDir[i], ":")[1], "", "", "", "", "", ""], Split(aFileAndDir[i], ": ")[0]) NEXT ' extract package info from apt cache and store it to gridview hFile = OPEN sPathTmpLst FOR CREATE PRINT #hFile, sAppList CLOSE #hFile ' execute helper lua script and redirect standard output to temporary file. ' we should use a file to pass large number of application names (possibly a bug of gambas?). SHELL "apt-cache show `cat " & sPathTmpLst & "` | tee " & sPathTmpRes FOR READ AS "AptScript" END PUBLIC SUB AptScript_Read() DIM sLine AS String LINE INPUT #LAST, sLine IF sLine LIKE "Package: *" THEN pgbProgress.Value = iCount / (cApplications.Count) INC iCount WAIT 0.001 ' wait a mili second for progress bar drawing ENDIF END ' apt-cache output error messages when unavailable package is specified. ' so we cannot use _Error event to catch exit status of command. ' (BTS:wished:236>) ' ' PUBLIC SUB AptScript_Error(sStr AS String) ' ' bScriptError = TRUE ' ' END PUBLIC SUB AptScript_Kill() DIM i AS Integer IF Stat(sPathTmpRes).Size = 0 THEN Message.Error(("Error while extracting package information.

Please resolve the problem using apt-get command or synaptic package manager.
"), ("&Close")) ME.Close ELSE CreateAppData() CreateAppList() FilterLctApps() ' back to original condition pgbProgress.Visible = FALSE FMain.Mouse = Mouse.Default FMain.Enabled = TRUE vbxMessage.Visible = TRUE ' re-select application if once selected IF sSelectedApp <> "" THEN FOR i = 0 TO lctApps.Children.Count - 1 IF lctApps.Children[i].name = sSelectedApp THEN lctApps.Select(lctApps.Children[i]) BREAK ENDIF NEXT ENDIF ' should set forcus on something to catch key event (as workaround?) btnClose.SetFocus ENDIF END PUBLIC SUB CreateAppData() DIM hFile AS File ' handler for temporary file DIM sLine AS String ' read one line from file (output of lua script) DIM sOutput AS String ' keep command standard output DIM aRes AS String[] ' keep splitted sRes as array DIM sRes AS String DIM aElement AS String[] IF Exist(sPathTmpRes) = TRUE THEN hFile = OPEN sPathTmpRes FOR INPUT WHILE NOT Eof(hFile) LINE INPUT #hFile, sLine IF InStr(sLine, ": ") THEN SELECT CASE Split(sLine, ":")[0] CASE "Package" ' Name sLine = Right(sLine, Len(sLine) - 9) ' pacakge name sAppName = sLine ' hold current app name ' set default value as "not installed" cApplications[sAppName][idCkBox] = "Off" cApplications[sAppName][idStat] = "NotInstalled" CASE "Summary" cApplications[sAppName][idSumm] = Right(sLine, Len(sLine) - 9) CASE "Installed Size" cApplications[sAppName][idInstSize] = Right(sLine, Len(sLine) - 16) CASE "Version" cApplications[sAppName][idVersion] = Right(sLine, Len(sLine) - 9) CASE "Size" cApplications[sAppName][idDLSize] = Right(sLine, Len(sLine) - 6) CASE "Description" END SELECT ELSE ' assume only description has multi line text IF sAppName <> "" THEN cApplications[sAppName][idDesc] &= sLine & "
" ENDIF ENDIF WEND ' check package is installed or not SHELL "rpm -q --queryformat %{NAME}\"\n\" `cat " & sPathTmpLst & "` | grep -v " & ("is not installed") TO sOutput aRes = Split(sOutput, "\n") FOR EACH sRes IN aRes IF Len(sRes) > 0 THEN cApplications[sRes][idCkBox] = "On" cApplications[sRes][idStat] = "Installed" ENDIF NEXT ENDIF ' remove unavailable package when summary is blank ' (BTS:wished:236>) FOR EACH aElement IN cApplications IF aElement[idSumm] = "" THEN cApplications.Remove(cApplications.key) ENDIF NEXT END PUBLIC SUB CreateAppList() DIM hBox AS HBox ' DIM hCheckbox AS CheckBox DIM hTextLabel AS TextLabel DIM hPict AS PictureBox DIM hPanel AS Panel DIM element AS String[] DIM i AS Integer DIM mImage AS Image 'temporaly copy of icon to overlay check mark ' enable main form whlie adding items (workaround for ) FMain.Enabled = TRUE IF lctApps.Count > 0 THEN lctApps.Clear FOR EACH element IN cApplications ' create HBox hBox = NEW HBox(lctApps) hBox.Padding = 1 hBox.Spacing = 0 hBox.Height = iHeightHBox hBox.Name = cApplications.Key ' create PictureBox for icon hPict = NEW PictureBox(hBox) hPict.Alignment = Align.left hPict.Width = 52 hPict.Height = 28 mImage = NEW Image(48, 28) mImage.Fill(Color.Transparent) IF Exist(sBaseDir &/ element[idCat] &/ "icons" &/ cApplications.Key & ".png") = TRUE THEN mImage.Draw(Image.Load(sBaseDir &/ element[idCat] &/ "icons" &/ cApplications.Key & ".png").stretch(28, 28), 10, 0) ELSE mImage.Draw(Image.Load("noicon28.png"), 10, 0) ENDIF IF element[idStat] = "Installed" THEN mImage.Draw(Image.Load("checkmark.png"), 30, 0) ENDIF hPict.Picture = mImage.Picture ' create TextLabel for application name hTextLabel = NEW TextLabel(hBox) hTextLabel.Expand = TRUE hTextLabel.Alignment = Align.Normal hTextLabel.Text = "" & cApplications.Key & "
" hTextLabel.Text &= element[idSumm] NEXT ' disable main form again (workaround for ) FMain.Enabled = FALSE END PUBLIC SUB FilterLctApps() DIM i AS Integer DIM iCount AS Integer = 0 DIM sName AS String ' hide unmatch application with specified category and state FOR i = 0 TO lctApps.Children.Count - 1 sName = lctApps.Children[i].Name IF CkCategory(sName) = TRUE AND CkState(sName) = TRUE THEN INC iCount lctApps.Children[i].Height = iHeightHBox lctApps.Children[i].Visible = TRUE ELSE lctApps.Children[i].Height = 0 lctApps.Children[i].Visible = FALSE ENDIF NEXT END FUNCTION CkCategory(sApp AS String) AS Boolean ' return immediately while loading the app list IF lctCategory.Current = NULL THEN RETURN FALSE IF lctCategory.Current.Name = "Search" THEN RETURN CkSearch(sApp) ELSE IF cApplications[sApp][idCat] = lctCategory.Current.Name THEN RETURN TRUE ELSE RETURN FALSE ENDIF ENDIF END FUNCTION CkState(sApp AS String) AS Boolean ' return TRUE if an application shold be shown SELECT CASE cbxState.Text CASE ("Installed") IF cApplications[sApp][idStat] = "Installed" THEN RETURN TRUE ELSE RETURN FALSE ENDIF CASE ("Not installed") IF cApplications[sApp][idStat] = "NotInstalled" THEN RETURN TRUE ELSE RETURN FALSE ENDIF DEFAULT RETURN TRUE END SELECT END PUBLIC SUB CkSearch(sApp AS String) AS Boolean ' return TRUE if name , summary or description contains serch term IF InStr(sApp, sSearchTerm, 0, gb.Text) > 0 OR InStr(cApplications[sApp][idSumm], sSearchTerm, 0, gb.Text) > 0 OR InStr(cApplications[sApp][idDesc], sSearchTerm, 0, gb.Text) > 0 THEN RETURN TRUE ELSE RETURN FALSE ENDIF END FUNCTION ConvUnit(sSize AS String) AS String DIM iConv AS Integer = 0 DIM fConv AS Float = 0 IF Val(sSize) < 1024 THEN RETURN sSize & "Byte" ELSE IF Val(sSize) < 1048576 THEN iConv = Int(Val(sSize) / 1024) RETURN Str(iConv) & "KB" ELSE fConv = Val(sSize) / 1024 / 1024 RETURN Str(Format(fConv, "####.#")) & "MB" ENDIF END FUNCTION FindCategory(sCat AS String) AS Integer ' check specified category and return internal number (of return -1 if not exist) DIM i AS Integer DIM bRes AS Boolean = FALSE FOR i = 0 TO lctCategory.Children.Count - 1 IF lctCategory.Children[i].Name = sCat THEN bRes = TRUE BREAK ENDIF NEXT IF bRes = TRUE THEN RETURN i ELSE RETURN -1 ENDIF END