mirror of
https://github.com/Xpl0itU/WiiUDownloader.git
synced 2025-05-09 13:52:02 -04:00
Improve queue management
This commit is contained in:
parent
d7abadd317
commit
d8e17cb3b4
6 changed files with 291 additions and 244 deletions
|
@ -58,16 +58,19 @@ func main() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
app.Connect("activate", func() {
|
||||
win := NewMainWindow(app, wiiudownloader.GetTitleEntries(wiiudownloader.TITLE_CATEGORY_GAME), client, config)
|
||||
config.saveConfigCallback = func() {
|
||||
win.applyConfig(config)
|
||||
}
|
||||
win.ShowAll()
|
||||
app.AddWindow(win.window)
|
||||
app.GetActiveWindow().Show()
|
||||
win := NewMainWindow(wiiudownloader.GetTitleEntries(wiiudownloader.TITLE_CATEGORY_GAME), client, config)
|
||||
config.saveConfigCallback = func() {
|
||||
win.applyConfig(config)
|
||||
}
|
||||
|
||||
app.Connect("activate", func(app *gtk.Application) {
|
||||
win.SetApplicationForGTKWindow(app)
|
||||
glib.IdleAddPriority(glib.PRIORITY_HIGH, func() {
|
||||
win.ShowAll()
|
||||
app.AddWindow(win.window)
|
||||
app.GetActiveWindow().Show()
|
||||
})
|
||||
gtk.Main()
|
||||
})
|
||||
app.Run(nil)
|
||||
app.Quit()
|
||||
glib.ApplicationGetDefault().Run(os.Args)
|
||||
}
|
||||
|
|
|
@ -26,16 +26,15 @@ const (
|
|||
)
|
||||
|
||||
type MainWindow struct {
|
||||
window *gtk.ApplicationWindow
|
||||
window *gtk.Window
|
||||
queuePane *QueuePane
|
||||
treeView *gtk.TreeView
|
||||
searchEntry *gtk.Entry
|
||||
deleteEncryptedContentsCheckbox *gtk.CheckButton
|
||||
deleteEncryptedContents bool
|
||||
addToQueueButton *gtk.Button
|
||||
progressWindow *ProgressWindow
|
||||
configWindow *ConfigWindow
|
||||
lastSearchText string
|
||||
titleQueue []wiiudownloader.TitleEntry
|
||||
categoryButtons []*gtk.ToggleButton
|
||||
titles []wiiudownloader.TitleEntry
|
||||
decryptContents bool
|
||||
|
@ -43,14 +42,14 @@ type MainWindow struct {
|
|||
client *http.Client
|
||||
}
|
||||
|
||||
func NewMainWindow(app *gtk.Application, entries []wiiudownloader.TitleEntry, client *http.Client, config *Config) *MainWindow {
|
||||
win, err := gtk.ApplicationWindowNew(app)
|
||||
func NewMainWindow(entries []wiiudownloader.TitleEntry, client *http.Client, config *Config) *MainWindow {
|
||||
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to create window:", err)
|
||||
}
|
||||
|
||||
win.SetTitle("WiiUDownloader")
|
||||
win.SetDefaultSize(716, 400)
|
||||
win.SetDefaultSize(870, 400)
|
||||
win.Connect("destroy", func() {
|
||||
gtk.MainQuit()
|
||||
})
|
||||
|
@ -59,9 +58,17 @@ func NewMainWindow(app *gtk.Application, entries []wiiudownloader.TitleEntry, cl
|
|||
if err != nil {
|
||||
log.Fatalln("Unable to create entry:", err)
|
||||
}
|
||||
searchEntry.SetPlaceholderText("Search...")
|
||||
searchEntry.SetHExpand(false)
|
||||
|
||||
queuePane, err := NewQueuePane()
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to create queue pane:", err)
|
||||
}
|
||||
|
||||
mainWindow := MainWindow{
|
||||
window: win,
|
||||
queuePane: queuePane,
|
||||
titles: entries,
|
||||
searchEntry: searchEntry,
|
||||
currentRegion: wiiudownloader.MCP_REGION_EUROPE | wiiudownloader.MCP_REGION_JAPAN | wiiudownloader.MCP_REGION_USA,
|
||||
|
@ -69,6 +76,8 @@ func NewMainWindow(app *gtk.Application, entries []wiiudownloader.TitleEntry, cl
|
|||
client: client,
|
||||
}
|
||||
|
||||
queuePane.updateFunc = mainWindow.updateTitlesInQueue
|
||||
|
||||
mainWindow.applyConfig(config)
|
||||
|
||||
searchEntry.Connect("changed", mainWindow.onSearchEntryChanged)
|
||||
|
@ -76,6 +85,10 @@ func NewMainWindow(app *gtk.Application, entries []wiiudownloader.TitleEntry, cl
|
|||
return &mainWindow
|
||||
}
|
||||
|
||||
func (mw *MainWindow) SetApplicationForGTKWindow(app *gtk.Application) {
|
||||
mw.window.SetApplication(app)
|
||||
}
|
||||
|
||||
func (mw *MainWindow) updateTitles(titles []wiiudownloader.TitleEntry) {
|
||||
store, err := gtk.ListStoreNew(glib.TYPE_BOOLEAN, glib.TYPE_STRING, glib.TYPE_STRING, glib.TYPE_STRING, glib.TYPE_STRING)
|
||||
if err != nil {
|
||||
|
@ -89,7 +102,7 @@ func (mw *MainWindow) updateTitles(titles []wiiudownloader.TitleEntry) {
|
|||
iter := store.Append()
|
||||
if err := store.Set(iter,
|
||||
[]int{IN_QUEUE_COLUMN, KIND_COLUMN, TITLE_ID_COLUMN, REGION_COLUMN, NAME_COLUMN},
|
||||
[]interface{}{mw.isTitleInQueue(entry), wiiudownloader.GetFormattedKind(entry.TitleID), fmt.Sprintf("%016x", entry.TitleID), wiiudownloader.GetFormattedRegion(entry.Region), entry.Name},
|
||||
[]interface{}{mw.queuePane.IsTitleInQueue(entry), wiiudownloader.GetFormattedKind(entry.TitleID), fmt.Sprintf("%016x", entry.TitleID), wiiudownloader.GetFormattedRegion(entry.Region), entry.Name},
|
||||
); err != nil {
|
||||
log.Fatalln("Unable to set values:", err)
|
||||
}
|
||||
|
@ -137,7 +150,7 @@ func (mw *MainWindow) ShowAll() {
|
|||
iter := store.Append()
|
||||
err = store.Set(iter,
|
||||
[]int{IN_QUEUE_COLUMN, KIND_COLUMN, TITLE_ID_COLUMN, REGION_COLUMN, NAME_COLUMN},
|
||||
[]interface{}{mw.isTitleInQueue(entry), wiiudownloader.GetFormattedKind(entry.TitleID), fmt.Sprintf("%016x", entry.TitleID), wiiudownloader.GetFormattedRegion(entry.Region), entry.Name},
|
||||
[]interface{}{mw.queuePane.IsTitleInQueue(entry), wiiudownloader.GetFormattedKind(entry.TitleID), fmt.Sprintf("%016x", entry.TitleID), wiiudownloader.GetFormattedRegion(entry.Region), entry.Name},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to set values:", err)
|
||||
|
@ -191,22 +204,16 @@ func (mw *MainWindow) ShowAll() {
|
|||
if err != nil {
|
||||
log.Fatalln("Unable to get value:", err)
|
||||
}
|
||||
parsedTid, err := strconv.ParseUint(tidStr, 16, 64)
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to parse title ID:", err)
|
||||
}
|
||||
if isInQueue.(bool) {
|
||||
mw.removeFromQueue(tidStr)
|
||||
mw.queuePane.RemoveTitle(wiiudownloader.TitleEntry{TitleID: parsedTid})
|
||||
} else {
|
||||
name, err := store.ToTreeModel().GetValue(iter, NAME_COLUMN)
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to get value:", err)
|
||||
}
|
||||
nameStr, err := name.GetString()
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to get value:", err)
|
||||
}
|
||||
mw.addToQueue(tidStr, nameStr)
|
||||
name.Unset()
|
||||
mw.queuePane.AddTitle(wiiudownloader.GetTitleEntryFromTid(parsedTid))
|
||||
}
|
||||
mw.updateTitlesInQueue()
|
||||
mw.onSelectionChanged()
|
||||
})
|
||||
column, err := gtk.TreeViewColumnNewWithAttribute("Queue", toggleRenderer, "active", IN_QUEUE_COLUMN)
|
||||
if err != nil {
|
||||
|
@ -224,10 +231,6 @@ func (mw *MainWindow) ShowAll() {
|
|||
}
|
||||
mw.treeView.AppendColumn(column)
|
||||
|
||||
renderer, err = gtk.CellRendererTextNew()
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to create cell renderer:", err)
|
||||
}
|
||||
column, err = gtk.TreeViewColumnNewWithAttribute("Title ID", renderer, "text", TITLE_ID_COLUMN)
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to create tree view column:", err)
|
||||
|
@ -240,10 +243,6 @@ func (mw *MainWindow) ShowAll() {
|
|||
}
|
||||
mw.treeView.AppendColumn(column)
|
||||
|
||||
renderer, err = gtk.CellRendererTextNew()
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to create cell renderer:", err)
|
||||
}
|
||||
column, err = gtk.TreeViewColumnNewWithAttribute("Name", renderer, "text", NAME_COLUMN)
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to create tree view column:", err)
|
||||
|
@ -387,7 +386,6 @@ func (mw *MainWindow) ShowAll() {
|
|||
log.Fatalln("Unable to create scrolled window:", err)
|
||||
}
|
||||
scrollable.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
selection.Connect("changed", mw.onSelectionChanged)
|
||||
scrollable.Add(mw.treeView)
|
||||
|
||||
mainvBox.PackStart(scrollable, true, true, 0)
|
||||
|
@ -397,11 +395,6 @@ func (mw *MainWindow) ShowAll() {
|
|||
log.Fatalln("Unable to create box:", err)
|
||||
}
|
||||
|
||||
mw.addToQueueButton, err = gtk.ButtonNewWithLabel("Add to queue")
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to create button:", err)
|
||||
}
|
||||
|
||||
downloadQueueButton, err := gtk.ButtonNewWithLabel("Download queue")
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to create button:", err)
|
||||
|
@ -430,9 +423,8 @@ func (mw *MainWindow) ShowAll() {
|
|||
}
|
||||
})
|
||||
|
||||
mw.addToQueueButton.Connect("clicked", mw.onAddToQueueClicked)
|
||||
downloadQueueButton.Connect("clicked", func() {
|
||||
if len(mw.titleQueue) == 0 {
|
||||
if mw.queuePane.IsQueueEmpty() {
|
||||
return
|
||||
}
|
||||
mw.progressWindow, err = createProgressWindow(mw.window)
|
||||
|
@ -457,7 +449,6 @@ func (mw *MainWindow) ShowAll() {
|
|||
}()
|
||||
})
|
||||
decryptContentsCheckbox.Connect("clicked", mw.onDecryptContentsClicked)
|
||||
bottomhBox.PackStart(mw.addToQueueButton, false, false, 0)
|
||||
bottomhBox.PackStart(downloadQueueButton, false, false, 0)
|
||||
|
||||
checkboxvBox, err := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
|
||||
|
@ -501,14 +492,21 @@ func (mw *MainWindow) ShowAll() {
|
|||
|
||||
mainvBox.PackEnd(bottomhBox, false, false, 0)
|
||||
|
||||
mainvBox.SetMarginBottom(2)
|
||||
mainvBox.SetMarginEnd(2)
|
||||
mainvBox.SetMarginStart(2)
|
||||
mainvBox.SetMarginTop(2)
|
||||
splitPane, err := gtk.PanedNew(gtk.ORIENTATION_HORIZONTAL)
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to create paned:", err)
|
||||
}
|
||||
splitPane.Pack1(mw.queuePane.GetContainer(), true, false)
|
||||
splitPane.Pack2(mainvBox, true, true)
|
||||
|
||||
mw.window.Add(mainvBox)
|
||||
splitPane.SetMarginBottom(2)
|
||||
splitPane.SetMarginEnd(2)
|
||||
splitPane.SetMarginStart(2)
|
||||
splitPane.SetMarginTop(2)
|
||||
|
||||
mainvBox.ShowAll()
|
||||
mw.window.Add(splitPane)
|
||||
|
||||
splitPane.ShowAll()
|
||||
}
|
||||
|
||||
func (mw *MainWindow) onRegionChange(button *gtk.CheckButton, region uint8) {
|
||||
|
@ -556,7 +554,7 @@ func (mw *MainWindow) filterTitles(filterText string) {
|
|||
iter := storeRef.Append()
|
||||
if err := storeRef.Set(iter,
|
||||
[]int{IN_QUEUE_COLUMN, KIND_COLUMN, TITLE_ID_COLUMN, REGION_COLUMN, NAME_COLUMN},
|
||||
[]interface{}{mw.isTitleInQueue(entry), wiiudownloader.GetFormattedKind(entry.TitleID), fmt.Sprintf("%016x", entry.TitleID), wiiudownloader.GetFormattedRegion(entry.Region), entry.Name},
|
||||
[]interface{}{mw.queuePane.IsTitleInQueue(entry), wiiudownloader.GetFormattedKind(entry.TitleID), fmt.Sprintf("%016x", entry.TitleID), wiiudownloader.GetFormattedRegion(entry.Region), entry.Name},
|
||||
); err != nil {
|
||||
log.Fatalln("Unable to set values:", err)
|
||||
}
|
||||
|
@ -587,64 +585,6 @@ func (mw *MainWindow) onDecryptContentsMenuItemClicked(selectedPath string) erro
|
|||
return err
|
||||
}
|
||||
|
||||
func (mw *MainWindow) isSelectionInQueue() bool {
|
||||
selection, err := mw.treeView.GetSelection()
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to get selection:", err)
|
||||
}
|
||||
|
||||
store, err := mw.treeView.GetModel()
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to get model:", err)
|
||||
}
|
||||
|
||||
storeRef := store.(*gtk.ListStore)
|
||||
treeModel := storeRef.ToTreeModel()
|
||||
if treeModel == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
selectionSelected := selection.GetSelectedRows(treeModel)
|
||||
if selectionSelected == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := uint(0); i < selectionSelected.Length(); i++ {
|
||||
path, ok := selectionSelected.Nth(i).Data().(*gtk.TreePath)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
iter, err := treeModel.GetIter(path)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
inQueueVal, err := treeModel.GetValue(iter, IN_QUEUE_COLUMN)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
isInQueue, err := inQueueVal.GoValue()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if !isInQueue.(bool) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (mw *MainWindow) onSelectionChanged() {
|
||||
if mw.isSelectionInQueue() {
|
||||
mw.addToQueueButton.SetLabel("Remove from queue")
|
||||
} else {
|
||||
mw.addToQueueButton.SetLabel("Add to queue")
|
||||
}
|
||||
}
|
||||
|
||||
func (mw *MainWindow) onDecryptContentsClicked() {
|
||||
mw.decryptContents = !mw.decryptContents
|
||||
mw.deleteEncryptedContentsCheckbox.SetSensitive(mw.decryptContents)
|
||||
|
@ -665,119 +605,6 @@ func (mw *MainWindow) getDeleteEncryptedContents() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (mw *MainWindow) isTitleInQueue(title wiiudownloader.TitleEntry) bool {
|
||||
for _, entry := range mw.titleQueue {
|
||||
if entry.TitleID == title.TitleID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (mw *MainWindow) addToQueue(tid, name string) {
|
||||
titleID, err := strconv.ParseUint(tid, 16, 64)
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to parse title ID:", err)
|
||||
}
|
||||
mw.titleQueue = append(mw.titleQueue, wiiudownloader.TitleEntry{TitleID: titleID, Name: name})
|
||||
}
|
||||
|
||||
func (mw *MainWindow) removeFromQueue(tid string) {
|
||||
for i, entry := range mw.titleQueue {
|
||||
if fmt.Sprintf("%016x", entry.TitleID) == tid {
|
||||
mw.titleQueue = append(mw.titleQueue[:i], mw.titleQueue[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (mw *MainWindow) onAddToQueueClicked() {
|
||||
selection, err := mw.treeView.GetSelection()
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to get selection:", err)
|
||||
}
|
||||
|
||||
store, err := mw.treeView.GetModel()
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to get model:", err)
|
||||
}
|
||||
|
||||
storeRef := store.(*gtk.ListStore)
|
||||
treeModel := storeRef.ToTreeModel()
|
||||
if treeModel == nil {
|
||||
return
|
||||
}
|
||||
|
||||
addToQueue := !mw.isSelectionInQueue()
|
||||
|
||||
selectionSelected := selection.GetSelectedRows(treeModel)
|
||||
if selectionSelected == nil || selectionSelected.Length() == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Fatalln("Error updating model:", r)
|
||||
}
|
||||
}()
|
||||
|
||||
iter, _ := treeModel.GetIterFirst()
|
||||
for iter != nil {
|
||||
isSelected := selection.IterIsSelected(iter)
|
||||
if isSelected {
|
||||
inQueueVal, err := treeModel.GetValue(iter, IN_QUEUE_COLUMN)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
isInQueue, err := inQueueVal.GoValue()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if addToQueue != isInQueue.(bool) {
|
||||
inQueueVal.SetBool(addToQueue)
|
||||
|
||||
tid, err := treeModel.GetValue(iter, TITLE_ID_COLUMN)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
tidStr, err := tid.GetString()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if addToQueue {
|
||||
name, err := treeModel.GetValue(iter, NAME_COLUMN)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
nameStr, err := name.GetString()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
mw.addToQueue(tidStr, nameStr)
|
||||
name.Unset()
|
||||
} else {
|
||||
mw.removeFromQueue(tidStr)
|
||||
}
|
||||
|
||||
storeRef.SetValue(iter, IN_QUEUE_COLUMN, addToQueue)
|
||||
tid.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
if !storeRef.IterNext(iter) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if addToQueue {
|
||||
mw.addToQueueButton.SetLabel("Remove from queue")
|
||||
} else {
|
||||
mw.addToQueueButton.SetLabel("Add to queue")
|
||||
}
|
||||
}
|
||||
|
||||
func (mw *MainWindow) updateTitlesInQueue() {
|
||||
store, err := mw.treeView.GetModel()
|
||||
if err != nil {
|
||||
|
@ -801,7 +628,7 @@ func (mw *MainWindow) updateTitlesInQueue() {
|
|||
if err != nil {
|
||||
continue
|
||||
}
|
||||
isInQueue := mw.isTitleInQueue(wiiudownloader.TitleEntry{TitleID: tidNum})
|
||||
isInQueue := mw.queuePane.IsTitleInQueue(wiiudownloader.TitleEntry{TitleID: tidNum})
|
||||
storeRef.SetValue(iter, IN_QUEUE_COLUMN, isInQueue)
|
||||
tid.Unset()
|
||||
}
|
||||
|
@ -810,6 +637,7 @@ func (mw *MainWindow) updateTitlesInQueue() {
|
|||
break
|
||||
}
|
||||
}
|
||||
mw.queuePane.Update(false)
|
||||
}
|
||||
|
||||
func (mw *MainWindow) showError(err error) {
|
||||
|
@ -822,7 +650,7 @@ func (mw *MainWindow) showError(err error) {
|
|||
}
|
||||
|
||||
func (mw *MainWindow) onDownloadQueueClicked(selectedPath string) error {
|
||||
if len(mw.titleQueue) == 0 {
|
||||
if mw.queuePane.IsQueueEmpty() {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -832,7 +660,7 @@ func (mw *MainWindow) onDownloadQueueClicked(selectedPath string) error {
|
|||
defer close(queueStatusChan)
|
||||
errGroup := errgroup.Group{}
|
||||
|
||||
for _, title := range mw.titleQueue {
|
||||
mw.queuePane.ForEachRemoving(func(title wiiudownloader.TitleEntry) {
|
||||
errGroup.Go(func() error {
|
||||
if mw.progressWindow.cancelled {
|
||||
queueStatusChan <- true
|
||||
|
@ -853,16 +681,15 @@ func (mw *MainWindow) onDownloadQueueClicked(selectedPath string) error {
|
|||
}
|
||||
|
||||
if !<-queueStatusChan {
|
||||
break
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
mw.titleQueue = []wiiudownloader.TitleEntry{} // Clear the queue
|
||||
mw.queuePane.Clear()
|
||||
glib.IdleAdd(func() {
|
||||
mw.progressWindow.Window.Hide()
|
||||
})
|
||||
mw.updateTitlesInQueue()
|
||||
mw.onSelectionChanged()
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ func (pw *ProgressWindow) SetStartTime(startTime time.Time) {
|
|||
pw.startTime = startTime
|
||||
}
|
||||
|
||||
func createProgressWindow(parent *gtk.ApplicationWindow) (*ProgressWindow, error) {
|
||||
func createProgressWindow(parent *gtk.Window) (*ProgressWindow, error) {
|
||||
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
220
cmd/WiiUDownloader/queuePane.go
Normal file
220
cmd/WiiUDownloader/queuePane.go
Normal file
|
@ -0,0 +1,220 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
|
||||
wiiudownloader "github.com/Xpl0itU/WiiUDownloader"
|
||||
"github.com/gotk3/gotk3/glib"
|
||||
"github.com/gotk3/gotk3/gtk"
|
||||
)
|
||||
|
||||
type QueuePane struct {
|
||||
container *gtk.Box
|
||||
titleTreeView *gtk.TreeView
|
||||
titleQueue []wiiudownloader.TitleEntry
|
||||
store *gtk.ListStore
|
||||
updateFunc func()
|
||||
}
|
||||
|
||||
func createColumn(renderer *gtk.CellRendererText, title string, id int) *gtk.TreeViewColumn {
|
||||
column, _ := gtk.TreeViewColumnNewWithAttribute(title, renderer, "text", id)
|
||||
return column
|
||||
}
|
||||
|
||||
func NewQueuePane() (*QueuePane, error) {
|
||||
scrolledWindow, err := gtk.ScrolledWindowNew(nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scrolledWindow.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
|
||||
store, err := gtk.ListStoreNew(glib.TYPE_STRING, glib.TYPE_STRING, glib.TYPE_STRING)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
titleTreeView, err := gtk.TreeViewNew()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
selection, err := titleTreeView.GetSelection()
|
||||
if err != nil {
|
||||
log.Fatalln("Unable to get selection:", err)
|
||||
}
|
||||
selection.SetMode(gtk.SELECTION_MULTIPLE)
|
||||
|
||||
titleTreeView.SetModel(store)
|
||||
|
||||
renderer, err := gtk.CellRendererTextNew()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nameColumn := createColumn(renderer, "Name", 0)
|
||||
nameColumn.SetMaxWidth(200)
|
||||
nameColumn.SetResizable(true)
|
||||
titleTreeView.AppendColumn(nameColumn)
|
||||
regionColumn := createColumn(renderer, "Region", 1)
|
||||
regionColumn.SetMaxWidth(70)
|
||||
titleTreeView.AppendColumn(regionColumn)
|
||||
titleIDColumn := createColumn(renderer, "Title ID", 2)
|
||||
titleIDColumn.SetMaxWidth(125)
|
||||
titleTreeView.AppendColumn(titleIDColumn)
|
||||
titleTreeView.SetExpanderColumn(nameColumn)
|
||||
|
||||
scrolledWindow.Add(titleTreeView)
|
||||
|
||||
queueVBox, err := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queueVBox.PackStart(scrolledWindow, true, true, 0)
|
||||
|
||||
queuePane := QueuePane{
|
||||
container: queueVBox,
|
||||
titleTreeView: titleTreeView,
|
||||
store: store,
|
||||
titleQueue: make([]wiiudownloader.TitleEntry, 0),
|
||||
}
|
||||
|
||||
removeFromQueueButton, err := gtk.ButtonNewWithLabel("Remove from Queue")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
removeFromQueueButton.Connect("clicked", func() {
|
||||
selection, err := titleTreeView.GetSelection()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
store, err := titleTreeView.GetModel()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
storeRef := store.(*gtk.ListStore)
|
||||
treeModel := storeRef.ToTreeModel()
|
||||
if treeModel == nil {
|
||||
return
|
||||
}
|
||||
|
||||
selectionSelected := selection.GetSelectedRows(treeModel)
|
||||
if selectionSelected == nil || selectionSelected.Length() == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Fatalln("Error updating model:", r)
|
||||
}
|
||||
}()
|
||||
|
||||
iter, _ := treeModel.GetIterFirst()
|
||||
for iter != nil {
|
||||
isSelected := selection.IterIsSelected(iter)
|
||||
if isSelected {
|
||||
tid, err := treeModel.GetValue(iter, 2)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
tidStr, err := tid.GetString()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
tidParsed, err := strconv.ParseUint(tidStr, 16, 64)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
queuePane.RemoveTitle(wiiudownloader.TitleEntry{TitleID: tidParsed})
|
||||
|
||||
tid.Unset()
|
||||
}
|
||||
|
||||
if !storeRef.IterNext(iter) {
|
||||
break
|
||||
}
|
||||
}
|
||||
queuePane.Update(true)
|
||||
})
|
||||
queueVBox.PackEnd(removeFromQueueButton, false, false, 0)
|
||||
|
||||
return &queuePane, nil
|
||||
}
|
||||
|
||||
func (qp *QueuePane) AddTitle(title wiiudownloader.TitleEntry) {
|
||||
qp.titleQueue = append(qp.titleQueue, title)
|
||||
}
|
||||
|
||||
func (qp *QueuePane) RemoveTitle(title wiiudownloader.TitleEntry) {
|
||||
for i, t := range qp.titleQueue {
|
||||
if t.TitleID == title.TitleID {
|
||||
qp.titleQueue = append(qp.titleQueue[:i], qp.titleQueue[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (qp *QueuePane) Clear() {
|
||||
qp.titleQueue = make([]wiiudownloader.TitleEntry, 0)
|
||||
}
|
||||
|
||||
func (qp *QueuePane) GetContainer() *gtk.Box {
|
||||
return qp.container
|
||||
}
|
||||
|
||||
func (qp *QueuePane) GetTitleQueue() []wiiudownloader.TitleEntry {
|
||||
return qp.titleQueue
|
||||
}
|
||||
|
||||
func (qp *QueuePane) IsQueueEmpty() bool {
|
||||
return len(qp.titleQueue) == 0
|
||||
}
|
||||
|
||||
func (qp *QueuePane) GetTitleQueueSize() int {
|
||||
return len(qp.titleQueue)
|
||||
}
|
||||
|
||||
func (qp *QueuePane) GetTitleQueueAtIndex(index int) wiiudownloader.TitleEntry {
|
||||
return qp.titleQueue[index]
|
||||
}
|
||||
|
||||
func (qp *QueuePane) IsTitleInQueue(title wiiudownloader.TitleEntry) bool {
|
||||
for _, t := range qp.titleQueue {
|
||||
if t.TitleID == title.TitleID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (qp *QueuePane) ForEachRemoving(f func(wiiudownloader.TitleEntry)) {
|
||||
for _, title := range qp.titleQueue {
|
||||
f(title)
|
||||
qp.RemoveTitle(title)
|
||||
}
|
||||
}
|
||||
|
||||
func (qp *QueuePane) GetTitleTreeView() *gtk.TreeView {
|
||||
return qp.titleTreeView
|
||||
}
|
||||
|
||||
func (qp *QueuePane) SetTitleTreeView(titleTreeView *gtk.TreeView) {
|
||||
qp.titleTreeView = titleTreeView
|
||||
}
|
||||
|
||||
func (qp *QueuePane) Update(doUpdateFunc bool) {
|
||||
qp.store.Clear()
|
||||
|
||||
for _, title := range qp.titleQueue {
|
||||
iter := qp.store.Append()
|
||||
|
||||
qp.store.Set(iter, []int{0, 1, 2}, []interface{}{title.Name, wiiudownloader.GetFormattedRegion(title.Region), fmt.Sprintf("%016x", title.TitleID)})
|
||||
}
|
||||
|
||||
if qp.updateFunc != nil && doUpdateFunc {
|
||||
qp.updateFunc()
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import (
|
|||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -157,7 +158,11 @@ func downloadFile(progressReporter ProgressReporter, client *http.Client, downlo
|
|||
}
|
||||
|
||||
func DownloadTitle(titleID, outputDirectory string, doDecryption bool, progressReporter ProgressReporter, deleteEncryptedContents bool, client *http.Client) error {
|
||||
tEntry := getTitleEntryFromTid(titleID)
|
||||
tid, err := strconv.ParseUint(titleID, 16, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tEntry := GetTitleEntryFromTid(tid)
|
||||
|
||||
progressReporter.ResetTotals()
|
||||
progressReporter.SetGameTitle(tEntry.Name)
|
||||
|
|
12
gtitles.go
12
gtitles.go
|
@ -1,9 +1,5 @@
|
|||
package wiiudownloader
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
MCP_REGION_JAPAN = 0x01
|
||||
MCP_REGION_USA = 0x02
|
||||
|
@ -127,13 +123,9 @@ func GetCategoryFromFormattedCategory(formattedCategory string) uint8 {
|
|||
}
|
||||
}
|
||||
|
||||
func getTitleEntryFromTid(tid string) TitleEntry {
|
||||
titleID, err := strconv.ParseUint(tid, 16, 64)
|
||||
if err != nil {
|
||||
return TitleEntry{}
|
||||
}
|
||||
func GetTitleEntryFromTid(tid uint64) TitleEntry {
|
||||
for _, entry := range GetTitleEntries(TITLE_CATEGORY_ALL) {
|
||||
if entry.TitleID == titleID {
|
||||
if entry.TitleID == tid {
|
||||
return entry
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue