' Gambas class file
PUBLIC sBaseDir AS String = "/usr/share/vine-app-install-data/"
PUBLIC sPathLua AS String = "/usr/share/vine-app-install/list-package-info.lua"
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 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 SUB Form_Open()
'setup left(category) panel
hspMain.Layout = "180," & CStr(hspMain.Width - 180)
AddCategories("All", ("All"), Stock["24/package"])
AddCategories("Accessories", ("Accessories"), Picture[sIconDir & "applications-accessories.png"])
AddCategories("Internet", ("Internet"), Picture[sIconDir & "applications-internet.png"])
AddCategories("Office", ("Office"), Picture[sIconDir & "applications-office.png"])
AddCategories("Graphics", ("Graphics"), Picture[sIconDir & "applications-graphics.png"])
AddCategories("Multimedia", ("Multimedia"), Picture[sIconDir & "applications-multimedia.png"])
AddCategories("Games", ("Games"), Picture[sIconDir & "applications-games.png"])
AddCategories("System", ("System"), Picture[sIconDir & "applications-system.png"])
AddCategories("Development", ("Development"), Picture[sIconDir & "applications-development.png"])
AddCategories("Other", ("Other"), Picture[sIconDir & "applications-other.png"])
AddCategories("Tasks", ("Tasks"), Stock["24/component"])
AddCategories("Restricted", ("Restricted"), Stock["24/lock"])
' start with "All" is selected
lctCategory.Select(lctCategory.Children[0])
' adjust some widgets size according to it's font size
''' bottom buttons
btnHelp.Width = btnHelp.Font.Width(btnHelp.Text) + 48
btnApply.Width = btnApply.Font.Width(btnApply.Text) + 48
btnClose.Width = btnClose.Font.Width(btnClose.Text) + 48
hbxBottom.Height = btnClose.Font.Height(btnClose.Text) + 16
''' top combo box and serarch area
hbxTop.Height = tbxSearch.Font.Height(tbxSearch.Text) + 16
''' keep search button square
btnSearch.Width = btnSearch.Height
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_MouseDown()
DIM sApp AS String
DIM iSsHeight AS Integer
DIM hPict AS Picture
' 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 = CStr(vspRight.Height / 2) & "," & CStr(vspRight.Height / 2)
ENDIF
' set icon(large) and description of selected package
sApp = lctApps.Current.Name
tlbAppDesc.Text = "" & sApp & "
"
tlbAppDesc.Text &= cApplications[sApp][idDesc]
IF Exist(sBaseDir &/ cApplications[sApp][idCat] &/ "icons" &/ sApp & ".png") = TRUE THEN
pbxDetail.Picture = Image.Load(sBaseDir &/ cApplications[sApp][idCat] &/ "icons" &/ sApp & ".png").stretch(48, 48).Picture
ELSE
pbxDetail.Picture = Picture["noicon.png"]
ENDIF
' set screenshot if available
IF Exist(sBaseDir &/ cApplications[sApp][idCat] &/ "screenshots" &/ sApp & ".png") = TRUE THEN
hPict = Picture[sBaseDir &/ cApplications[sApp][idCat] &/ "screenshots" &/ sApp & ".png"]
iSsHeight = hPict.Height / hPict.Width * pbxThumb.Width
pbxThumb.Picture = hPict.Image.Stretch(pbxThumb.Width, iSsHeight).Picture
pbxThumb.Mouse = Mouse.Pointing
pbxThumb.Visible = TRUE
ELSE
pbxThumb.Mouse = Mouse.Default
pbxThumb.Visible = FALSE
ENDIF
END
PUBLIC SUB pbxThumb_MouseUp()
DIM sName AS String
sName = lctApps.Current.Name
EXEC ["xdg-open", sBaseDir &/ cApplications[sName][idCat] &/ "screenshots" &/ sName & ".png"]
END
PUBLIC SUB CheckBoxes_Click()
DIM sApp AS String
' ignore useless event call while loading the application data
IF FMain.Enabled = FALSE THEN RETURN
sApp = LAST.Parent.Name
' synchronize checkbox valu and idCkBox value
IF LAST.Value = CheckBox.True THEN
cApplications[sApp][idCkBox] = "On"
ELSE
cApplications[sApp][idCkBox] = "Off"
ENDIF
' change color of selected application
IF LAST.Value = CheckBox.TRUE AND cApplications[sApp][idStat] = "NotInstalled" THEN
LAST.Parent.Children[1].Background = Color.DarkGreen
LAST.Parent.Children[2].Background = Color.DarkGreen
LAST.Parent.Children[3].Background = Color.DarkGreen
LAST.Parent.Children[3].Foreground = Color.White
ELSE IF LAST.Value = CheckBox.False AND cApplications[sApp][idStat] = "Installed" THEN
LAST.Parent.Children[1].Background = Color.Darkred
LAST.Parent.Children[2].Background = Color.Darkred
LAST.Parent.Children[3].Background = Color.Darkred
LAST.Parent.Children[3].Foreground = Color.White
ELSE
LAST.Parent.Children[1].Background = Color.Default
LAST.Parent.Children[2].Background = Color.Default
LAST.Parent.Children[3].Background = Color.Default
LAST.Parent.Children[3].Foreground = Color.Default
ENDIF
END
PUBLIC SUB lctCategory_Click()
FilterLctApps()
END
PUBLIC SUB cbxState_Click()
FilterLctApps()
END
PUBLIC SUB btnSearch_Click()
btnSearch.SetFocus
FilterLctApps()
END
PUBLIC SUB btnApply_Click()
DIM sSelection AS String
DIM hProcess AS Stream
DIM element AS String[]
FOR EACH element IN cApplications
IF element[idCkBox] = "On" AND element[idStat] = "NotInstalled" THEN
sSelection &= cApplications.Key & " " & "install" & "\n"
ELSE IF element[idCkBox] = "Off" AND element[idStat] = "Installed" THEN
sSelection &= cApplications.Key & " " & "delete" & "\n"
ENDIF
NEXT
IF Len(sSelection) > 0 THEN
FMain.Enabled = FALSE
FMain.Mouse = Mouse.Wait
hProcess = EXEC ["synaptic", "--non-interactive", "--hide-main-window", "--set-selections", "<"] FOR WRITE AS "ShellSynaptic"
PRINT #hProcess, sSelection;
CLOSE #hProcess
ELSE
Message.Error(("Nothing marked as install and/or remove"))
ENDIF
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
PUBLIC SUB Form_KeyPress()
' set focus on search field when Ctrl + K pressed
IF Key.Control = TRUE AND Key.Code = Key["K"] THEN tbxSearch.SetFocus
END
PUBLIC SUB tbxSearch_KeyPress()
' press enter key then start serch
IF Key.Code = Key.Return THEN FilterLctApps()
END
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'' procedures and functions (including process event)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
PUBLIC SUB AddCategories(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 an redirect standard output to temporary file
' and we should use a file to pass large number of application names (possibly a bug or not?).
SHELL "apt-get script " & sPathLua & " < " & sPathTmpLst & " | tee " & sPathTmpRes FOR READ AS "AptScript"
END
PUBLIC SUB AptScript_Read()
DIM sLine AS String
LINE INPUT #LAST, sLine
IF sLine LIKE ("Reading Package Lists*") OR sLine LIKE ("Building Dependency Tree*") OR sLine LIKE "Package: *" THEN
pgbProgress.Value = iCount / (cApplications.Count + 2)
INC iCount
WAIT 0.001 ' wait a mili second for progress bar drawing
ENDIF
END
PUBLIC SUB AptScript_Error(sStr AS String)
bScriptError = TRUE
END
PUBLIC SUB AptScript_Kill()
IF bScriptError = TRUE 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()
pgbProgress.Visible = FALSE
FMain.Mouse = Mouse.Default
FMain.Enabled = TRUE
' 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)
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
CASE "State"
IF Right(sLine, Len(Sline) - 7) = "Installed" THEN
cApplications[sAppName][idCkBox] = "On"
cApplications[sAppName][idStat] = "Installed"
ELSE
cApplications[sAppName][idCkBox] = "Off"
cApplications[sAppName][idStat] = "NotInstalled"
END IF
CASE "Summary"
cApplications[sAppName][idSumm] = Right(sLine, Len(sLine) - 9)
CASE "Description"
END SELECT
ELSE
' assume only description has multi line text
IF sAppName <> "" THEN
cApplications[sAppName][idDesc] &= sLine & "
"
ENDIF
ENDIF
WEND
ENDIF
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
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 panel (for space adjustment)
hPanel = NEW Panel(hBox)
HPanel.Width = 4
HPanel.Height = iHeightHBox
' create checkbox
hCheckbox = NEW CheckBox(hBox) AS "CheckBoxes"
hCheckbox.Width = 20
hCheckbox.Height = 24
IF element[idStat] = "Installed" THEN
hCheckbox.Value = TRUE
ELSE
hCheckbox.Value = FALSE
ENDIF
' create PictureBox for icon
hPict = NEW PictureBox(hBox)
hPict.Alignment = Align.Center
hPict.Width = 32
hPict.Height = 24
IF Exist(sBaseDir &/ element[idCat] &/ "icons" &/ cApplications.Key & ".png") = TRUE THEN
hPict.Picture = Image.Load(sBaseDir &/ element[idCat] &/ "icons" &/ cApplications.Key & ".png").stretch(24, 24).Picture
ELSE
hPict.Picture = Picture["noicon24.png"]
ENDIF
' 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
END
PUBLIC SUB FilterLctApps()
DIM i AS Integer
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 AND CkSearch(sName) = TRUE THEN
lctApps.Children[i].Height = iHeightHBox
lctApps.Children[i].Visible = TRUE
ELSE
lctApps.Children[i].Height = 0
lctApps.Children[i].Visible = FALSE
ENDIF
NEXT
lctApps.Refresh()
END
FUNCTION CkCategory(sApp AS String) AS Boolean
' return TRUE if an application shold be shown
IF cApplications[sApp][idCat] = lctCategory.Current.Name OR lctCategory.Current.Name = "All" THEN ' show all rows if "All" is selected
RETURN TRUE
ELSE
RETURN FALSE
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
CASE ("Marked changes")
IF cApplications[sApp][idStat] = "Installed" AND cApplications[sApp][idCkBox] = "Off" THEN
RETURN TRUE
ELSE IF cApplications[sApp][idStat] = "NotInstalled" AND cApplications[sApp][idCkBox] = "On" THEN
RETURN TRUE
ELSE
RETURN FALSE
ENDIF
DEFAULT
RETURN TRUE
END SELECT
END
PUBLIC SUB CkSearch(sApp AS String) AS Boolean
' return TRUE if serch term is not specified
IF tbxSearch.Text = "" OR tbxSearch.Text = ("Enter search term") THEN RETURN TRUE
' return TRUE if name , summary or description contains serch term
IF InStr(sApp, tbxSearch.Text, 0, gb.Text) > 0 OR InStr(cApplications[sApp][idSumm], tbxSearch.Text, 0, gb.Text) > 0 OR InStr(cApplications[sApp][idDesc], tbxSearch.Text, 0, gb.Text) > 0 THEN
RETURN TRUE
ELSE
RETURN FALSE
ENDIF
END