├── DiskFormatID
└── __init__.py
├── README.md
├── attic
└── settings.json
├── chooseFormats.py
├── chooseFormatsGUI.py
├── diskIDMain
├── diskIDMainGUI.py
├── setup.py
└── ui_files
├── chooseFormatsGUI.ui
└── diskIDMainGUI.ui
/DiskFormatID/__init__.py:
--------------------------------------------------------------------------------
1 | # Minimal init for DiskFormatID. Update for future releases.
2 | __license__ = "GPL 3.0"
3 | __version__ = "1.0.0"
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DiskFormatID
2 |
3 | More information is available in this blog post: http://digitalcontinuity.org/post/144268258748/floppy-disk-format-identifer-tool
4 |
5 |
6 | This program is intended to help to identify floppy disk formats. It takes a folder of http://www.Kryoflux.com stream files as input. It only works with linux and requires
7 |
8 | python 2.7
9 |
10 | pyqt4
11 |
12 | mount
13 |
14 | Kam Woods packaged it with setuptools, (https://twitter.com/kamwoods) thanks Kam! You will need the python-setuptools package installed on your system to install it.
15 |
16 |
17 | Please support http://kryoflux.com/ !
18 |
19 | To use:
20 | Clone the repository or download all the files using the download zip button and extract them to a folder (not all are actually needed).
21 |
22 | In the DiskFormatID directory, build and install the program for all users as follows:
23 |
24 | python setup.py build
25 | sudo python setup.py install
26 |
27 | Now, you can run the program as root from any location with:
28 |
29 | "sudo diskIDMain"
30 |
31 | (If you properly install DTC according to the instructions in the Kryoflux documentation then you may not need to run it as root).
32 |
33 | The first time you start the program, you will see a warning that informs you a new settings file is being created. This settings file is located in the .diskFormatID directory within your home directory.
34 |
35 | Click "choose formats" to select disk image formats to be created
36 | Select input and output folders and specify the directory containing the Kryoflux DTC application. These settings (including selected formats) will be saved in "settings.json"
37 |
38 | NB: the program license must already have been agreed to by navigating to the dtc directory in a terminal window and running the GUI with:
39 |
40 | java -jar kryoflux-ui.jar
41 |
42 | Then accepting the prompt.
43 |
44 | Choose how many concurrent dtc instances you want to run to create the disk images.
45 | Click "create images" to use a local copy of the Kryoflux DTC program to create the image files from a folder containing folders of raw Kryoflux stream files. NB: the interface may lock up and not update the results for a indeterminate period of time.
46 |
47 | Click a button to mount the disk image files and get feedback on which files could be mounted. Check "delete unmountable" to delete the image files that couldn't be mounted.
48 |
49 | Click either of the "save results" buttons to save the results from the corresponding window to a file (extension will be added automatically).
50 |
51 | All created disk images will be have root permissions assigned, you may need to change that after using the program.
52 |
--------------------------------------------------------------------------------
/attic/settings.json:
--------------------------------------------------------------------------------
1 | {"outputFormats": [{"Image type": "-i4"}, {"Image type": "-i10"}, {"Image type": "-i9"}], "mainSettings": [{"Output directory": "/home/euan/kryo/output/", "DTC directory": "/home/euan/kryo/kryoflux_2.6_linux/dtc/", "Input directory": "/home/euan/kryo/smallTest/", "Delete unmountable": "TRUE"}]}
--------------------------------------------------------------------------------
/chooseFormats.py:
--------------------------------------------------------------------------------
1 | from PyQt4 import QtGui
2 | import sys
3 | import os
4 | import json
5 | import chooseFormatsGUI
6 |
7 |
8 | imageTypes = {"CT Raw":"-i2","FM Sector":"-i3","FM XFD":"-i3a","MFM":"-i4","Amiga DOS":"-i5","CBM DOS":"-i6","CBM DOS ErrMap":"-i7","Apple DOS 3.2":"-i8","Apple DOS 3.3":"-i8a","DSK":"-i9","Apple DOS 400/800K":"-i10","EMU":"-i11","EMU2":"-i12","Amiga Disk Spare":"-i13","DEC RX01":"-i14","DEC RX02":"-i15","CBM Micro Prose":"-i16","CBM RapidLok":"-i17","CBM Datasoft":"-i18","CBM Vorpal":"-i19","CBM V-MAX":"-i20","CBM Teque":"-i21","CBM TDP":"-i22","CBM GCR":"-i22a","CBM Big5":"-i23","CBM DOS":"-i24","CBM OziSoft":"-i25"}
9 | imageFmts = {'-i3a': 'FM XFD', '-i24': 'CBM DOS', '-i25': 'CBM OziSoft', '-i20': 'CBM V-MAX', '-i21': 'CBM Teque', '-i22': 'CBM TDP', '-i23': 'CBM Big5', '-i22a': 'CBM GCR', '-i9': 'DSK', '-i8': 'Apple DOS 3.2', '-i3': 'FM Sector', '-i2': 'CT Raw', '-i5': 'Amiga DOS', '-i4': 'MFM', '-i7': 'CBMDOS ErrMap', '-i15': 'DEC RX02', '-i14': 'DEC RX01', '-i17': 'CBM RapidLok', '-i16': 'CBM MicroProse', '-i11': 'EMU', '-i10': 'Apple DOS 400/800K', '-i13': 'Amiga Disk Spare', '-i12': 'EMU2', '-i19': 'CBM Vorpal', '-i18': 'CBM Datasoft', '-i8a': 'AppleDOS3.3'}
10 |
11 | endTracks = ("x","-e73","-e72","-e79","-e39","-e34","-e76","-e81")
12 |
13 | sideModes = {"Both sides":"-g2","Side 0":"-g0","Side 1":"-g1"}
14 | sideModesRv = {'-g2': 'Both sides', '-g1': 'Side 1', '-g0': 'Side 0'}
15 |
16 | sectorSizes = {"128":"-z0","256":"-z1","512":"-z3","1024":"-z2"}
17 | sectorSizesRv = {'-z0': '128', '-z1': '256', '-z2': '1024', '-z3': '512'}
18 |
19 | sectorCounts = {"Exactly":"+","At most":"-"}
20 | sectorCountsRv = {'+': 'Exactly', '-': 'At most'}
21 |
22 | trackDistances = {"80":"-k1","40":"-k2"}
23 | trackDistancesRv = {"-k1":"80","-k2":"40"}
24 |
25 | targetRPMsBasic = {"300":"-v300","288":"-v288","360":"-v360","150":"-v150"}
26 | targetRPMsBasicRv = {'-v150': '150', '-v288': '288', '-v300': '300', '-v360': '360'}
27 |
28 | driveDensities = {"High":"-dd0","Low":"-dd1"}
29 | driveDensitiesRv = {"-dd0":"High","-dd1":"Low"}
30 |
31 | outputTrackOrders = {"Side 0 descending":"-oo1","Side 1 descending":"-oo2","Side 1 then side 0":"-oo4","Side oriented":"-oo8"}
32 | outputTrackOrdersRv = {'-oo1': 'Side 0 descending', '-oo8': 'Side oriented', '-oo2': 'Side 1 descending', '-oo4': 'Side 1 then side 0'}
33 |
34 | global spath
35 | spath = os.getenv("HOME") + '/.diskFormatID/settings.json'
36 |
37 | class addTypes(QtGui.QMainWindow, chooseFormatsGUI.Ui_addTypes):
38 | def __init__(self, parent=None):
39 | global spath
40 | super(addTypes, self).__init__(parent)
41 | self.setupUi(self)
42 | self.imageTypeCB.clear()
43 | # populate the combo box with the keys in the image variables defined above
44 | self.imageTypeCB.addItems(imageTypes.keys())
45 | #set the default value actual defaults
46 | #set most of the combo boxes to not editable/greyed out by default (that will be changed if the check box is unchecked
47 | self.imageTypeCB.setCurrentIndex(self.imageTypeCB.findText('MFM'))
48 | self.trackDistanceCB.addItems(trackDistances.keys())
49 | self.trackDistanceCB.setCurrentIndex(self.trackDistanceCB.findText('40'))
50 |
51 | self.trackDistanceCB.setEnabled(False)
52 |
53 | self.sectorCountCB.addItems(sectorCounts.keys())
54 | self.sectorCountCB.setEnabled(False)
55 |
56 | self.sideModeCB.addItems(sideModes.keys())
57 | self.sideModeCB.setCurrentIndex(self.sideModeCB.findText('Both sides'))
58 | self.sideModeCB.setEnabled(False)
59 |
60 | self.sectorSizeCB.addItems(sectorSizes.keys())
61 | self.sectorSizeCB.setCurrentIndex(self.sectorSizeCB.findText('512'))
62 | self.sectorSizeCB.setEnabled(False)
63 |
64 | self.startTrack.setEnabled(False)
65 | self.endTrack.setEnabled(False)
66 | self.sectorCount.setEnabled(False)
67 |
68 | self.targetRPMCB.addItems(targetRPMsBasic.keys())
69 | self.targetRPMCB.setEnabled(False)
70 |
71 |
72 | # if the reset all button is clicked launch that function
73 | self.resetTypes.clicked.connect(self.reset_types)
74 |
75 |
76 | #open the spath file for reading
77 | if os.stat(spath).st_size != 0:
78 | self.updateTextBrowserFromJSON()
79 | else:
80 | #pass if file is empty
81 | pass
82 |
83 | def reset_types(self):
84 | global spath
85 | #open the json file and get the contents
86 |
87 | with open(spath ,'r') as settings_file:
88 |
89 | settings = json.load(settings_file)
90 | # try deleting the outputFormats element/key
91 | try:
92 | del settings['outputFormats']
93 | except KeyError:
94 | pass
95 | #write back the remaining json
96 | jsoutput = json.dumps(settings)
97 | outfile = open(spath, 'w')
98 | outfile.write(jsoutput)
99 | outfile.close()
100 |
101 | # clear what is in the text browser in the gui
102 | self.settingsDisplay.clear()
103 | # process that clearance event
104 | QtGui.QApplication.processEvents()
105 |
106 | def save_and_add(self):
107 | # this function adds what is in each setting to the json file
108 | global spath
109 |
110 | #check to see if the spath file is empty
111 |
112 | if os.stat(spath).st_size != 0:
113 | # if it is not empty open it for reading
114 | with open(spath,'r') as settings_file:
115 | settings = json.load(settings_file)
116 | #create a variable to store the current input in the image type comobo box
117 | imgType = imageTypes[str(self.imageTypeCB.currentText())]
118 | #print imgType
119 | #create a dictionary to store the set of settings for one disk (if needed)
120 | diskSetting = {}
121 | diskSetting.update({"Image type":imgType})
122 | #Check to see if the side mode combo box is set to default
123 | if not self.sideModeDefault.isChecked():
124 | # if the side mode combo box is not set to default add the contents of it to the diskSetting dictionary
125 | diskSetting.update({"Side mode":sideModes[str(self.sideModeCB.currentText())]})
126 | if self.flippyMode.isChecked():
127 | diskSetting.update({"Flippy mode":"-y"})
128 |
129 | if not self.sectorSizeDefault.isChecked():
130 | # if the sector size combo box is not set to default add the contents of it to the diskSetting dictionary
131 | diskSetting.update({"Sector size":sectorSizes[str(self.sectorSizeCB.currentText())]})
132 |
133 | if not self.sectorCountDefault.isChecked():
134 | # if the sector count combo box is not set to default add the contents of it to the diskSetting dictionary
135 | diskSetting.update({"Sector count":sectorCounts[str(self.sectorCountCB.currentText())] + str(self.sectorCount.text())})
136 |
137 | if not self.trackDistanceDefault.isChecked():
138 | # if the track distance combo box is not set to default add the contents of it to the diskSetting dictionary
139 | diskSetting.update({"Track Distance":trackDistances[str(self.trackDistanceCB.currentText())]})
140 |
141 | if not self.tracksDefault.isChecked():
142 | starttr = "-os" + str(self.startTrack.text())
143 | endtr = "-oe" + str(self.endTrack.text())
144 | diskSetting.update({"Start track":str(starttr)})
145 | diskSetting.update({"End track":str(endtr)})
146 |
147 | if not self.targetRPMDefault.isChecked():
148 | # if the target RPM combo box is not set to default add the contents of it to the diskSetting dictionary
149 | diskSetting.update({"Target RPM":targetRPMsBasic[str(self.targetRPMCB.currentText())]})
150 |
151 | # append the contents of disk settings to the format json element
152 | if "outputFormats" in settings:
153 | settings["outputFormats"].append(diskSetting)
154 | else:
155 | settings["outputFormats"] = [diskSetting]
156 | #Clear the json file and write back the updated json
157 | jsoutput = json.dumps(settings)
158 | outfile = open(spath, 'w')
159 | outfile.write(jsoutput)
160 | outfile.close()
161 | self.settingsDisplay.clear()
162 | #clear the settings text browser in the GUI
163 | #open the spath file and print the contents to the text browser in the gui, one per format instance
164 |
165 | self.updateTextBrowserFromJSON()
166 |
167 | else:
168 | #if the spath file is empty you should put something into it
169 |
170 | #this is a hangover from earlier versions where I needed to id/process the imagetype ina a unique way
171 | imgType = imageTypes[str(self.imageTypeCB.currentText())]
172 | #print imgType
173 | #create a dictionary to store the set of settings for one disk (if needed)
174 | diskSetting = {}
175 | diskSetting.update({"Image type":imgType})
176 | #Check to see if the side mode combo box is set to default
177 | if not self.sideModeDefault.isChecked():
178 | # if the side mode combo box is not set to default add the contents of it to the diskSetting dictionary
179 | diskSetting.update({"Side mode":sideModes[str(self.sideModeCB.currentText())]})
180 |
181 | if not self.sectorSizeDefault.isChecked():
182 | # if the sector size combo box is not set to default add the contents of it to the diskSetting dictionary
183 | diskSetting.update({"Sector size":sectorSizes[str(self.sectorSizeCB.currentText())]})
184 | if self.flippyMode.isChecked():
185 | diskSetting.update({"Flippy mode":"-y"})
186 |
187 | if not self.sectorCountDefault.isChecked():
188 | # if the sector count combo box is not set to default add the contents of it to the diskSetting dictionary
189 | diskSetting.update({"Sector count":sectorCounts[str(self.sectorCountCB.currentText())] + str(self.sectorCount.text())})
190 |
191 | if not self.trackDistanceDefault.isChecked():
192 | # if the track distance combo box is not set to default add the contents of it to the diskSetting dictionary
193 | diskSetting.update({"Track Distance":trackDistances[str(self.trackDistanceCB.currentText())]})
194 |
195 | if not self.tracksDefault.isChecked():
196 | starttr = "-os" + str(self.startTrack.text())
197 | endtr = "-oe" + str(self.endTrack.text())
198 | diskSetting.update({"Start track":starttr})
199 | diskSetting.update({"End track":endtr})
200 |
201 |
202 | if not self.targetRPMDefault.isChecked():
203 | # if the target RPM combo box is not set to default add the contents of it to the diskSetting dictionary
204 | diskSetting.update({"Target RPM":targetRPMsBasic[str(self.targetRPMCB.currentText())]})
205 |
206 | #now write this all back
207 | settings = {"outputFormats":[diskSetting]}
208 | jsoutput = json.dumps(settings)
209 | outfile = open(spath, 'w')
210 | outfile.write(jsoutput)
211 | outfile.close()
212 | self.settingsDisplay.clear()
213 | self.updateTextBrowserFromJSON()
214 |
215 | def updateTextBrowserFromJSON(self):
216 |
217 | global spath
218 | #used to update what is in the textbrowser box in the GUI from the JSON file
219 | with open(spath) as settings_file:
220 | num = 0
221 | settings = json.load(settings_file)
222 | # get all the formats already stored in the file
223 | if "outputFormats" in settings:
224 | for format in settings["outputFormats"]:
225 | num = num + 1
226 | #create a variable to add content to be put into the text browser in the gui
227 | setting = ""
228 |
229 | for x in format:
230 | #For each format add the information to the setting variable, starting with Image type
231 | if x == "Image type":
232 | setting = x + ": " + imageFmts[str(format[x])] + setting
233 | elif x == "Sector size":
234 | setting = setting + ", " + x + ": " + sectorSizesRv[str(format[x])]
235 |
236 | elif x == "Side mode":
237 | setting = setting + ", " + x + ": " + sideModesRv[str(format[x])]
238 |
239 | elif x == "Sector count":
240 | setting = setting + ", " + x + ": " + sectorCountsRv[str(format[x])[0]] + str(self.sectorCount.text())
241 |
242 | elif x == "Track distance":
243 | setting = setting + ", " + x + ": " + trackDistancesRv[str(format[x])]
244 |
245 | elif x == "Target RPM":
246 | setting = setting + ", " + x + ": " + targetRPMsBasicRv[str(format[x])]
247 |
248 | elif x == "Flippy mode":
249 | setting = setting + ", " + x + ": " + str(format[x])
250 |
251 | elif x == "Start track":
252 | setting = setting + ", " + x + ": " + str(format[x])[2:]
253 |
254 | elif x == "End track":
255 | setting = setting + ", " + x + ": " + str(format[x])[2:]
256 |
257 | #update the text browser with the information in each format
258 | self.settingsDisplay.append("Image " + str(num) + ": " + setting)
259 | # process the update
260 | QtGui.QApplication.processEvents()
261 |
262 |
263 | settings_file.close()
264 |
265 |
266 | # set up functions to change the editablility of the various widgets when the checkboxes change to unchecked
267 | def tracks_default_change(self):
268 | if self.tracksDefault.isChecked():
269 | self.startTrack.setEnabled(False)
270 | self.endTrack.setEnabled(False)
271 | else:
272 | self.startTrack.setEnabled(True)
273 | self.endTrack.setEnabled(True)
274 |
275 |
276 | def side_mode_default_change(self):
277 |
278 | if self.sideModeDefault.isChecked():
279 | self.sideModeCB.setEnabled(False)
280 | else:
281 | self.sideModeCB.setEnabled(True)
282 |
283 | def sector_count_default_change(self):
284 |
285 | if self.sectorCountDefault.isChecked():
286 | self.sectorCountCB.setEnabled(False)
287 | self.sectorCount.setEnabled(False)
288 | else:
289 | self.sectorCountCB.setEnabled(True)
290 | self.sectorCount.setEnabled(True)
291 |
292 | def sector_size_default_change(self):
293 |
294 | if self.sectorSizeDefault.isChecked():
295 | self.sectorSizeCB.setEnabled(False)
296 | else:
297 | self.sectorSizeCB.setEnabled(True)
298 |
299 | def track_distance_default_change(self):
300 |
301 | if self.trackDistanceDefault.isChecked():
302 | self.trackDistanceCB.setEnabled(False)
303 | else:
304 | self.trackDistanceCB.setEnabled(True)
305 |
306 | def target_RPM_default_change(self):
307 | if self.targetRPMDefault.isChecked():
308 | self.targetRPMCB.setEnabled(False)
309 | else:
310 | self.targetRPMCB.setEnabled(True)
311 |
312 | # Don't think I strictly need this one
313 | def flippy_change(self):
314 | if self.flippyMode.isChecked():
315 | True
316 | else:
317 | False
318 |
319 |
320 | def main():
321 | app = QtGui.QApplication(sys.argv)
322 | form = addTypes()
323 | form.show()
324 | app.exec_()
325 |
326 |
327 |
328 |
329 | if __name__ == '__main__':
330 | main()
331 |
--------------------------------------------------------------------------------
/chooseFormatsGUI.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'chooseFormatsGUI.ui'
4 | #
5 | # Created by: PyQt4 UI code generator 4.11.4
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt4 import QtCore, QtGui
10 |
11 | try:
12 | _fromUtf8 = QtCore.QString.fromUtf8
13 | except AttributeError:
14 | def _fromUtf8(s):
15 | return s
16 |
17 | try:
18 | _encoding = QtGui.QApplication.UnicodeUTF8
19 | def _translate(context, text, disambig):
20 | return QtGui.QApplication.translate(context, text, disambig, _encoding)
21 | except AttributeError:
22 | def _translate(context, text, disambig):
23 | return QtGui.QApplication.translate(context, text, disambig)
24 |
25 | class Ui_addTypes(object):
26 | def setupUi(self, addTypes):
27 | addTypes.setObjectName(_fromUtf8("addTypes"))
28 | addTypes.resize(439, 587)
29 | self.centralwidget = QtGui.QWidget(addTypes)
30 | self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
31 | self.imageTypeCB = QtGui.QComboBox(self.centralwidget)
32 | self.imageTypeCB.setGeometry(QtCore.QRect(118, 10, 221, 27))
33 | self.imageTypeCB.setObjectName(_fromUtf8("imageTypeCB"))
34 | self.startTrack = QtGui.QLineEdit(self.centralwidget)
35 | self.startTrack.setGeometry(QtCore.QRect(118, 60, 61, 27))
36 | self.startTrack.setObjectName(_fromUtf8("startTrack"))
37 | self.endTrack = QtGui.QLineEdit(self.centralwidget)
38 | self.endTrack.setGeometry(QtCore.QRect(277, 59, 61, 27))
39 | self.endTrack.setObjectName(_fromUtf8("endTrack"))
40 | self.sideModeCB = QtGui.QComboBox(self.centralwidget)
41 | self.sideModeCB.setGeometry(QtCore.QRect(118, 100, 221, 27))
42 | self.sideModeCB.setObjectName(_fromUtf8("sideModeCB"))
43 | self.sectorSizeCB = QtGui.QComboBox(self.centralwidget)
44 | self.sectorSizeCB.setGeometry(QtCore.QRect(118, 140, 221, 27))
45 | self.sectorSizeCB.setObjectName(_fromUtf8("sectorSizeCB"))
46 | self.sectorCountCB = QtGui.QComboBox(self.centralwidget)
47 | self.sectorCountCB.setGeometry(QtCore.QRect(118, 177, 101, 27))
48 | self.sectorCountCB.setObjectName(_fromUtf8("sectorCountCB"))
49 | self.sectorCount = QtGui.QLineEdit(self.centralwidget)
50 | self.sectorCount.setGeometry(QtCore.QRect(248, 177, 41, 27))
51 | self.sectorCount.setObjectName(_fromUtf8("sectorCount"))
52 | self.trackDistanceCB = QtGui.QComboBox(self.centralwidget)
53 | self.trackDistanceCB.setGeometry(QtCore.QRect(118, 217, 221, 27))
54 | self.trackDistanceCB.setObjectName(_fromUtf8("trackDistanceCB"))
55 | self.flippyMode = QtGui.QCheckBox(self.centralwidget)
56 | self.flippyMode.setGeometry(QtCore.QRect(131, 295, 121, 22))
57 | self.flippyMode.setObjectName(_fromUtf8("flippyMode"))
58 | self.tracksDefault = QtGui.QCheckBox(self.centralwidget)
59 | self.tracksDefault.setEnabled(True)
60 | self.tracksDefault.setGeometry(QtCore.QRect(350, 62, 99, 22))
61 | self.tracksDefault.setChecked(True)
62 | self.tracksDefault.setObjectName(_fromUtf8("tracksDefault"))
63 | self.sideModeDefault = QtGui.QCheckBox(self.centralwidget)
64 | self.sideModeDefault.setGeometry(QtCore.QRect(350, 103, 99, 22))
65 | self.sideModeDefault.setChecked(True)
66 | self.sideModeDefault.setObjectName(_fromUtf8("sideModeDefault"))
67 | self.sectorSizeDefault = QtGui.QCheckBox(self.centralwidget)
68 | self.sectorSizeDefault.setGeometry(QtCore.QRect(349, 143, 99, 22))
69 | self.sectorSizeDefault.setChecked(True)
70 | self.sectorSizeDefault.setObjectName(_fromUtf8("sectorSizeDefault"))
71 | self.sectorCountDefault = QtGui.QCheckBox(self.centralwidget)
72 | self.sectorCountDefault.setGeometry(QtCore.QRect(349, 180, 99, 22))
73 | self.sectorCountDefault.setChecked(True)
74 | self.sectorCountDefault.setObjectName(_fromUtf8("sectorCountDefault"))
75 | self.trackDistanceDefault = QtGui.QCheckBox(self.centralwidget)
76 | self.trackDistanceDefault.setGeometry(QtCore.QRect(349, 217, 99, 22))
77 | self.trackDistanceDefault.setChecked(True)
78 | self.trackDistanceDefault.setObjectName(_fromUtf8("trackDistanceDefault"))
79 | self.addType = QtGui.QPushButton(self.centralwidget)
80 | self.addType.setGeometry(QtCore.QRect(259, 290, 171, 31))
81 | self.addType.setObjectName(_fromUtf8("addType"))
82 | self.label = QtGui.QLabel(self.centralwidget)
83 | self.label.setGeometry(QtCore.QRect(29, 12, 81, 20))
84 | self.label.setObjectName(_fromUtf8("label"))
85 | self.label_2 = QtGui.QLabel(self.centralwidget)
86 | self.label_2.setGeometry(QtCore.QRect(29, 62, 81, 20))
87 | self.label_2.setObjectName(_fromUtf8("label_2"))
88 | self.label_3 = QtGui.QLabel(self.centralwidget)
89 | self.label_3.setGeometry(QtCore.QRect(205, 62, 71, 20))
90 | self.label_3.setObjectName(_fromUtf8("label_3"))
91 | self.label_4 = QtGui.QLabel(self.centralwidget)
92 | self.label_4.setGeometry(QtCore.QRect(31, 104, 81, 20))
93 | self.label_4.setObjectName(_fromUtf8("label_4"))
94 | self.label_5 = QtGui.QLabel(self.centralwidget)
95 | self.label_5.setGeometry(QtCore.QRect(29, 143, 81, 20))
96 | self.label_5.setObjectName(_fromUtf8("label_5"))
97 | self.label_6 = QtGui.QLabel(self.centralwidget)
98 | self.label_6.setGeometry(QtCore.QRect(19, 180, 91, 20))
99 | self.label_6.setObjectName(_fromUtf8("label_6"))
100 | self.label_7 = QtGui.QLabel(self.centralwidget)
101 | self.label_7.setGeometry(QtCore.QRect(9, 220, 101, 20))
102 | self.label_7.setObjectName(_fromUtf8("label_7"))
103 | self.label_8 = QtGui.QLabel(self.centralwidget)
104 | self.label_8.setGeometry(QtCore.QRect(24, 260, 81, 20))
105 | self.label_8.setObjectName(_fromUtf8("label_8"))
106 | self.targetRPMDefault = QtGui.QCheckBox(self.centralwidget)
107 | self.targetRPMDefault.setGeometry(QtCore.QRect(350, 258, 99, 22))
108 | self.targetRPMDefault.setChecked(True)
109 | self.targetRPMDefault.setObjectName(_fromUtf8("targetRPMDefault"))
110 | self.settingsDisplay = QtGui.QTextBrowser(self.centralwidget)
111 | self.settingsDisplay.setGeometry(QtCore.QRect(10, 370, 421, 171))
112 | self.settingsDisplay.setObjectName(_fromUtf8("settingsDisplay"))
113 | self.resetTypes = QtGui.QPushButton(self.centralwidget)
114 | self.resetTypes.setGeometry(QtCore.QRect(330, 338, 99, 27))
115 | self.resetTypes.setObjectName(_fromUtf8("resetTypes"))
116 | self.label_9 = QtGui.QLabel(self.centralwidget)
117 | self.label_9.setGeometry(QtCore.QRect(12, 350, 181, 17))
118 | font = QtGui.QFont()
119 | font.setBold(True)
120 | font.setWeight(75)
121 | self.label_9.setFont(font)
122 | self.label_9.setObjectName(_fromUtf8("label_9"))
123 | self.targetRPMCB = QtGui.QComboBox(self.centralwidget)
124 | self.targetRPMCB.setGeometry(QtCore.QRect(118, 255, 221, 27))
125 | self.targetRPMCB.setObjectName(_fromUtf8("targetRPMCB"))
126 | addTypes.setCentralWidget(self.centralwidget)
127 | self.menubar = QtGui.QMenuBar(addTypes)
128 | self.menubar.setGeometry(QtCore.QRect(0, 0, 439, 25))
129 | self.menubar.setObjectName(_fromUtf8("menubar"))
130 | addTypes.setMenuBar(self.menubar)
131 | self.statusbar = QtGui.QStatusBar(addTypes)
132 | self.statusbar.setObjectName(_fromUtf8("statusbar"))
133 | addTypes.setStatusBar(self.statusbar)
134 |
135 | self.retranslateUi(addTypes)
136 | QtCore.QObject.connect(self.resetTypes, QtCore.SIGNAL(_fromUtf8("clicked()")), addTypes.reset_types)
137 | QtCore.QObject.connect(self.addType, QtCore.SIGNAL(_fromUtf8("clicked()")), addTypes.save_and_add)
138 | QtCore.QObject.connect(self.tracksDefault, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), addTypes.tracks_default_change)
139 | QtCore.QObject.connect(self.sideModeDefault, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), addTypes.side_mode_default_change)
140 | QtCore.QObject.connect(self.sectorSizeDefault, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), addTypes.sector_size_default_change)
141 | QtCore.QObject.connect(self.sectorCountDefault, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), addTypes.sector_count_default_change)
142 | QtCore.QObject.connect(self.trackDistanceDefault, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), addTypes.track_distance_default_change)
143 | QtCore.QObject.connect(self.targetRPMDefault, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), addTypes.target_RPM_default_change)
144 | QtCore.QObject.connect(self.flippyMode, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), addTypes.flippy_change)
145 | QtCore.QMetaObject.connectSlotsByName(addTypes)
146 |
147 | def retranslateUi(self, addTypes):
148 | addTypes.setWindowTitle(_translate("addTypes", "Add Disk Types", None))
149 | self.flippyMode.setText(_translate("addTypes", "Flippy Mode", None))
150 | self.tracksDefault.setText(_translate("addTypes", "Default", None))
151 | self.sideModeDefault.setText(_translate("addTypes", "Default", None))
152 | self.sectorSizeDefault.setText(_translate("addTypes", "Default", None))
153 | self.sectorCountDefault.setText(_translate("addTypes", "Default", None))
154 | self.trackDistanceDefault.setText(_translate("addTypes", "Default", None))
155 | self.addType.setText(_translate("addTypes", "Save (and add another)", None))
156 | self.label.setText(_translate("addTypes", "Image Type", None))
157 | self.label_2.setText(_translate("addTypes", "Start Track", None))
158 | self.label_3.setText(_translate("addTypes", "End Track", None))
159 | self.label_4.setText(_translate("addTypes", "Side Mode", None))
160 | self.label_5.setText(_translate("addTypes", "Sector Size", None))
161 | self.label_6.setText(_translate("addTypes", "Sector Count", None))
162 | self.label_7.setText(_translate("addTypes", "Track distance", None))
163 | self.label_8.setText(_translate("addTypes", "Target RPM", None))
164 | self.targetRPMDefault.setText(_translate("addTypes", "Default", None))
165 | self.resetTypes.setText(_translate("addTypes", "Reset all", None))
166 | self.label_9.setText(_translate("addTypes", "Configured image types:", None))
167 |
168 |
--------------------------------------------------------------------------------
/diskIDMain:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 | from PyQt4 import QtGui, QtCore
3 | from distutils.dir_util import copy_tree
4 | import sys
5 | import os
6 | import diskIDMainGUI
7 | import chooseFormats
8 | import subprocess
9 | import json
10 | import shutil
11 | import sys
12 | import getpass
13 | from subprocess import Popen
14 | from subprocess import check_output
15 | from itertools import islice
16 |
17 |
18 | global inpDirLoc
19 | global outDirLoc
20 | global dtcDirloc
21 |
22 |
23 | impDirLoc = ""
24 | outDirLoc = ""
25 | dtcDirLoc = ""
26 |
27 | spath = os.getenv("HOME") + '/.diskFormatID/settings.json'
28 |
29 | class kryoMain(QtGui.QMainWindow, diskIDMainGUI.Ui_kryoMain):
30 | def __init__(self, parent=None):
31 | #don't really understand global variables well enough, but I think I need to put these here
32 | global inpDirLoc
33 |
34 | global outDirLoc
35 |
36 | global dtcDirLoc
37 | # start the whole gui thing
38 | super(kryoMain, self).__init__(parent)
39 | self.setupUi(self)
40 |
41 | # set the dtc max concurrent isntances box to default to 1
42 | self.DTCInstances.setText("1")
43 |
44 | # Check for existence of settings file for local user. If it doesn't
45 | # exist (e.g. on first use) warn and create)
46 |
47 | if not os.path.exists(spath):
48 |
49 | QtGui.QMessageBox.warning(self, "First run notice",
50 | "It looks like you're running the program for the first time as this user. I'm creating a new default settings file for you in " + spath,
51 | QtGui.QMessageBox.Ok, QtGui.QMessageBox.NoButton,
52 | QtGui.QMessageBox.NoButton)
53 |
54 | os.mkdir(os.getenv("HOME") + '/.diskFormatID')
55 | sfile = open(spath, 'w+')
56 | sfile.write('{"outputFormats": [{"Image type": "-i4"}, {"Image type": "-i10"}, {"Image type": "-i9"}], "mainSettings": [{"Output directory": "/home/euan/kryo/output/", "DTC directory": "/home/euan/kryo/kryoflux_2.6_linux/dtc/", "Input directory": "/home/euan/kryo/smallTest/", "Delete unmountable": "TRUE"}]}')
57 | sfile.close()
58 |
59 | # Probably need to change ownership settings if this program
60 | # is being run as root, and the user later decides to run it
61 | # as themselves. Fix this ina future version. Right now,
62 | # the settings directory and file installed in the dot-directory
63 | # will be root-owned if run as sudo.
64 |
65 | #open the settings.json file for reading
66 | if os.stat(spath).st_size != 0:
67 | with open(spath) as settings_file:
68 |
69 | #set main settings to values from settings json file
70 | settings = json.load(settings_file)
71 | if "mainSettings" in settings:
72 | for setting in settings["mainSettings"]:
73 | self.inputDir.setText(setting["Input directory"])
74 | dtcDirLoc = str(setting["DTC directory"])
75 | self.DTCDir.setText(setting["DTC directory"])
76 | inpDirLoc = str(setting["Input directory"])
77 | self.outputDir.setText(setting["Output directory"])
78 | outDirLoc = str(setting["Output directory"])
79 | if setting == "Delete unmountable":
80 | if setting["Delete unmountable"] == "TRUE":
81 | self.deleteUnmountable.setChecked(true)
82 | else:
83 | self.deleteUnmountable.setChecked(true)
84 |
85 |
86 |
87 | # initiate sub program to choose formats when button is clicked
88 |
89 | def choose_formats(self):
90 |
91 | self.addTypes = chooseFormats.addTypes()
92 | self.addTypes.show()
93 |
94 |
95 | # function below takes input from create images button and creates the images
96 |
97 |
98 | def create_images(self):
99 | global inpDirLoc
100 |
101 | global outDirLoc
102 |
103 | global dtcDirLoc
104 |
105 | with open(spath) as data_file:
106 | data = json.load(data_file)
107 |
108 | # set input variables for the source and destination file directories and dtc directory
109 |
110 | source_dirname= inpDirLoc
111 | dest_dir = outDirLoc
112 | dtc_dir = dtcDirLoc
113 | commands = []
114 |
115 | outdir = ()
116 |
117 | # check the input folder and find all sub directories
118 | for dirname, dirnames, filenames in os.walk(source_dirname):
119 |
120 | # get the folder names for each sub directory
121 | for subdirname in dirnames:
122 |
123 | # create a variable to use for the sub directory paths
124 | indirname = os.path.join(dirname, subdirname)
125 | #print str(indirname)
126 |
127 |
128 | # check each sub directory to see if it has a stream file in it
129 | if os.path.isfile(os.path.join(indirname, "track00.0.raw")) == True:
130 |
131 | # create directories to copy the streamfiles to, as the directories have to have no spaces in them, then copy the files to those directories
132 |
133 | outTrackDir = os.path.join(dest_dir,subdirname.replace(" ","_"),"track")
134 | if not os.path.exists(outTrackDir):
135 | os.makedirs(outTrackDir)
136 | outdir = os.path.join(dest_dir, subdirname.replace(" ","_"))
137 |
138 | for trackFile in os.listdir(indirname):
139 | if not os.path.isfile(os.path.join(outTrackDir,trackFile)):
140 | self.imageCreationResults.append("copying track " + str(os.path.join(indirname,trackFile)))
141 | QtGui.QApplication.processEvents()
142 | shutil.copyfile(os.path.join(indirname,trackFile),os.path.join(outTrackDir,trackFile))
143 |
144 |
145 |
146 |
147 | #setup a variable to form each command into
148 | for format in data["outputFormats"]:
149 | command = set()
150 |
151 | filepath = os.path.join(outdir, subdirname.replace(" ","_"))
152 | #print str(trackPath)
153 |
154 | for param in format:
155 | if command != "":
156 | command.add(format[param])
157 | filepath = filepath + format[param]
158 |
159 | else:
160 | command = format[param]
161 | filepath = filepath + format[param]
162 |
163 | commands.append((dtc_dir + "./dtc", "-f" + str(filepath) + ".img", "-m1", ", ".join([str(x) for x in command]), "-f" + outTrackDir + "/track","-i0"))
164 |
165 |
166 |
167 | # Now run the commands in paralell
168 | # set max concurrent instances from feild in gui
169 | max_workers = int(self.DTCInstances.text())
170 | processes = (Popen(cmd, cwd=dtc_dir,stdout=subprocess.PIPE,stderr=subprocess.PIPE) for cmd in commands)
171 |
172 | running_processes = list(islice(processes, max_workers))
173 | while running_processes:
174 | results = []
175 | for i, process in enumerate(running_processes):
176 | out, err = process.communicate()
177 |
178 | #update the text browser with the status
179 |
180 |
181 | results.append(str(out) + str(err))
182 | # process the update to the gui
183 | QtGui.QApplication.processEvents()
184 | if process.poll() is not None: # the process has finished
185 | running_processes[i] = next(processes, None) # start new process
186 | if running_processes[i] is None: # no new processes
187 | del running_processes[i]
188 | break
189 | for result in results:
190 | self.imageCreationResults.append(result)
191 | self.imageCreationResults.append(" ")
192 | self.imageCreationResults.append("------------------------------------------------")
193 | self.imageCreationResults.append("Creation of images complete")
194 | self.imageCreationResults.append("------------------------------------------------")
195 |
196 |
197 | def try_mounting(self):
198 | global outDirLoc
199 | dest_dir = outDirLoc
200 |
201 | # now try mounting the files you created and delete the ones that don't mount
202 |
203 | #select all directories in the destination directory
204 | for dirname, dirnames, filenames in os.walk(dest_dir):
205 |
206 | # for each of those find the files in them
207 | for subdirname in dirnames:
208 | indirname = os.path.join(dirname,subdirname)
209 |
210 |
211 | #for each disk image file in that directory
212 | for dirname2, dirnames2, filenames2 in os.walk(indirname):
213 | for filenm in filenames2:
214 | if not "track" in str(os.path.join(dest_dir, indirname, filenm)):
215 | # for each file, mount it and put the resulting errors into a variable p.stderr
216 | #update the text browser with the status
217 | self.MountingResults.append("Trying to mount " + str(filenm))
218 | # process the update to the gui
219 | QtGui.QApplication.processEvents()
220 | p = subprocess.Popen(["mount", "-O loop", os.path.join(dest_dir, indirname, filenm), "/mnt"], stderr=subprocess.PIPE)
221 |
222 | # if there is no error then umount the disk image
223 | if p.stderr.readline() == "":
224 | #update the text browser with the status
225 | self.MountingResults.append(str(filenm) + " mounted successfully")
226 | # process the update to the gui
227 | QtGui.QApplication.processEvents()
228 | subprocess.call(["umount", "/mnt"])
229 | self.MountingResults.append(" ")
230 | self.MountingResults.append("------------------------------------------------")
231 | self.MountingResults.append(" ")
232 |
233 |
234 | else:
235 | #update the text browser with the status
236 | self.MountingResults.append(str(filenm) + " mounting failed")
237 |
238 | # process the update to the gui
239 | QtGui.QApplication.processEvents()
240 | if self.deleteUnmountable.isChecked():
241 | #update the text browser with the status
242 | self.MountingResults.append("Deleting " + str(filenm))
243 | self.MountingResults.append(" ")
244 | self.MountingResults.append("------------------------------------------------")
245 | self.MountingResults.append(" ")
246 | # process the update to the gui
247 | QtGui.QApplication.processEvents()
248 | subprocess.call(["rm", os.path.join(dest_dir, indirname, filenm)])
249 | else:
250 |
251 | self.MountingResults.append(" ")
252 | self.MountingResults.append("------------------------------------------------")
253 | self.MountingResults.append(" ")
254 | self.MountingResults.append
255 | self.MountingResults.append("Mounting process complete")
256 | self.MountingResults.append(" ")
257 | self.MountingResults.append("------------------------------------------------")
258 |
259 | def delete_unmountable_change(self):
260 |
261 | if os.stat(spath).st_size != 0:
262 | # if it is not empty open it for reading
263 | with open(spath,'r') as settings_file:
264 | settings = json.load(settings_file)
265 | if self.deleteUnmountable.isChecked():
266 | for setting in settings["mainSettings"]:
267 | setting["Delete unmountable"] = "TRUE"
268 |
269 | else:
270 | for setting in settings["mainSettings"]:
271 | setting["Delete unmountable"] = "FALSE"
272 | jsoutput = json.dumps(settings)
273 | outfile = open(spath, 'w')
274 | outfile.write(jsoutput)
275 | outfile.close()
276 |
277 | def browse_dtc_dir(self):
278 |
279 | global dtcDirLoc
280 | dtcDirLoc = QtGui.QFileDialog.getExistingDirectory(self,
281 | "Select a folder") + "/"
282 | dtcDirLoc = str(dtcDirLoc)
283 | self.DTCDir.setText(dtcDirLoc)
284 |
285 | if os.stat(spath).st_size != 0:
286 | # if it is not empty open it for reading
287 | with open(spath,'r') as settings_file:
288 | settings = json.load(settings_file)
289 | for setting in settings["mainSettings"]:
290 | setting["DTC directory"] = str(dtcDirLoc)
291 |
292 | jsoutput = json.dumps(settings)
293 | outfile = open(spath, 'w')
294 | outfile.write(jsoutput)
295 | outfile.close()
296 |
297 | #This function processes the browse input directory button press
298 | def browse_inp_dir(self):
299 | global inpDirLoc
300 |
301 | inpDirLoc = QtGui.QFileDialog.getExistingDirectory(self,
302 | "Select a folder") + "/"
303 | inpDirLoc = str(inpDirLoc)
304 | self.inputDir.setText(inpDirLoc)
305 |
306 | if os.stat(spath).st_size != 0:
307 | # if it is not empty open it for reading
308 | with open(spath,'r') as settings_file:
309 | settings = json.load(settings_file)
310 | for setting in settings["mainSettings"]:
311 | setting["Input directory"] = str(inpDirLoc)
312 |
313 | jsoutput = json.dumps(settings)
314 | outfile = open(spath, 'w')
315 | outfile.write(jsoutput)
316 | outfile.close()
317 |
318 | def save_mounting_results(self):
319 | # get file path from user input browsing
320 | saveFilePath = QtGui.QFileDialog.getSaveFileName(self,'Choose save file location',str(outDirLoc),selectedFilter='*.txt')
321 | #make file extension .txt if not already
322 | if str(saveFilePath)[-4:] != '.txt':
323 | saveFilePath = saveFilePath + ".txt"
324 | #assing textbrowser contents to a variable and write it to the file selected above
325 | mountingResultsDialog = self.MountingResults.toPlainText()
326 | outfile = open(saveFilePath, 'w')
327 | outfile.write(mountingResultsDialog)
328 | outfile.close()
329 |
330 |
331 |
332 |
333 | def save_dtc_results(self):
334 | # get file path from user input browsing
335 | saveDTCPath = QtGui.QFileDialog.getSaveFileName(self,'Choose save file location',str(outDirLoc),selectedFilter='*.txt')
336 | #make file extension .txt if not already
337 | if str(saveDTCPath)[-4:] != '.txt':
338 | saveDTCPath = saveDTCPath + ".txt"
339 | #assing textbrowser contents to a variable and write it to the file selected above
340 | imageCreationResultsDialog = self.imageCreationResults.toPlainText()
341 | outfile = open(saveDTCPath, 'w')
342 | outfile.write(imageCreationResultsDialog)
343 | outfile.close()
344 |
345 |
346 | def browse_output_dir(self):
347 | global outDirLoc
348 |
349 | outDirLoc = QtGui.QFileDialog.getExistingDirectory(self,
350 | "Select a folder") + "/"
351 | outDirLoc = str(outDirLoc)
352 | self.outputDir.setText(outDirLoc)
353 |
354 | if os.stat(spath).st_size != 0:
355 | # if it is not empty open it for reading
356 | with open(spath,'r') as settings_file:
357 | settings = json.load(settings_file)
358 | for setting in settings["mainSettings"]:
359 | setting["Output directory"] = str(outDirLoc)
360 |
361 | jsoutput = json.dumps(settings)
362 | outfile = open(spath, 'w')
363 | outfile.write(jsoutput)
364 | outfile.close()
365 |
366 | def main():
367 | app = QtGui.QApplication(sys.argv)
368 | form = kryoMain()
369 | form.show()
370 | app.exec_()
371 |
372 |
373 |
374 |
375 | if __name__ == '__main__':
376 | main()
377 |
--------------------------------------------------------------------------------
/diskIDMainGUI.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'diskIDMainGUI.ui'
4 | #
5 | # Created by: PyQt4 UI code generator 4.11.4
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt4 import QtCore, QtGui
10 |
11 | try:
12 | _fromUtf8 = QtCore.QString.fromUtf8
13 | except AttributeError:
14 | def _fromUtf8(s):
15 | return s
16 |
17 | try:
18 | _encoding = QtGui.QApplication.UnicodeUTF8
19 | def _translate(context, text, disambig):
20 | return QtGui.QApplication.translate(context, text, disambig, _encoding)
21 | except AttributeError:
22 | def _translate(context, text, disambig):
23 | return QtGui.QApplication.translate(context, text, disambig)
24 |
25 | class Ui_kryoMain(object):
26 | def setupUi(self, kryoMain):
27 | kryoMain.setObjectName(_fromUtf8("kryoMain"))
28 | kryoMain.resize(770, 600)
29 | self.centralwidget = QtGui.QWidget(kryoMain)
30 | self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
31 | self.chooseFormats = QtGui.QPushButton(self.centralwidget)
32 | self.chooseFormats.setGeometry(QtCore.QRect(30, 10, 201, 27))
33 | self.chooseFormats.setObjectName(_fromUtf8("chooseFormats"))
34 | self.createImages = QtGui.QPushButton(self.centralwidget)
35 | self.createImages.setGeometry(QtCore.QRect(30, 50, 201, 71))
36 | self.createImages.setObjectName(_fromUtf8("createImages"))
37 | self.tryMounting = QtGui.QPushButton(self.centralwidget)
38 | self.tryMounting.setGeometry(QtCore.QRect(30, 330, 191, 27))
39 | self.tryMounting.setObjectName(_fromUtf8("tryMounting"))
40 | self.imageCreationResults = QtGui.QTextBrowser(self.centralwidget)
41 | self.imageCreationResults.setGeometry(QtCore.QRect(30, 140, 711, 181))
42 | self.imageCreationResults.setObjectName(_fromUtf8("imageCreationResults"))
43 | self.MountingResults = QtGui.QTextBrowser(self.centralwidget)
44 | self.MountingResults.setGeometry(QtCore.QRect(31, 360, 711, 192))
45 | self.MountingResults.setObjectName(_fromUtf8("MountingResults"))
46 | self.deleteUnmountable = QtGui.QCheckBox(self.centralwidget)
47 | self.deleteUnmountable.setGeometry(QtCore.QRect(225, 333, 171, 22))
48 | self.deleteUnmountable.setChecked(False)
49 | self.deleteUnmountable.setObjectName(_fromUtf8("deleteUnmountable"))
50 | self.browseOutputDir = QtGui.QPushButton(self.centralwidget)
51 | self.browseOutputDir.setGeometry(QtCore.QRect(250, 80, 141, 27))
52 | self.browseOutputDir.setObjectName(_fromUtf8("browseOutputDir"))
53 | self.browseInpDir = QtGui.QPushButton(self.centralwidget)
54 | self.browseInpDir.setGeometry(QtCore.QRect(250, 46, 141, 27))
55 | self.browseInpDir.setObjectName(_fromUtf8("browseInpDir"))
56 | self.browseDTCDir = QtGui.QPushButton(self.centralwidget)
57 | self.browseDTCDir.setGeometry(QtCore.QRect(250, 10, 141, 27))
58 | self.browseDTCDir.setObjectName(_fromUtf8("browseDTCDir"))
59 | self.inputDir = QtGui.QLineEdit(self.centralwidget)
60 | self.inputDir.setGeometry(QtCore.QRect(410, 46, 331, 27))
61 | self.inputDir.setObjectName(_fromUtf8("inputDir"))
62 | self.outputDir = QtGui.QLineEdit(self.centralwidget)
63 | self.outputDir.setGeometry(QtCore.QRect(410, 80, 331, 27))
64 | self.outputDir.setObjectName(_fromUtf8("outputDir"))
65 | self.DTCDir = QtGui.QLineEdit(self.centralwidget)
66 | self.DTCDir.setGeometry(QtCore.QRect(410, 11, 331, 27))
67 | self.DTCDir.setObjectName(_fromUtf8("DTCDir"))
68 | self.saveMountingResults = QtGui.QPushButton(self.centralwidget)
69 | self.saveMountingResults.setGeometry(QtCore.QRect(601, 330, 141, 27))
70 | self.saveMountingResults.setObjectName(_fromUtf8("saveMountingResults"))
71 | self.line = QtGui.QFrame(self.centralwidget)
72 | self.line.setGeometry(QtCore.QRect(30, 319, 711, 16))
73 | self.line.setFrameShape(QtGui.QFrame.HLine)
74 | self.line.setFrameShadow(QtGui.QFrame.Sunken)
75 | self.line.setObjectName(_fromUtf8("line"))
76 | self.saveDTCResults = QtGui.QPushButton(self.centralwidget)
77 | self.saveDTCResults.setGeometry(QtCore.QRect(601, 109, 141, 27))
78 | self.saveDTCResults.setObjectName(_fromUtf8("saveDTCResults"))
79 | self.DTCInstances = QtGui.QLineEdit(self.centralwidget)
80 | self.DTCInstances.setGeometry(QtCore.QRect(503, 109, 41, 27))
81 | self.DTCInstances.setObjectName(_fromUtf8("DTCInstances"))
82 | self.label = QtGui.QLabel(self.centralwidget)
83 | self.label.setGeometry(QtCore.QRect(253, 115, 261, 17))
84 | self.label.setObjectName(_fromUtf8("label"))
85 | kryoMain.setCentralWidget(self.centralwidget)
86 | self.menubar = QtGui.QMenuBar(kryoMain)
87 | self.menubar.setGeometry(QtCore.QRect(0, 0, 770, 25))
88 | self.menubar.setObjectName(_fromUtf8("menubar"))
89 | kryoMain.setMenuBar(self.menubar)
90 | self.statusbar = QtGui.QStatusBar(kryoMain)
91 | self.statusbar.setObjectName(_fromUtf8("statusbar"))
92 | kryoMain.setStatusBar(self.statusbar)
93 |
94 | self.retranslateUi(kryoMain)
95 | QtCore.QObject.connect(self.chooseFormats, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.choose_formats)
96 | QtCore.QObject.connect(self.createImages, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.create_images)
97 | QtCore.QObject.connect(self.tryMounting, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.try_mounting)
98 | QtCore.QObject.connect(self.browseDTCDir, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.browse_dtc_dir)
99 | QtCore.QObject.connect(self.browseInpDir, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.browse_inp_dir)
100 | QtCore.QObject.connect(self.browseOutputDir, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.browse_output_dir)
101 | QtCore.QObject.connect(self.deleteUnmountable, QtCore.SIGNAL(_fromUtf8("stateChanged(int)")), kryoMain.delete_unmountable_change)
102 | QtCore.QObject.connect(self.saveMountingResults, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.save_mounting_results)
103 | QtCore.QObject.connect(self.saveDTCResults, QtCore.SIGNAL(_fromUtf8("clicked()")), kryoMain.save_dtc_results)
104 | QtCore.QMetaObject.connectSlotsByName(kryoMain)
105 |
106 | def retranslateUi(self, kryoMain):
107 | kryoMain.setWindowTitle(_translate("kryoMain", "Disk format identifier", None))
108 | self.chooseFormats.setText(_translate("kryoMain", "Choose formats to create", None))
109 | self.createImages.setText(_translate("kryoMain", "Create images", None))
110 | self.tryMounting.setText(_translate("kryoMain", "Try mounting", None))
111 | self.deleteUnmountable.setText(_translate("kryoMain", "Delete unmountable", None))
112 | self.browseOutputDir.setText(_translate("kryoMain", "Output Directory", None))
113 | self.browseInpDir.setText(_translate("kryoMain", "Input Directory", None))
114 | self.browseDTCDir.setText(_translate("kryoMain", "DTC Directory", None))
115 | self.saveMountingResults.setText(_translate("kryoMain", "Save Results", None))
116 | self.saveDTCResults.setText(_translate("kryoMain", "Save Results", None))
117 | self.label.setText(_translate("kryoMain", "Maximum concurrent DTC instances:", None))
118 |
119 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import os
2 | import warnings
3 |
4 | from setuptools import setup
5 |
6 | with open(os.path.join('DiskFormatID', '__init__.py')) as init_:
7 | for line in init_:
8 | if '__version__' in line:
9 | version = line.split('=')[-1].strip().replace('"','')
10 | break
11 | else:
12 | version = 'unknown'
13 | warnings.warn('Unable to find version, using "%s"' % version)
14 | input("Continue?")
15 |
16 |
17 | setup(name='DiskFormatID',
18 | version=version,
19 | description='Disk Format Identification for KryoFlux',
20 | author='Euan Cochrane',
21 | author_email='euanc@foobar.com',
22 | maintainer = "Euan Cochrane",
23 | maintainer_email = "euanc@foobar.com",
24 | url="https://github.com/euanc/DiskFormatID",
25 |
26 | py_modules = ['chooseFormatsGUI', 'chooseFormats', 'diskIDMainGUI'],
27 |
28 | scripts = ['diskIDMain'],
29 |
30 | classifiers = ['Development Status :: 2 - Pre-Alpha'
31 | "Intended Audience :: Developers",
32 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
33 | "Programming Language :: Python",
34 | 'Programming Language :: Python :: 2',
35 | 'Programming Language :: Python :: 2.7'
36 | "Operating System :: OS Independent",
37 | "Topic :: Software Development :: Libraries :: Python Modules"],
38 | keywords="DiskFormatID")
39 |
40 |
--------------------------------------------------------------------------------
/ui_files/chooseFormatsGUI.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | addTypes
4 |
5 |
6 |
7 | 0
8 | 0
9 | 439
10 | 587
11 |
12 |
13 |
14 | Add Disk Types
15 |
16 |
17 |
18 |
19 |
20 | 118
21 | 10
22 | 221
23 | 27
24 |
25 |
26 |
27 |
28 |
29 |
30 | 118
31 | 60
32 | 61
33 | 27
34 |
35 |
36 |
37 |
38 |
39 |
40 | 277
41 | 59
42 | 61
43 | 27
44 |
45 |
46 |
47 |
48 |
49 |
50 | 118
51 | 100
52 | 221
53 | 27
54 |
55 |
56 |
57 |
58 |
59 |
60 | 118
61 | 140
62 | 221
63 | 27
64 |
65 |
66 |
67 |
68 |
69 |
70 | 118
71 | 177
72 | 101
73 | 27
74 |
75 |
76 |
77 |
78 |
79 |
80 | 248
81 | 177
82 | 41
83 | 27
84 |
85 |
86 |
87 |
88 |
89 |
90 | 118
91 | 217
92 | 221
93 | 27
94 |
95 |
96 |
97 |
98 |
99 |
100 | 131
101 | 295
102 | 121
103 | 22
104 |
105 |
106 |
107 | Flippy Mode
108 |
109 |
110 |
111 |
112 | true
113 |
114 |
115 |
116 | 350
117 | 62
118 | 99
119 | 22
120 |
121 |
122 |
123 | Default
124 |
125 |
126 | true
127 |
128 |
129 |
130 |
131 |
132 | 350
133 | 103
134 | 99
135 | 22
136 |
137 |
138 |
139 | Default
140 |
141 |
142 | true
143 |
144 |
145 |
146 |
147 |
148 | 349
149 | 143
150 | 99
151 | 22
152 |
153 |
154 |
155 | Default
156 |
157 |
158 | true
159 |
160 |
161 |
162 |
163 |
164 | 349
165 | 180
166 | 99
167 | 22
168 |
169 |
170 |
171 | Default
172 |
173 |
174 | true
175 |
176 |
177 |
178 |
179 |
180 | 349
181 | 217
182 | 99
183 | 22
184 |
185 |
186 |
187 | Default
188 |
189 |
190 | true
191 |
192 |
193 |
194 |
195 |
196 | 259
197 | 290
198 | 171
199 | 31
200 |
201 |
202 |
203 | Save (and add another)
204 |
205 |
206 |
207 |
208 |
209 | 29
210 | 12
211 | 81
212 | 20
213 |
214 |
215 |
216 | Image Type
217 |
218 |
219 |
220 |
221 |
222 | 29
223 | 62
224 | 81
225 | 20
226 |
227 |
228 |
229 | Start Track
230 |
231 |
232 |
233 |
234 |
235 | 205
236 | 62
237 | 71
238 | 20
239 |
240 |
241 |
242 | End Track
243 |
244 |
245 |
246 |
247 |
248 | 31
249 | 104
250 | 81
251 | 20
252 |
253 |
254 |
255 | Side Mode
256 |
257 |
258 |
259 |
260 |
261 | 29
262 | 143
263 | 81
264 | 20
265 |
266 |
267 |
268 | Sector Size
269 |
270 |
271 |
272 |
273 |
274 | 19
275 | 180
276 | 91
277 | 20
278 |
279 |
280 |
281 | Sector Count
282 |
283 |
284 |
285 |
286 |
287 | 9
288 | 220
289 | 101
290 | 20
291 |
292 |
293 |
294 | Track distance
295 |
296 |
297 |
298 |
299 |
300 | 24
301 | 260
302 | 81
303 | 20
304 |
305 |
306 |
307 | Target RPM
308 |
309 |
310 |
311 |
312 |
313 | 350
314 | 258
315 | 99
316 | 22
317 |
318 |
319 |
320 | Default
321 |
322 |
323 | true
324 |
325 |
326 |
327 |
328 |
329 | 10
330 | 370
331 | 421
332 | 171
333 |
334 |
335 |
336 |
337 |
338 |
339 | 330
340 | 338
341 | 99
342 | 27
343 |
344 |
345 |
346 | Reset all
347 |
348 |
349 |
350 |
351 |
352 | 12
353 | 350
354 | 181
355 | 17
356 |
357 |
358 |
359 |
360 | 75
361 | true
362 |
363 |
364 |
365 | Configured image types:
366 |
367 |
368 |
369 |
370 |
371 | 118
372 | 255
373 | 221
374 | 27
375 |
376 |
377 |
378 |
379 |
389 |
390 |
391 |
392 |
393 |
394 | resetTypes
395 | clicked()
396 | addTypes
397 | reset_types()
398 |
399 |
400 | 378
401 | 383
402 |
403 |
404 | 95
405 | 352
406 |
407 |
408 |
409 |
410 | addType
411 | clicked()
412 | addTypes
413 | save_and_add()
414 |
415 |
416 | 381
417 | 335
418 |
419 |
420 | 413
421 | 44
422 |
423 |
424 |
425 |
426 | tracksDefault
427 | stateChanged(int)
428 | addTypes
429 | tracks_default_change()
430 |
431 |
432 | 396
433 | 100
434 |
435 |
436 | 367
437 | 74
438 |
439 |
440 |
441 |
442 | sideModeDefault
443 | stateChanged(int)
444 | addTypes
445 | side_mode_default_change()
446 |
447 |
448 | 359
449 | 141
450 |
451 |
452 | 349
453 | 122
454 |
455 |
456 |
457 |
458 | sectorSizeDefault
459 | stateChanged(int)
460 | addTypes
461 | sector_size_default_change()
462 |
463 |
464 | 379
465 | 171
466 |
467 |
468 | 340
469 | 157
470 |
471 |
472 |
473 |
474 | sectorCountDefault
475 | stateChanged(int)
476 | addTypes
477 | sector_count_default_change()
478 |
479 |
480 | 379
481 | 218
482 |
483 |
484 | 336
485 | 208
486 |
487 |
488 |
489 |
490 | trackDistanceDefault
491 | stateChanged(int)
492 | addTypes
493 | track_distance_default_change()
494 |
495 |
496 | 380
497 | 254
498 |
499 |
500 | 336
501 | 228
502 |
503 |
504 |
505 |
506 | targetRPMDefault
507 | stateChanged(int)
508 | addTypes
509 | target_RPM_default_change()
510 |
511 |
512 | 408
513 | 288
514 |
515 |
516 | 350
517 | 268
518 |
519 |
520 |
521 |
522 | flippyMode
523 | stateChanged(int)
524 | addTypes
525 | flippy_change()
526 |
527 |
528 | 177
529 | 325
530 |
531 |
532 | 99
533 | 316
534 |
535 |
536 |
537 |
538 |
539 | reset_types()
540 | save_and_add()
541 | side_mode_default_change()
542 | tracks_default_change()
543 | sector_size_default_change()
544 | sector_count_default_change()
545 | track_distance_default_change()
546 | target_RPM_default_change()
547 | flippy_change()
548 |
549 |
550 |
--------------------------------------------------------------------------------
/ui_files/diskIDMainGUI.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | kryoMain
4 |
5 |
6 |
7 | 0
8 | 0
9 | 770
10 | 600
11 |
12 |
13 |
14 | Disk format identifier
15 |
16 |
17 |
18 |
19 |
20 | 30
21 | 10
22 | 201
23 | 27
24 |
25 |
26 |
27 | Choose formats to create
28 |
29 |
30 |
31 |
32 |
33 | 30
34 | 50
35 | 201
36 | 71
37 |
38 |
39 |
40 | Create images
41 |
42 |
43 |
44 |
45 |
46 | 30
47 | 330
48 | 191
49 | 27
50 |
51 |
52 |
53 | Try mounting
54 |
55 |
56 |
57 |
58 |
59 | 30
60 | 140
61 | 711
62 | 181
63 |
64 |
65 |
66 |
67 |
68 |
69 | 31
70 | 360
71 | 711
72 | 192
73 |
74 |
75 |
76 |
77 |
78 |
79 | 225
80 | 333
81 | 171
82 | 22
83 |
84 |
85 |
86 | Delete unmountable
87 |
88 |
89 | false
90 |
91 |
92 |
93 |
94 |
95 | 250
96 | 80
97 | 141
98 | 27
99 |
100 |
101 |
102 | Output Directory
103 |
104 |
105 |
106 |
107 |
108 | 250
109 | 46
110 | 141
111 | 27
112 |
113 |
114 |
115 | Input Directory
116 |
117 |
118 |
119 |
120 |
121 | 250
122 | 10
123 | 141
124 | 27
125 |
126 |
127 |
128 | DTC Directory
129 |
130 |
131 |
132 |
133 |
134 | 410
135 | 46
136 | 331
137 | 27
138 |
139 |
140 |
141 |
142 |
143 |
144 | 410
145 | 80
146 | 331
147 | 27
148 |
149 |
150 |
151 |
152 |
153 |
154 | 410
155 | 11
156 | 331
157 | 27
158 |
159 |
160 |
161 |
162 |
163 |
164 | 601
165 | 330
166 | 141
167 | 27
168 |
169 |
170 |
171 | Save Results
172 |
173 |
174 |
175 |
176 |
177 | 30
178 | 319
179 | 711
180 | 16
181 |
182 |
183 |
184 | Qt::Horizontal
185 |
186 |
187 |
188 |
189 |
190 | 601
191 | 109
192 | 141
193 | 27
194 |
195 |
196 |
197 | Save Results
198 |
199 |
200 |
201 |
202 |
203 | 503
204 | 109
205 | 41
206 | 27
207 |
208 |
209 |
210 |
211 |
212 |
213 | 253
214 | 115
215 | 261
216 | 17
217 |
218 |
219 |
220 | Maximum concurrent DTC instances:
221 |
222 |
223 |
224 |
234 |
235 |
236 |
237 |
238 |
239 | chooseFormats
240 | clicked()
241 | kryoMain
242 | choose_formats()
243 |
244 |
245 | 173
246 | 61
247 |
248 |
249 | 295
250 | 72
251 |
252 |
253 |
254 |
255 | createImages
256 | clicked()
257 | kryoMain
258 | create_images()
259 |
260 |
261 | 183
262 | 109
263 |
264 |
265 | 253
266 | 85
267 |
268 |
269 |
270 |
271 | tryMounting
272 | clicked()
273 | kryoMain
274 | try_mounting()
275 |
276 |
277 | 170
278 | 369
279 |
280 |
281 | 9
282 | 332
283 |
284 |
285 |
286 |
287 | browseDTCDir
288 | clicked()
289 | kryoMain
290 | browse_dtc_dir()
291 |
292 |
293 | 349
294 | 49
295 |
296 |
297 | 17
298 | 77
299 |
300 |
301 |
302 |
303 | browseInpDir
304 | clicked()
305 | kryoMain
306 | browse_inp_dir()
307 |
308 |
309 | 383
310 | 92
311 |
312 |
313 | 397
314 | 94
315 |
316 |
317 |
318 |
319 | browseOutputDir
320 | clicked()
321 | kryoMain
322 | browse_output_dir()
323 |
324 |
325 | 350
326 | 121
327 |
328 |
329 | 401
330 | 121
331 |
332 |
333 |
334 |
335 | deleteUnmountable
336 | stateChanged(int)
337 | kryoMain
338 | delete_unmountable_change()
339 |
340 |
341 | 354
342 | 361
343 |
344 |
345 | 486
346 | 335
347 |
348 |
349 |
350 |
351 | saveMountingResults
352 | clicked()
353 | kryoMain
354 | save_mounting_results()
355 |
356 |
357 | 649
358 | 366
359 |
360 |
361 | 762
362 | 363
363 |
364 |
365 |
366 |
367 | saveDTCResults
368 | clicked()
369 | kryoMain
370 | save_dtc_results()
371 |
372 |
373 | 717
374 | 331
375 |
376 |
377 | 757
378 | 219
379 |
380 |
381 |
382 |
383 |
384 | choose_formats()
385 | create_images()
386 | try_mounting()
387 | delete_unmountable_change()
388 | browse_dtc_dir()
389 | browse_inp_dir()
390 | browse_output_dir()
391 | save_dtc_results()
392 | save_mounting_results()
393 |
394 |
395 |
--------------------------------------------------------------------------------