Skip to content
This repository was archived by the owner on Oct 31, 2022. It is now read-only.

Commit 1ff1e5d

Browse files
committed
python 3
1 parent dfcd7a2 commit 1ff1e5d

File tree

7 files changed

+132
-103
lines changed

7 files changed

+132
-103
lines changed

mangle.pyw

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,25 @@
1515
# You should have received a copy of the GNU General Public License
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717

18+
## TODO # Port to Python3, PyQt5 # TODO ##
19+
# X run 2to3
20+
# X change imports to PyQt5 and update PyQt method calls
21+
# X test main functionality:
22+
# X build comic with images and generate all formats for at least 2 types of Kindle
23+
# X test load/save .mngl files and other menu bar buttons.
24+
# - remove unused imports
25+
# - remove print/ debug
26+
# - test all functions
1827

1928
import sys
2029

21-
from PyQt4 import QtGui
30+
from PyQt5 import QtGui, QtCore, uic, QtWidgets
31+
from PyQt5.QtWidgets import QMainWindow, QApplication
32+
from PyQt5.QtCore import *
2233

2334
from mangle.book import MainWindowBook
2435

25-
26-
application = QtGui.QApplication(sys.argv)
36+
application = QtWidgets.QApplication(sys.argv)
2737
filename = sys.argv[1] if len(sys.argv) > 1 else None
2838
window = MainWindowBook(filename)
2939
window.show()

mangle/about.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@
1414
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1515

1616

17-
from PyQt4 import QtGui, uic
17+
#from PyQt4 import QtGui, uic
18+
from PyQt5 import QtWidgets, uic
19+
# from PyQt5.QtCore import *
1820

19-
import util
21+
from . import util
2022

21-
22-
class DialogAbout(QtGui.QDialog):
23+
class DialogAbout(QtWidgets.QDialog):
2324
def __init__(self, parent):
24-
QtGui.QDialog.__init__(self, parent)
25+
QtWidgets.QDialog.__init__(self, parent)
2526
uic.loadUi(util.buildResPath('mangle/ui/about.ui'), self)

mangle/book.py

Lines changed: 79 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,33 @@
1919
import tempfile
2020
from zipfile import ZipFile
2121

22-
from PyQt4 import QtGui, QtCore, QtXml, uic
22+
# from PyQt4 import QtGui, QtCore, QtXml, uic
23+
from PyQt5 import QtGui, QtCore, uic, QtXml, QtWidgets
24+
from PyQt5.QtCore import *
2325

24-
from about import DialogAbout
25-
from convert import DialogConvert
26-
from image import ImageFlags
27-
from options import DialogOptions
28-
import util
26+
from .about import DialogAbout
27+
from .convert import DialogConvert
28+
from .image import ImageFlags
29+
from .options import DialogOptions
30+
from . import util
2931

3032

31-
# Sort function use to sort files in a natural order, by lowering
32-
# characters, and manage multi levels of integers (tome 1/ page 1.jpg, etc etc)
33+
# Sort function used to sort files in a natural order, by lowering
34+
# characters, and managing multi levels of integers (tome 1/ page 1.jpg, etc etc)
3335
# cf: See http://www.codinghorror.com/blog/archives/001018.html
3436
def natural_key(string_):
3537
l = []
36-
for s in re.split(r'(\d+)', string_):
37-
# QString do not have isdigit, so convert it if need
38-
if isinstance(s, QtCore.QString):
39-
s = unicode(s)
40-
if s.isdigit():
41-
l.append(int(s))
42-
else:
43-
l.append(s.lower())
38+
print(f"string_ => {string_}")
39+
print(f"type(string_) => {type(string_)}")
40+
if string_:
41+
for s in re.split(r'(\d+)', string_):
42+
# str does not have isdigit, so convert it if needed
43+
if isinstance(s, str):
44+
s = str(s)
45+
if s.isdigit():
46+
l.append(int(s))
47+
else:
48+
l.append(s.lower())
4449
return l
4550

4651

@@ -80,35 +85,39 @@ def save(self, filename):
8085
root.appendChild(itemImg)
8186
itemImg.setAttribute('filename', filenameImg)
8287

83-
textXml = document.toString(4).toUtf8()
88+
textXml = document.toString(4)
89+
90+
if len(filename) == 2:
91+
filename = filename[0] # filename received is a tuple: get the first item
8492

8593
try:
86-
fileXml = open(unicode(filename), 'w')
94+
fileXml = open(str(filename), 'w')
8795
fileXml.write(textXml)
8896
fileXml.close()
89-
except IOError:
90-
raise RuntimeError('Cannot create book file %s' % filename)
97+
except IOError as ioe:
98+
print(f"IOError caught =>\n{ioe}")
99+
raise RuntimeError(f'Can\'t save file {filename}')
91100

92101
self.filename = filename
93102
self.modified = False
94103

95104

96105
def load(self, filename):
97106
try:
98-
fileXml = open(unicode(filename), 'r')
107+
fileXml = open(str(filename), 'r')
99108
textXml = fileXml.read()
100109
fileXml.close()
101110
except IOError:
102-
raise RuntimeError('Cannot open book file %s' % filename)
111+
raise RuntimeError(f'Can\'t open Mangle file {filename}')
103112

104113
document = QtXml.QDomDocument()
105114

106-
if not document.setContent(QtCore.QString.fromUtf8(textXml)):
107-
raise RuntimeError('Error parsing book file %s' % filename)
115+
if not document.setContent(textXml):
116+
raise RuntimeError(f'Error parsing Mangle file {filename}')
108117

109118
root = document.documentElement()
110119
if root.tagName() != 'book':
111-
raise RuntimeError('Unexpected book format in file %s' % filename)
120+
raise RuntimeError(f'Unexpected Mangle format in file {filename}')
112121

113122
self.title = root.attribute('title', 'Untitled')
114123
self.overwrite = root.attribute('overwrite', 'true' if Book.DefaultOverwrite else 'false') == 'true'
@@ -123,15 +132,15 @@ def load(self, filename):
123132
if items is None:
124133
return
125134

126-
for i in xrange(0, len(items)):
135+
for i in range(0, len(items)):
127136
item = items.at(i).toElement()
128137
if item.hasAttribute('filename'):
129138
self.images.append(item.attribute('filename'))
130139

131140

132-
class MainWindowBook(QtGui.QMainWindow):
141+
class MainWindowBook(QtWidgets.QMainWindow):
133142
def __init__(self, filename=None):
134-
QtGui.QMainWindow.__init__(self)
143+
QtWidgets.QMainWindow.__init__(self)
135144

136145
uic.loadUi(util.buildResPath('mangle/ui/book.ui'), self)
137146
self.listWidgetFiles.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
@@ -174,7 +183,7 @@ def dropEvent(self, event):
174183
filename = url.toLocalFile()
175184
if self.isImageFile(filename):
176185
filenames.append(filename)
177-
elif os.path.isdir(unicode(filename)):
186+
elif os.path.isdir(str(filename)):
178187
directories.append(filename)
179188

180189
self.addImageDirs(directories)
@@ -191,12 +200,14 @@ def onFileOpen(self):
191200
if not self.saveIfNeeded():
192201
return
193202

