mirror of
https://github.com/Xpl0itU/WiiUDownloader.git
synced 2025-05-15 15:44:56 -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)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Connect("activate", func() {
|
win := NewMainWindow(wiiudownloader.GetTitleEntries(wiiudownloader.TITLE_CATEGORY_GAME), client, config)
|
||||||
win := NewMainWindow(app, wiiudownloader.GetTitleEntries(wiiudownloader.TITLE_CATEGORY_GAME), client, config)
|
config.saveConfigCallback = func() {
|
||||||
config.saveConfigCallback = func() {
|
win.applyConfig(config)
|
||||||
win.applyConfig(config)
|
}
|
||||||
}
|
|
||||||
win.ShowAll()
|
app.Connect("activate", func(app *gtk.Application) {
|
||||||
app.AddWindow(win.window)
|
win.SetApplicationForGTKWindow(app)
|
||||||
app.GetActiveWindow().Show()
|
glib.IdleAddPriority(glib.PRIORITY_HIGH, func() {
|
||||||
|
win.ShowAll()
|
||||||
|
app.AddWindow(win.window)
|
||||||
|
app.GetActiveWindow().Show()
|
||||||
|
})
|
||||||
gtk.Main()
|
gtk.Main()
|
||||||
})
|
})
|
||||||
app.Run(nil)
|
glib.ApplicationGetDefault().Run(os.Args)
|
||||||
app.Quit()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,16 +26,15 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type MainWindow struct {
|
type MainWindow struct {
|
||||||
window *gtk.ApplicationWindow
|
window *gtk.Window
|
||||||
|
queuePane *QueuePane
|
||||||
treeView *gtk.TreeView
|
treeView *gtk.TreeView
|
||||||
searchEntry *gtk.Entry
|
searchEntry *gtk.Entry
|
||||||
deleteEncryptedContentsCheckbox *gtk.CheckButton
|
deleteEncryptedContentsCheckbox *gtk.CheckButton
|
||||||
deleteEncryptedContents bool
|
deleteEncryptedContents bool
|
||||||
addToQueueButton *gtk.Button
|
|
||||||
progressWindow *ProgressWindow
|
progressWindow *ProgressWindow
|
||||||
configWindow *ConfigWindow
|
configWindow *ConfigWindow
|
||||||
lastSearchText string
|
lastSearchText string
|
||||||
titleQueue []wiiudownloader.TitleEntry
|
|
||||||
categoryButtons []*gtk.ToggleButton
|
categoryButtons []*gtk.ToggleButton
|
||||||
titles []wiiudownloader.TitleEntry
|
titles []wiiudownloader.TitleEntry
|
||||||
decryptContents bool
|
decryptContents bool
|
||||||
|
@ -43,14 +42,14 @@ type MainWindow struct {
|
||||||
client *http.Client
|
client *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMainWindow(app *gtk.Application, entries []wiiudownloader.TitleEntry, client *http.Client, config *Config) *MainWindow {
|
func NewMainWindow(entries []wiiudownloader.TitleEntry, client *http.Client, config *Config) *MainWindow {
|
||||||
win, err := gtk.ApplicationWindowNew(app)
|
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Unable to create window:", err)
|
log.Fatalln("Unable to create window:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
win.SetTitle("WiiUDownloader")
|
win.SetTitle("WiiUDownloader")
|
||||||
win.SetDefaultSize(716, 400)
|
win.SetDefaultSize(870, 400)
|
||||||
win.Connect("destroy", func() {
|
win.Connect("destroy", func() {
|
||||||
gtk.MainQuit()
|
gtk.MainQuit()
|
||||||
})
|
})
|
||||||
|
@ -59,9 +58,17 @@ func NewMainWindow(app *gtk.Application, entries []wiiudownloader.TitleEntry, cl
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Unable to create entry:", err)
|
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{
|
mainWindow := MainWindow{
|
||||||
window: win,
|
window: win,
|
||||||
|
queuePane: queuePane,
|
||||||
titles: entries,
|
titles: entries,
|
||||||
searchEntry: searchEntry,
|
searchEntry: searchEntry,
|
||||||
currentRegion: wiiudownloader.MCP_REGION_EUROPE | wiiudownloader.MCP_REGION_JAPAN | wiiudownloader.MCP_REGION_USA,
|
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,
|
client: client,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queuePane.updateFunc = mainWindow.updateTitlesInQueue
|
||||||
|
|
||||||
mainWindow.applyConfig(config)
|
mainWindow.applyConfig(config)
|
||||||
|
|
||||||
searchEntry.Connect("changed", mainWindow.onSearchEntryChanged)
|
searchEntry.Connect("changed", mainWindow.onSearchEntryChanged)
|
||||||
|
@ -76,6 +85,10 @@ func NewMainWindow(app *gtk.Application, entries []wiiudownloader.TitleEntry, cl
|
||||||
return &mainWindow
|
return &mainWindow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mw *MainWindow) SetApplicationForGTKWindow(app *gtk.Application) {
|
||||||
|
mw.window.SetApplication(app)
|
||||||
|
}
|
||||||
|
|
||||||
func (mw *MainWindow) updateTitles(titles []wiiudownloader.TitleEntry) {
|
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)
|
store, err := gtk.ListStoreNew(glib.TYPE_BOOLEAN, glib.TYPE_STRING, glib.TYPE_STRING, glib.TYPE_STRING, glib.TYPE_STRING)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -89,7 +102,7 @@ func (mw *MainWindow) updateTitles(titles []wiiudownloader.TitleEntry) {
|
||||||
iter := store.Append()
|
iter := store.Append()
|
||||||
if err := store.Set(iter,
|
if err := store.Set(iter,
|
||||||
[]int{IN_QUEUE_COLUMN, KIND_COLUMN, TITLE_ID_COLUMN, REGION_COLUMN, NAME_COLUMN},
|
[]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 {
|
); err != nil {
|
||||||
log.Fatalln("Unable to set values:", err)
|
log.Fatalln("Unable to set values:", err)
|
||||||
}
|
}
|
||||||
|
@ -137,7 +150,7 @@ func (mw *MainWindow) ShowAll() {
|
||||||
iter := store.Append()
|
iter := store.Append()
|
||||||
err = store.Set(iter,
|
err = store.Set(iter,
|
||||||
[]int{IN_QUEUE_COLUMN, KIND_COLUMN, TITLE_ID_COLUMN, REGION_COLUMN, NAME_COLUMN},
|
[]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 {
|
if err != nil {
|
||||||
log.Fatalln("Unable to set values:", err)
|
log.Fatalln("Unable to set values:", err)
|
||||||
|
@ -191,22 +204,16 @@ func (mw *MainWindow) ShowAll() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Unable to get value:", err)
|
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) {
|
if isInQueue.(bool) {
|
||||||
mw.removeFromQueue(tidStr)
|
mw.queuePane.RemoveTitle(wiiudownloader.TitleEntry{TitleID: parsedTid})
|
||||||
} else {
|
} else {
|
||||||
name, err := store.ToTreeModel().GetValue(iter, NAME_COLUMN)
|
mw.queuePane.AddTitle(wiiudownloader.GetTitleEntryFromTid(parsedTid))
|
||||||
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.updateTitlesInQueue()
|
mw.updateTitlesInQueue()
|
||||||
mw.onSelectionChanged()
|
|
||||||
})
|
})
|
||||||
column, err := gtk.TreeViewColumnNewWithAttribute("Queue", toggleRenderer, "active", IN_QUEUE_COLUMN)
|
column, err := gtk.TreeViewColumnNewWithAttribute("Queue", toggleRenderer, "active", IN_QUEUE_COLUMN)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -224,10 +231,6 @@ func (mw *MainWindow) ShowAll() {
|
||||||
}
|
}
|
||||||
mw.treeView.AppendColumn(column)
|
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)
|
column, err = gtk.TreeViewColumnNewWithAttribute("Title ID", renderer, "text", TITLE_ID_COLUMN)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Unable to create tree view column:", err)
|
log.Fatalln("Unable to create tree view column:", err)
|
||||||
|
@ -240,10 +243,6 @@ func (mw *MainWindow) ShowAll() {
|
||||||
}
|
}
|
||||||
mw.treeView.AppendColumn(column)
|
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)
|
column, err = gtk.TreeViewColumnNewWithAttribute("Name", renderer, "text", NAME_COLUMN)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Unable to create tree view column:", err)
|
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)
|
log.Fatalln("Unable to create scrolled window:", err)
|
||||||
}
|
}
|
||||||
scrollable.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
scrollable.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||||
selection.Connect("changed", mw.onSelectionChanged)
|
|
||||||
scrollable.Add(mw.treeView)
|
scrollable.Add(mw.treeView)
|
||||||
|
|
||||||
mainvBox.PackStart(scrollable, true, true, 0)
|
mainvBox.PackStart(scrollable, true, true, 0)
|
||||||
|
@ -397,11 +395,6 @@ func (mw *MainWindow) ShowAll() {
|
||||||
log.Fatalln("Unable to create box:", err)
|
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")
|
downloadQueueButton, err := gtk.ButtonNewWithLabel("Download queue")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Unable to create button:", err)
|
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() {
|
downloadQueueButton.Connect("clicked", func() {
|
||||||
if len(mw.titleQueue) == 0 {
|
if mw.queuePane.IsQueueEmpty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mw.progressWindow, err = createProgressWindow(mw.window)
|
mw.progressWindow, err = createProgressWindow(mw.window)
|
||||||
|
@ -457,7 +449,6 @@ func (mw *MainWindow) ShowAll() {
|
||||||
}()
|
}()
|
||||||
})
|
})
|
||||||
decryptContentsCheckbox.Connect("clicked", mw.onDecryptContentsClicked)
|
decryptContentsCheckbox.Connect("clicked", mw.onDecryptContentsClicked)
|
||||||
bottomhBox.PackStart(mw.addToQueueButton, false, false, 0)
|
|
||||||
bottomhBox.PackStart(downloadQueueButton, false, false, 0)
|
bottomhBox.PackStart(downloadQueueButton, false, false, 0)
|
||||||
|
|
||||||
checkboxvBox, err := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
|
checkboxvBox, err := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
|
||||||
|
@ -501,14 +492,21 @@ func (mw *MainWindow) ShowAll() {
|
||||||
|
|
||||||
mainvBox.PackEnd(bottomhBox, false, false, 0)
|
mainvBox.PackEnd(bottomhBox, false, false, 0)
|
||||||
|
|
||||||
mainvBox.SetMarginBottom(2)
|
splitPane, err := gtk.PanedNew(gtk.ORIENTATION_HORIZONTAL)
|
||||||
mainvBox.SetMarginEnd(2)
|
if err != nil {
|
||||||
mainvBox.SetMarginStart(2)
|
log.Fatalln("Unable to create paned:", err)
|
||||||
mainvBox.SetMarginTop(2)
|
}
|
||||||
|
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) {
|
func (mw *MainWindow) onRegionChange(button *gtk.CheckButton, region uint8) {
|
||||||
|
@ -556,7 +554,7 @@ func (mw *MainWindow) filterTitles(filterText string) {
|
||||||
iter := storeRef.Append()
|
iter := storeRef.Append()
|
||||||
if err := storeRef.Set(iter,
|
if err := storeRef.Set(iter,
|
||||||
[]int{IN_QUEUE_COLUMN, KIND_COLUMN, TITLE_ID_COLUMN, REGION_COLUMN, NAME_COLUMN},
|
[]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 {
|
); err != nil {
|
||||||
log.Fatalln("Unable to set values:", err)
|
log.Fatalln("Unable to set values:", err)
|
||||||
}
|
}
|
||||||
|
@ -587,64 +585,6 @@ func (mw *MainWindow) onDecryptContentsMenuItemClicked(selectedPath string) erro
|
||||||
return err
|
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() {
|
func (mw *MainWindow) onDecryptContentsClicked() {
|
||||||
mw.decryptContents = !mw.decryptContents
|
mw.decryptContents = !mw.decryptContents
|
||||||
mw.deleteEncryptedContentsCheckbox.SetSensitive(mw.decryptContents)
|
mw.deleteEncryptedContentsCheckbox.SetSensitive(mw.decryptContents)
|
||||||
|
@ -665,119 +605,6 @@ func (mw *MainWindow) getDeleteEncryptedContents() bool {
|
||||||
return false
|
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() {
|
func (mw *MainWindow) updateTitlesInQueue() {
|
||||||
store, err := mw.treeView.GetModel()
|
store, err := mw.treeView.GetModel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -801,7 +628,7 @@ func (mw *MainWindow) updateTitlesInQueue() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
isInQueue := mw.isTitleInQueue(wiiudownloader.TitleEntry{TitleID: tidNum})
|
isInQueue := mw.queuePane.IsTitleInQueue(wiiudownloader.TitleEntry{TitleID: tidNum})
|
||||||
storeRef.SetValue(iter, IN_QUEUE_COLUMN, isInQueue)
|
storeRef.SetValue(iter, IN_QUEUE_COLUMN, isInQueue)
|
||||||
tid.Unset()
|
tid.Unset()
|
||||||
}
|
}
|
||||||
|
@ -810,6 +637,7 @@ func (mw *MainWindow) updateTitlesInQueue() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mw.queuePane.Update(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mw *MainWindow) showError(err error) {
|
func (mw *MainWindow) showError(err error) {
|
||||||
|
@ -822,7 +650,7 @@ func (mw *MainWindow) showError(err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mw *MainWindow) onDownloadQueueClicked(selectedPath string) error {
|
func (mw *MainWindow) onDownloadQueueClicked(selectedPath string) error {
|
||||||
if len(mw.titleQueue) == 0 {
|
if mw.queuePane.IsQueueEmpty() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -832,7 +660,7 @@ func (mw *MainWindow) onDownloadQueueClicked(selectedPath string) error {
|
||||||
defer close(queueStatusChan)
|
defer close(queueStatusChan)
|
||||||
errGroup := errgroup.Group{}
|
errGroup := errgroup.Group{}
|
||||||
|
|
||||||
for _, title := range mw.titleQueue {
|
mw.queuePane.ForEachRemoving(func(title wiiudownloader.TitleEntry) {
|
||||||
errGroup.Go(func() error {
|
errGroup.Go(func() error {
|
||||||
if mw.progressWindow.cancelled {
|
if mw.progressWindow.cancelled {
|
||||||
queueStatusChan <- true
|
queueStatusChan <- true
|
||||||
|
@ -853,16 +681,15 @@ func (mw *MainWindow) onDownloadQueueClicked(selectedPath string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !<-queueStatusChan {
|
if !<-queueStatusChan {
|
||||||
break
|
return
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
mw.titleQueue = []wiiudownloader.TitleEntry{} // Clear the queue
|
mw.queuePane.Clear()
|
||||||
glib.IdleAdd(func() {
|
glib.IdleAdd(func() {
|
||||||
mw.progressWindow.Window.Hide()
|
mw.progressWindow.Window.Hide()
|
||||||
})
|
})
|
||||||
mw.updateTitlesInQueue()
|
mw.updateTitlesInQueue()
|
||||||
mw.onSelectionChanged()
|
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ func (pw *ProgressWindow) SetStartTime(startTime time.Time) {
|
||||||
pw.startTime = startTime
|
pw.startTime = startTime
|
||||||
}
|
}
|
||||||
|
|
||||||
func createProgressWindow(parent *gtk.ApplicationWindow) (*ProgressWindow, error) {
|
func createProgressWindow(parent *gtk.Window) (*ProgressWindow, error) {
|
||||||
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"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 {
|
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.ResetTotals()
|
||||||
progressReporter.SetGameTitle(tEntry.Name)
|
progressReporter.SetGameTitle(tEntry.Name)
|
||||||
|
|
12
gtitles.go
12
gtitles.go
|
@ -1,9 +1,5 @@
|
||||||
package wiiudownloader
|
package wiiudownloader
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MCP_REGION_JAPAN = 0x01
|
MCP_REGION_JAPAN = 0x01
|
||||||
MCP_REGION_USA = 0x02
|
MCP_REGION_USA = 0x02
|
||||||
|
@ -127,13 +123,9 @@ func GetCategoryFromFormattedCategory(formattedCategory string) uint8 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTitleEntryFromTid(tid string) TitleEntry {
|
func GetTitleEntryFromTid(tid uint64) TitleEntry {
|
||||||
titleID, err := strconv.ParseUint(tid, 16, 64)
|
|
||||||
if err != nil {
|
|
||||||
return TitleEntry{}
|
|
||||||
}
|
|
||||||
for _, entry := range GetTitleEntries(TITLE_CATEGORY_ALL) {
|
for _, entry := range GetTitleEntries(TITLE_CATEGORY_ALL) {
|
||||||
if entry.TitleID == titleID {
|
if entry.TitleID == tid {
|
||||||
return entry
|
return entry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue