qwad/GUI/VenPri.py
2013-06-17 19:38:09 +02:00

469 lines
17 KiB
Python

# -*- coding: utf-8 -*-
"""
Module implementing Qwad's main window
"""
from PyQt4.QtGui import QMainWindow,QFileDialog,QMessageBox, QLabel
from PyQt4.QtCore import pyqtSignature,QString,QT_TR_NOOP,SIGNAL,QObject
from WiiPy.archive import WAD
from WiiPy.title import NUS, TMD
from Ui_VenPri import Ui_Qwad
from shutil import rmtree
from threading import Thread
import TitleIDs
import tempfile, os, time
import binascii
CWD = os.getcwd()
def str2bool(v):
return v.lower() in ("yes", "true", "t", "1")
class MWQwad(QMainWindow, Ui_Qwad):
"""
Class documentation goes here.
"""
def __init__(self, parent = None):
"""
Constructor
"""
QMainWindow.__init__(self, parent)
self.setupUi(self)
self.defaultversion = self.trUtf8("""(Latest)""")
self.availableVersions.setText("(---)")
self.VersionlineEdit.setText(self.defaultversion)
for key in TitleIDs.sorted_copy(TitleIDs.TitleDict):
self.comboBox.addItem(key)
for key in TitleIDs.SupportedRegions:
self.ChooseRegion.addItem(key)
self.getReady()
self.default_region = ""
def Status(self,status):
print status
self.setEnabled(False)
self.statusBar.showMessage(status)
def getReady(self):
self.setEnabled(True)
self.statusBar.showMessage(self.trUtf8("Ready"))
os.chdir(CWD)
print "Done."
def ErrorDiag(self, error = QT_TR_NOOP("Unknown error")):
print error
QMessageBox.critical(None,
self.trUtf8("Error"),
self.trUtf8("""An error has ocurred:""") +" " + str(error),
QMessageBox.StandardButtons(\
QMessageBox.Ok),
QMessageBox.Ok)
def loadTMD(self,tmdpath):#TODO: TMD viewer
"""
Displays _TMD information in the UI
"""
tmd = TMD().loadFile(tmdpath)
self.TitleID.setText("%016x" % tmd.tmd.titleid)
tid = "%016x" % tmd.tmd.titleid
tid = tid[8:]
asc = ''.join([chr(int(''.join(c), 16)) for c in zip(tid[0::2],tid[1::2])])
self.idASCII.setText("%s" % asc)
self.IOSversion.setText(TitleIDs.TitleSwapDict["%s" % ("%016x" % tmd.tmd.iosversion)])
self.TitleType.setText(str(tmd.tmd.title_type))
self.GroupID.setText(str(tmd.tmd.group_id))
self.Reserved.setText(str(tmd.tmd.reserved))
self.AccessRights.setText(str(tmd.tmd.access_rights))
self.Version.setText(str(tmd.tmd.title_version))
self.Contents.setText(str(tmd.tmd.numcontents))
self.BootIndex.setText(str(tmd.tmd.boot_index))
@pyqtSignature("")
def on_BotonRutaWad_clicked(self):
"""
Get path to WAD file
"""
WadPath = QFileDialog.getOpenFileName(\
None,
self.trUtf8("Select WAD file"),
QString(),
self.trUtf8("*.wad; *.WAD"),
None)
if WadPath != "" :
self.MuestraRutaWad.setText(WadPath)
@pyqtSignature("")
def on_BotonRutaExtraer_clicked(self):
"""
WAD contents output path
"""
OutputDir = QFileDialog.getExistingDirectory(\
None,
self.trUtf8("Select where to store WAD contents"),
QString(),
QFileDialog.Options(QFileDialog.ShowDirsOnly))
if OutputDir != "":
self.MuestraRutaExtraer.setText(OutputDir)
@pyqtSignature("")
def on_Desempaqueta_clicked(self):
"""
Unpack wad
"""
try:
self.unpack = Unpacking(str(self.MuestraRutaWad.text()), str(self.MuestraRutaExtraer.text()), self)
self.unpack.start()
except Exception, e:
self.ErrorDiag(e)
@pyqtSignature("")
def on_BotonRutaEmpaquetado_clicked(self):
"""
Select where to save the newly created WAD
"""
NewWadPath = QFileDialog.getSaveFileName(\
None,
self.trUtf8("Select where to save the newly created WAD"),
QString("output.wad"),
self.trUtf8("*.wad; *.WAD"),
None)
if NewWadPath != "":
self.MuestraRutaEmpaquetado.setText(NewWadPath)
@pyqtSignature("")
def on_BotonRutaDesempaquetado_clicked(self):
"""
Get path off folder to pack.
"""
Dir2Wad = QFileDialog.getExistingDirectory(\
None,
self.trUtf8("Select folder to pack into WAD"),
QString(),
QFileDialog.Options(QFileDialog.ShowDirsOnly))
if Dir2Wad != "":
self.MuestraRutaDesempaquetado.setText(Dir2Wad)
@pyqtSignature("")
def on_Empaqueta_clicked(self):
"""
Create WAD
"""
self.setEnabled(False)
try:
self.packing = Packing(str(self.MuestraRutaDesempaquetado.text()),str(self.MuestraRutaEmpaquetado.text()), self)
self.packing.start()
except Exception, e:
self.ErrorDiag(e)
self.setEnabled(True)
@pyqtSignature("")
def on_actionAcerca_de_Qwad_triggered(self):
"""
About Qwad
"""
from AboutQwad import AboutQwad
Pop = AboutQwad()
Pop.exec_()
@pyqtSignature("")
def on_actionAbout_Qt_triggered(self):
"""
About Qt
"""
QMessageBox.aboutQt(None,
self.trUtf8("About Qt"))
@pyqtSignature("")
def on_Download_from_NUS_clicked(self):
"""
Start doing the actual work... well, in fact, the actual work is done by Wii.py
"""
try:
version = self.VersionlineEdit.text()
if version == self.defaultversion:
print "downloading latest version"
version = None
else:
version = str(version)
print "downloading version " + version
outputdir = str(self.NusOutputPath.text())
self.nusdow = nusDownloading(int(str(self.enteredTitleID.text()).lower(),16), version, outputdir, self.decryptCheck.isChecked(), self)
self.nusdow.start()
except Exception, e:
self.ErrorDiag(e)
@pyqtSignature("")
def on_NusOutputButton_clicked(self):
"""
Selects the output path
"""
if self.pack_in_WAD_checkbox.isChecked():
outputdir = QFileDialog.getSaveFileName(\
None,
self.trUtf8("Select where to save the downloaded WAD"),
QString(),
self.trUtf8("*.wad; *.WAD"),
None)
else:
outputdir = QFileDialog.getExistingDirectory(\
None,
self.trUtf8("Select the directory where store the downloaded files"),
QString(),
QFileDialog.Options(QFileDialog.ShowDirsOnly))
if outputdir != "":
self.NusOutputPath.setText(outputdir)
@pyqtSignature("QString")
def on_comboBox_currentIndexChanged(self, selection):
"""
Show the title ID of the selected title
"""
if self.comboBox.findText(selection) == 0:
self.enteredTitleID.setText("")
self.availableVersions.setText("")
elif self.comboBox.findText(selection) > 0:
self.enteredTitleID.enabled = False
self.enteredTitleID.setText(TitleIDs.TitleDict[str(selection)])
self.availableVersions.setText(TitleIDs.IOSdict[str(selection)])
@pyqtSignature("QString")
def on_comboBox2_currentIndexChanged(self, selection):
"""
Show the title ID of the selected title
"""
if self.comboBox2.findText(selection) == 0:
self.enteredTitleID.setText("")
self.availableVersions.setText("")
elif self.comboBox2.findText(selection) > 0:
self.enteredTitleID.enabled = False
if self.default_region == "JAP":
self.enteredTitleID.setText(TitleIDs.ChannelJAPDict[str(selection)])
self.availableVersions.setText(TitleIDs.ChannelJAPVerDict[str(selection)])
elif self.default_region == "PAL":
self.enteredTitleID.setText(TitleIDs.ChannelPALDict[str(selection)])
self.availableVersions.setText(TitleIDs.ChannelPALVerDict[str(selection)])
elif self.default_region == "USA":
self.enteredTitleID.setText(TitleIDs.ChannelUSADict[str(selection)])
self.availableVersions.setText(TitleIDs.ChannelUSAVerDict[str(selection)])
@pyqtSignature("QString")
def on_ChooseRegion_currentIndexChanged(self, selection):
self.default_region = "JAP"
if self.default_region != "":
count = self.comboBox2.count()
while count > -1 :
self.comboBox2.removeItem(count)
count = count - 1
if self.ChooseRegion.findText(selection) != 0:
self.default_region = str(selection)
self.comboBox2.addItem("Choose Channel")
if self.default_region == "JAP":
for key in TitleIDs.sorted_copy(TitleIDs.ChannelJAPDict):
self.comboBox2.addItem(key)
elif self.default_region == "PAL":
for key in TitleIDs.sorted_copy(TitleIDs.ChannelPALDict):
self.comboBox2.addItem(key)
elif self.default_region == "USA":
for key in TitleIDs.sorted_copy(TitleIDs.ChannelUSADict):
self.comboBox2.addItem(key)
@pyqtSignature("")
def on_enteredTitleID_returnPressed(self):
"""
Place combobox un custom titleid
"""
self.comboBox.setCurrentIndex(0)
@pyqtSignature("int")
def on_pack_in_WAD_checkbox_stateChanged(self, state):
"""
Clear output path, because we change output type
"""
self.NusOutputPath.clear()
if state == 2:
self.decryptCheck.setChecked(False)
self.decryptCheck.setEnabled(False)
elif state == 0:
self.decryptCheck.setChecked(True)
self.decryptCheck.setEnabled(True)
elif state == 1:
print "OMG, what are you doing?"
else:
print "This is the end of the world. For PyQt4, at least"
@pyqtSignature("")
def on_TMDfilepath_returnPressed(self):
"""
Trigger loadTMD
"""
self.loadTMD(str(self.TMDfilepath.text()))
@pyqtSignature("")
def on_TMDfilebutton_clicked(self):
"""
Trigger loadTMD
"""
tmdpath = QFileDialog.getOpenFileName(\
None,
self.trUtf8("Select a TMD file"),
QString(),
self.trUtf8("*.tmd; *.TMD"),
None,
QFileDialog.Options(QFileDialog.DontResolveSymlinks))
if tmdpath != "":
self.TMDfilepath.setText(tmdpath)
self.loadTMD(str(tmdpath))
#Here useful thread classes
class Unpacking(Thread):
def __init__(self, wadpath, dirpath, QMW):
Thread.__init__(self)
self.wadpath = wadpath
self.dirpath = dirpath
self.QMW = QMW
self.qobject = QObject()
self.qobject.connect(self.qobject, SIGNAL("working"),self.QMW.Status)
self.qobject.connect(self.qobject, SIGNAL("Exception"),self.QMW.ErrorDiag)
self.qobject.connect(self.qobject, SIGNAL("Done"),self.QMW.getReady)
def run(self):
self.qobject.emit(SIGNAL("working"),UNPACKING)
try:
WAD.loadFile(self.wadpath).dumpDir(self.dirpath)
except Exception, e:
print e
self.qobject.emit(SIGNAL("Exception"),e)
self.qobject.emit(SIGNAL("Done"))
class UnpackingCLI(Thread):
def __init__(self, wadpath, dirpath):
Thread.__init__(self)
self.wadpath = wadpath
self.dirpath = dirpath
def run(self):
try:
WAD.loadFile(self.wadpath).dumpDir(self.dirpath)
except Exception, e:
print e
print "Done"
class Packing(Unpacking):
def __init__(self, dirpath, wadpath, QMW, deletedir = False):
Unpacking.__init__(self, wadpath, dirpath, QMW)
self.deletedir = deletedir
def run(self):
self.qobject.emit(SIGNAL("working"),PACKING)
try:
print self.wadpath
print self.dirpath
WAD.loadDir(self.dirpath).dumpFile(self.wadpath)
if self.deletedir:
print "Cleaning temporary files"
self.qobject.emit(SIGNAL("working"),CLEANING)
rmtree(self.dirpath)
except Exception, e:
if self.deletedir:
print "Cleaning temporary files"
self.qobject.emit(SIGNAL("working"),CLEANING)
rmtree(self.dirpath)
print e
self.qobject.emit(SIGNAL("Exception"),e)
self.qobject.emit(SIGNAL("Done"))
class PackingCLI(UnpackingCLI):
def __init__(self, dirpath, wadpath, deletedir = False):
UnpackingCLI.__init__(self, wadpath, dirpath)
self.deletedir = deletedir
def run(self):
try:
print self.dirpath
print self.wadpath
WAD.loadDir(self.dirpath).dumpFile(self.wadpath)
if self.deletedir:
print "Cleaning temporary files"
rmtree(self.dirpath)
except Exception, e:
if self.deletedir:
print "Cleaning temporary files"
rmtree(self.dirpath)
print e
print "Done"
class nusDownloading(Unpacking):
def __init__(self, titleid, version, outputdir, decrypt, QMW):
Unpacking.__init__(self, None, outputdir, QMW)
if version != None:
self.version = int(version)
else:
self.version = None
self.decrypt = decrypt
self.titleid = titleid
print self.titleid
print self.version
def run(self):
self.qobject.emit(SIGNAL("working"),DOWNLOADING)
try:
if self.QMW.pack_in_WAD_checkbox.isChecked():
self.dirpath = tempfile.gettempdir() + "/NUS_"+ str(time.time()).replace(".","") # A safe place for temporary files
NUS(self.titleid,self.version).download(self.dirpath, decrypt = self.decrypt)
self.packing = Packing(self.dirpath, str(self.QMW.NusOutputPath.text()), self.QMW, True)
self.packing.start()
else:
NUS(self.titleid,self.version).download(self.dirpath, decrypt = self.decrypt)
self.qobject.emit(SIGNAL("Done"))
except Exception, e:
print e
Errormsg = str(e) + ". " + QT_TR_NOOP(QString("Title %1 version %2 maybe isn't available for download on NUS.").arg(str(self.titleid)).arg(str(self.version)))
self.qobject.emit(SIGNAL("Exception"),Errormsg)
self.qobject.emit(SIGNAL("Done"))
class nusDownloadingCLI(UnpackingCLI):
def __init__(self, titleid, version, outputdir, decrypt, pack):
UnpackingCLI.__init__(self, None, outputdir)
if version != None:
self.version = int(version)
else:
self.version = None
self.decrypt = str2bool(decrypt)
self.pack = str2bool(pack)
self.titleid = titleid
self.outputdir = outputdir
def run(self):
try:
if self.pack:
self.dirpath = tempfile.gettempdir() + "/NUS_"+ str(time.time()).replace(".","")
NUS(self.titleid, self.version).download(self.dirpath, decrypt = self.decrypt)
self.packing = PackingCLI(self.dirpath, str(self.outputdir), True)
self.packing.start()
else:
NUS(self.titleid,self.version).download(self.outputdir, decrypt = self.decrypt)
except Exception, e:
print e
def ShowTMD(tmdpath):
"""
Displays _TMD information in the CLI
"""
tmd = TMD().loadFile(tmdpath)
print "Title ID (HEX) : %016x" % tmd.tmd.titleid
tid = "%016x" % tmd.tmd.titleid
tid = tid[8:]
asc = ''.join([chr(int(''.join(c), 16)) for c in zip(tid[0::2],tid[1::2])])
print "Title ID (ASCII) : %s" % asc
print "Title Version : %s" % tmd.tmd.title_version
print "Title Boot Index : %s" % tmd.tmd.boot_index
print "Title Contents : %s" % tmd.tmd.numcontents
if ("%016x" % tmd.tmd.iosversion) == "0000000000000000":
print "Title IOS : --"
else:
print "Title IOS : %s" % TitleIDs.TitleSwapDict["%s" % ("%016x" % tmd.tmd.iosversion)]
print "Title Access Rights: %s" % tmd.tmd.access_rights
print "Title Type : %s" % tmd.tmd.title_type
print "Title Group ID : %s" % tmd.tmd.group_id
print "Title Reserved : %s" % ''.join(str(tmd.tmd.reserved))
#Statusbar messages
#FIXME: Why don't they get translated? It's frustrating
DOWNLOADING = QT_TR_NOOP("Downloading files from NUS... This may take a while, please, be patient.")
UNPACKING = QT_TR_NOOP("Unpacking WAD...")
PACKING = QT_TR_NOOP("Packing into WAD...")
CLEANING = QT_TR_NOOP("Cleaning temporary files...")