194-
filename = QtGui.QFileDialog.getOpenFileName(
203+
filename = QtWidgets.QFileDialog.getOpenFileName(
195204
parent=self,
196205
caption='Select a book file to open',
197206
filter='Mangle files (*.mngl);;All files (*.*)'
198207
)
199-
if not filename.isNull():
208+
filename = filename[0] # first item is filename (second is filter)
209+
210+
if filename:
200211
self.loadBook(self.cleanupBookFile(filename))
201212

202213

@@ -209,7 +220,7 @@ def onFileSaveAs(self):
209220

210221

211222
def onFilesContextMenu(self, point):
212-
menu = QtGui.QMenu(self)
223+
menu = QtWidgets.QMenu(self)
213224
menu.addAction(self.menu_Add.menuAction())
214225

215226
if len(self.listWidgetFiles.selectedItems()) > 0:
@@ -225,21 +236,23 @@ def onFilesDoubleClick(self, item):
225236

226237

227238
def onBookAddFiles(self):
228-
filenames = QtGui.QFileDialog.getOpenFileNames(
239+
filenames = QtWidgets.QFileDialog.getOpenFileNames(
229240
parent=self,
230241
caption='Select image file(s) to add',
231242
filter='Image files (*.jpeg *.jpg *.gif *.png);;Comic files (*.cbz)'
232243
)
244+
filenames = filenames[0] # get first tuple item (second is file filter)
245+
233246
if(self.containsCbzFile(filenames)):
234247
self.addCBZFiles(filenames)
235248
else:
236249
self.addImageFiles(filenames)
237250

238251

239252
def onBookAddDirectory(self):
240-
directory = QtGui.QFileDialog.getExistingDirectory(self, 'Select an image directory to add')
241-
if not directory.isNull():
242-
self.book.title = os.path.basename(os.path.normpath(unicode(directory)))
253+
directory = QtWidgets.QFileDialog.getExistingDirectory(self, 'Select an image directory to add')
254+
if directory:
255+
self.book.title = os.path.basename(os.path.normpath(str(directory)))
243256
self.addImageDirs([directory])
244257

245258

@@ -257,24 +270,24 @@ def onBookRemove(self):
257270

258271
def onBookOptions(self):
259272
dialog = DialogOptions(self, self.book)
260-
if dialog.exec_() == QtGui.QDialog.Accepted:
273+
if dialog.exec_() == QtWidgets.QDialog.Accepted:
261274
self.book.titleSet = True
262275

263276

264277
def onBookExport(self):
265278
if len(self.book.images) == 0:
266-
QtGui.QMessageBox.warning(self, 'Mangle', 'This book has no images to export')
279+
QtWidgets.QMessageBox.warning(self, 'Mangle', 'This book has no images to export')
267280
return
268281

269282
if not self.book.titleSet: # if self.book.title is None:
270283
dialog = DialogOptions(self, self.book)
271-
if dialog.exec_() == QtGui.QDialog.Rejected:
284+
if dialog.exec_() == QtWidgets.QDialog.Rejected:
272285
return
273286
else:
274287
self.book.titleSet = True
275288

276-
directory = QtGui.QFileDialog.getExistingDirectory(self, 'Select a directory to export book to')
277-
if not directory.isNull():
289+
directory = QtWidgets.QFileDialog.getExistingDirectory(self, 'Select a directory to export book to')
290+
if directory:
278291
dialog = DialogConvert(self, self.book, directory)
279292
dialog.exec_()
280293

@@ -293,40 +306,40 @@ def saveIfNeeded(self):
293306
if not self.book.modified:
294307
return True
295308

296-
result = QtGui.QMessageBox.question(
309+
result = QtWidgets.QMessageBox.question(
297310
self,
298311
'Mangle',
299312
'Save changes to the current book?',
300-
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No | QtGui.QMessageBox.Cancel,
301-
QtGui.QMessageBox.Yes
313+
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel,
314+
QtWidgets.QMessageBox.Yes
302315
)
303316

304317
return (
305-
result == QtGui.QMessageBox.No or
306-
result == QtGui.QMessageBox.Yes and self.saveBook()
318+
result == QtWidgets.QMessageBox.No or
319+
result == QtWidgets.QMessageBox.Yes and self.saveBook()
307320
)
308321

309322

310323
def saveBook(self, browse=False):
311324
if self.book.title is None:
312-
QtGui.QMessageBox.warning(self, 'Mangle', 'You must specify a title for this book before saving')
325+
QtWidgets.QMessageBox.warning(self, 'Mangle', 'You must specify a title for this book before saving')
313326
return False
314327

315328
filename = self.book.filename
316329
if filename is None or browse:
317-
filename = QtGui.QFileDialog.getSaveFileName(
330+
filename = QtWidgets.QFileDialog.getSaveFileName(
318331
parent=self,
319332
caption='Select a book file to save as',
320333
filter='Mangle files (*.mngl);;All files (*.*)'
321334
)
322-
if filename.isNull():
335+
if not filename:
323336
return False
324337
filename = self.cleanupBookFile(filename)
325338

326339
try:
327340
self.book.save(filename)
328-
except RuntimeError, error:
329-
QtGui.QMessageBox.critical(self, 'Mangle', str(error))
341+
except RuntimeError as error:
342+
QtWidgets.QMessageBox.critical(self, 'Mangle', str(error))
330343
return False
331344

332345
return True
@@ -335,8 +348,8 @@ def saveBook(self, browse=False):
335348
def loadBook(self, filename):
336349
try:
337350
self.book.load(filename)
338-
except RuntimeError, error:
339-
QtGui.QMessageBox.critical(self, 'Mangle', str(error))
351+
except RuntimeError as error:
352+
QtWidgets.QMessageBox.critical(self, 'Mangle', str(error))
340353
else:
341354
self.listWidgetFiles.clear()
342355
for image in self.book.images:
@@ -380,13 +393,15 @@ def removeImageFiles(self):
380393

381394
def addImageFiles(self, filenames):
382395
filenamesListed = []
383-
for i in xrange(0, self.listWidgetFiles.count()):
396+
for i in range(0, self.listWidgetFiles.count()):
384397
filenamesListed.append(self.listWidgetFiles.item(i).text())
385-
398+
386399
# Get files but in a natural sorted order
387-
for filename in sorted(filenames, key=natural_key):
400+
sorted_filenames = sorted(filenames, key=natural_key)
401+
402+
for filename in sorted_filenames:
388403
if filename not in filenamesListed:
389-
filename = QtCore.QString(filename)
404+
filename = str(filename)
390405
self.listWidgetFiles.addItem(filename)
391406
self.book.images.append(filename)
392407
self.book.modified = True
@@ -396,12 +411,12 @@ def addImageDirs(self, directories):
396411
filenames = []
397412

398413
for directory in directories:
399-
for root, _, subfiles in os.walk(unicode(directory)):
414+
for root, _, subfiles in os.walk(str(directory)):
400415
for filename in subfiles:
401416
path = os.path.join(root, filename)
402417
if self.isImageFile(path):
403418
filenames.append(path)
404-
419+
405420
self.addImageFiles(filenames)
406421

407422

@@ -411,7 +426,7 @@ def addCBZFiles(self, filenames):
411426
filenames.sort()
412427

413428
filenamesListed = []
414-
for i in xrange(0, self.listWidgetFiles.count()):
429+
for i in range(0, self.listWidgetFiles.count()):
415430
filenamesListed.append(self.listWidgetFiles.item(i).text())
416431

417432
for filename in filenames:
@@ -426,15 +441,15 @@ def addCBZFiles(self, filenames):
426441
pass # the dir exists so we are going to extract the images only.
427442
else:
428443
cbzFile.extract(f, path)
429-
if os.path.isdir(unicode(path)): # Add the directories
444+
if os.path.isdir(str(path)): # Add the directories
430445
directories.append(path)
431446

432447
self.addImageDirs(directories) # Add the files
433448

434449

435450
def isImageFile(self, filename):
436451
imageExts = ['.jpeg', '.jpg', '.gif', '.png']
437-
filename = unicode(filename)
452+
filename = str(filename)
438453
return (
439454
os.path.isfile(filename) and
440455
os.path.splitext(filename)[1].lower() in imageExts
@@ -443,7 +458,7 @@ def isImageFile(self, filename):
443458
def containsCbzFile(self, filenames):
444459
cbzExts = ['.cbz']
445460
for filename in filenames:
446-
filename = unicode(filename)
461+
filename = str(filename)
447462
result = (
448463
os.path.isfile(filename) and
449464
os.path.splitext(filename)[1].lower() in cbzExts
@@ -453,6 +468,6 @@ def containsCbzFile(self, filenames):
453468
return False
454469

455470
def cleanupBookFile(self, filename):
456-
if len(os.path.splitext(unicode(filename))[1]) == 0:
471+
if len(os.path.splitext(str(filename))[1]) == 0:
457472
filename += '.mngl'
458473
return filename

0 commit comments

Comments
 (0)