-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFileMenu.py
More file actions
175 lines (149 loc) · 6.11 KB
/
FileMenu.py
File metadata and controls
175 lines (149 loc) · 6.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/usr/bin/python
#
# File: FileMenu.py
# Author: Ellery Chan
# Email: ellery@precisionlightworks.com
# Date: Nov 19, 2015
#
# Copyright (c) 2015 Precision Lightworks, LLC. All rights reserved.
#----------------------------------------------------------------------------
from __future__ import print_function, division
from Tkinter import Menu
import tkMessageBox
import tkFileDialog
import os.path
#----------------------------------------------------------------------------
class FileMenu(Menu):
""" Base class for a file menu that has the common entries New, Open, Save, Save As, Export, and Exit """
def __init__(self, menubar, **kwargs):
""" Constructor """
Menu.__init__(self, menubar, **kwargs)
self.add_command(label="New", command=self.onFileNew)
self.add_command(label="Open...", command=self.onFileOpen)
self.add_command(label="Revert", command=self.onRevert)
self.add_command(label="Save", command=self.onFileSave)
self.add_command(label="Save As...", command=self.onFileSaveAs)
self.add_command(label="Export...", command=self.onFileExport)
self.add_separator()
self.add_command(label="Exit", command=self.onExit)
self._isModified = False
self.currFile = None
self.fileTypes = [('JSON files', '*.json'), ('All files', '*')]
self.defaultExt = "json"
self.exportFileTypes = [('PDF files', '*.pdf'), ("Markdown files", "*.md"), ('All files', '*')]
@property
def isModified(self):
return self._isModified
@isModified.setter
def isModified(self, value):
self.setModified(value)
def setModified(self, value):
""" Set the _isModified flag to value, and call self.onModifiedChange() """
if self._isModified != value:
self._isModified = value
self.onModifiedChange()
def onModifiedChange(self):
""" Called when self._isModified is changed.
Subclass should override this.
"""
pass
def askSave(self):
""" Ask if the current file should be saved, then do as requested.
Returns True to proceed, and False if the user wants to cancel.
"""
resp = tkMessageBox.askyesnocancel(title="Save Modified File?", message="The current file is modified.\n\nClick Yes to Save it.\nClick No to discard changes.\nClick Cancel to resume editing the current file.")
# Returns True, False, or None
if resp is None:
return False
if resp:
self.onFileSave()
return True
def onFileNew(self):
""" Return False if the operation was cancelled. """
if self.isModified:
if not self.askSave():
return False
self.setModified(False)
self.currFile = None
return True
def onFileOpen(self, path=None):
""" Save a modified file if needed.
Get a pathname if None was specified.
Return True if successful or False if the operation was cancelled.
"""
if self.isModified:
if not self.askSave():
return False
# self.isModified is False at this point
if path is None: # Interactive file open
# ftypes = [('JSON files', '*.json'), ('All files', '*')]
path = tkFileDialog.askopenfilename(filetypes=self.fileTypes, defaultextension=self.defaultExt)
if path:
self.currFile = path
return path and len(path)
def onRevert(self):
""" Reset to the initial state of the opened file """
return True
def onFileSave(self):
""" Return False if the operation was cancelled. """
if self.isModified:
if not self.currFile:# or not os.path.exists(self.qaFile):
if not self.onFileSaveAs():
return False
else:
if not self.saveToFile(self.currFile):
return False
self.setModified(False)
return True
def onFileSaveAs(self):
""" Request a filename from the user and save the file to that name.
Note: does not force an extension like the standard Windows save dialog
Return False if the operation was cancelled.
"""
saveDir = os.path.dirname(self.currFile) if self.currFile else None
path = tkFileDialog.asksaveasfilename(filetypes=self.fileTypes, initialdir=saveDir)
if path:
if self.saveToFile(path):
self.currFile = path
self.setModified(False)
return True
return False
def saveToFile(self, path):
""" Save <something> to the specified file path.
Subclass should override the default behavior.
Return True on success.
"""
return False
def onFileExport(self):
""" Request a filename from the user and export data to that name.
Note: does not force an extension like the standard Windows save dialog
Return False if the operation was cancelled.
"""
path = tkFileDialog.asksaveasfilename(filetypes=self.exportFileTypes)
if path:
return self.exportToFile(path)
return False
def exportToFile(self, path):
""" Export <something> to the specified file path.
Subclass should override the default behavior.
Return True on success.
"""
return False
def onExit(self):
""" Subclass should override this method """
if self.isModified:
return self.askSave()
else:
return True
#----------------------------------------------------------------------------
if __name__ == "__main__":
import sys
import unittest
class FileMenuTestCase(unittest.TestCase):
def testInit(self):
pass
# def testEq(self):
# obj = FileMenu()
# self.assertEqual(obj, 42)
unittest.main() # run the unit tests
sys.exit(0)