Mercurial > projects > dwt-samples
annotate jface/Librarian.d @ 72:fc7a8f537871
Open/Save with experimental runner factory.
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 13 Apr 2008 17:19:38 +0200 |
parents | 63a7769cce57 |
children | 9ff9b8f7284b |
rev | line source |
---|---|
66 | 1 module jface.Librarian; |
2 | |
3 import dwtx.core.runtime.IProgressMonitor; | |
4 import dwtx.jface.action.MenuManager; | |
5 import dwtx.jface.action.StatusLineManager; | |
6 import dwtx.jface.action.ToolBarManager; | |
7 import dwtx.jface.action.CoolBarManager; | |
8 import dwtx.jface.action.Action; | |
9 import dwtx.jface.action.IAction; | |
10 import dwtx.jface.dialogs.MessageDialog; | |
11 import dwtx.jface.operation.IRunnableWithProgress; | |
12 import dwtx.jface.operation.ModalContext; | |
13 import dwtx.jface.util.IPropertyChangeListener; | |
14 import dwtx.jface.util.PropertyChangeEvent; | |
15 import dwtx.jface.viewers.TableViewer; | |
16 import dwtx.jface.viewers.Viewer; | |
17 import dwtx.jface.viewers.ITableLabelProvider; | |
18 import dwtx.jface.viewers.IStructuredContentProvider; | |
19 import dwtx.jface.viewers.ICellModifier; | |
20 import dwtx.jface.viewers.ILabelProviderListener; | |
21 import dwtx.jface.viewers.TextCellEditor; | |
22 import dwtx.jface.viewers.CellEditor; | |
23 import dwtx.jface.viewers.CheckboxCellEditor; | |
24 import dwtx.jface.action.Separator; | |
25 import dwtx.jface.viewers.IStructuredSelection; | |
26 import dwtx.jface.window.ApplicationWindow; | |
27 import dwtx.jface.resource.ImageDescriptor; | |
28 | |
29 import dwt.DWT; | |
30 | |
31 import dwt.graphics.Image; | |
32 import dwt.graphics.ImageData; | |
33 import dwt.layout.GridData; | |
34 import dwt.layout.GridLayout; | |
35 import dwt.widgets.Display; | |
36 import dwt.widgets.FileDialog; | |
37 import dwt.widgets.MessageBox; | |
38 import dwt.widgets.Shell; | |
39 import dwt.widgets.Table; | |
40 import dwt.widgets.TableColumn; | |
41 import dwt.widgets.Control; | |
42 import dwt.widgets.Composite; | |
43 import dwt.widgets.Item; | |
44 | |
45 import dwt.dwthelper.utils; | |
46 import dwt.dwthelper.ByteArrayInputStream; | |
47 | |
48 import tango.text.convert.Format; | |
49 import tango.util.collection.LinkSeq; | |
50 import tango.io.FilePath; | |
51 import tango.io.File; | |
52 import tango.io.Print; | |
53 import tango.io.stream.FileStream; | |
54 import tango.text.Util; | |
55 import tango.text.stream.LineIterator; | |
56 import tango.util.log.Trace; | |
57 | |
67 | 58 version(JIVE) import jive.stacktrace; |
59 | |
66 | 60 /++ |
61 Known Problem: | |
62 Blocks in Save Method | |
63 Not prepared for windows. | |
64 ++/ | |
65 | |
66 /** | |
67 * The application entry point | |
68 * | |
69 * @param args the command line arguments | |
70 */ | |
71 void main() { | |
72 (new Librarian()).run(); | |
73 } | |
74 | |
75 | |
76 /** | |
77 * This class keeps track of you library, and who you've loaned books to | |
78 */ | |
79 public class Librarian : ApplicationWindow { | |
80 // A static instance to the running application | |
81 private static Librarian APP; | |
82 | |
83 // Table column names/properties | |
84 public static const String TITLE = "Title"; | |
85 public static const String CHECKED_OUT = "?"; | |
86 public static const String WHO = "By Whom"; | |
87 public static const String[] PROPS = [ TITLE, CHECKED_OUT, WHO ]; | |
88 | |
89 // The viewer | |
90 private TableViewer viewer; | |
91 | |
92 // The current library | |
93 private Library library; | |
94 | |
95 // The actions | |
96 private NewAction newAction; | |
97 private OpenAction openAction; | |
98 private SaveAction saveAction; | |
99 private SaveAsAction saveAsAction; | |
100 private ExitAction exitAction; | |
101 private AddBookAction addBookAction; | |
102 private RemoveBookAction removeBookAction; | |
103 private AboutAction aboutAction; | |
104 private ShowBookCountAction showBookCountAction; | |
105 | |
106 /** | |
107 * Gets the running application | |
108 */ | |
109 public static Librarian getApp() { | |
110 return APP; | |
111 } | |
112 | |
113 /** | |
114 * Librarian constructor | |
115 */ | |
116 public this() { | |
117 super(null); | |
118 | |
119 APP = this; | |
120 | |
121 // Create the data model | |
122 library = new Library(); | |
123 | |
124 // Create the actions | |
125 newAction = new NewAction(); | |
126 openAction = new OpenAction(); | |
127 saveAction = new SaveAction(); | |
128 saveAsAction = new SaveAsAction(); | |
129 exitAction = new ExitAction(); | |
130 addBookAction = new AddBookAction(); | |
131 removeBookAction = new RemoveBookAction(); | |
132 aboutAction = new AboutAction(); | |
133 showBookCountAction = new ShowBookCountAction(); | |
134 | |
135 addMenuBar(); | |
136 //addCoolBar(DWT.NONE); | |
137 addToolBar(DWT.FLAT); | |
138 addStatusLine(); | |
139 } | |
140 | |
141 /** | |
142 * Runs the application | |
143 */ | |
144 public void run() { | |
145 // Don't return from open() until window closes | |
146 setBlockOnOpen(true); | |
147 | |
148 // Open the main window | |
149 open(); | |
150 | |
151 // Dispose the display | |
152 Display.getCurrent().dispose(); | |
153 } | |
154 | |
155 /** | |
156 * Configures the shell | |
157 * | |
158 * @param shell the shell | |
159 */ | |
160 protected void configureShell(Shell shell) { | |
161 super.configureShell(shell); | |
162 | |
163 // Set the title bar text | |
164 shell.setText("Librarian"); | |
165 } | |
166 | |
167 /** | |
168 * Creates the main window's contents | |
169 * | |
170 * @param parent the main window | |
171 * @return Control | |
172 */ | |
173 protected Control createContents(Composite parent) { | |
174 Composite composite = new Composite(parent, DWT.NONE); | |
175 composite.setLayout(new GridLayout(1, false)); | |
176 | |
177 viewer = new TableViewer(composite, DWT.FULL_SELECTION | DWT.BORDER); | |
178 Table table = viewer.getTable(); | |
179 table.setLayoutData(new GridData(GridData.FILL_BOTH)); | |
180 | |
181 // Set up the viewer | |
182 viewer.setContentProvider(new LibraryContentProvider()); | |
183 viewer.setLabelProvider(new LibraryLabelProvider()); | |
184 viewer.setInput(library); | |
185 viewer.setColumnProperties(PROPS); | |
186 viewer.setCellEditors( [ cast(CellEditor) new TextCellEditor(table), | |
187 new CheckboxCellEditor(table), new TextCellEditor(table)]); | |
188 viewer.setCellModifier(new LibraryCellModifier()); | |
189 | |
190 // Set up the table | |
191 for (int i = 0, n = PROPS.length; i < n; i++) | |
192 (new TableColumn(table, DWT.LEFT)).setText(PROPS[i]); | |
193 table.setHeaderVisible(true); | |
194 table.setLinesVisible(true); | |
195 | |
196 // Add code to hide or display the book count based on the action | |
197 showBookCountAction.addPropertyChangeListener(new class IPropertyChangeListener { | |
198 public void propertyChange(PropertyChangeEvent event) { | |
199 // The value has changed; refresh the view | |
200 refreshView(); | |
201 } | |
202 }); | |
203 | |
204 // Rfresh the view to get the columns right-sized | |
205 refreshView(); | |
206 | |
207 return composite; | |
208 } | |
209 | |
210 /** | |
211 * Creates the menu for the application | |
212 * | |
213 * @return MenuManager | |
214 */ | |
215 protected MenuManager createMenuManager() { | |
216 // Create the main menu | |
217 MenuManager mm = new MenuManager(); | |
218 | |
219 // Create the File menu | |
220 MenuManager fileMenu = new MenuManager("File"); | |
221 mm.add(fileMenu); | |
222 | |
223 // Add the actions to the File menu | |
224 fileMenu.add(newAction); | |
225 fileMenu.add(openAction); | |
226 fileMenu.add(saveAction); | |
227 fileMenu.add(saveAsAction); | |
228 fileMenu.add(new Separator()); | |
229 fileMenu.add(exitAction); | |
230 | |
231 // Create the Book menu | |
232 MenuManager bookMenu = new MenuManager("Book"); | |
233 mm.add(bookMenu); | |
234 | |
235 // Add the actions to the Book menu | |
236 bookMenu.add(addBookAction); | |
237 bookMenu.add(removeBookAction); | |
238 | |
239 // Create the View menu | |
240 MenuManager viewMenu = new MenuManager("View"); | |
241 mm.add(viewMenu); | |
242 | |
243 // Add the actions to the View menu | |
244 viewMenu.add(showBookCountAction); | |
245 | |
246 // Create the Help menu | |
247 MenuManager helpMenu = new MenuManager("Help"); | |
248 mm.add(helpMenu); | |
249 | |
250 // Add the actions to the Help menu | |
251 helpMenu.add(aboutAction); | |
252 | |
253 return mm; | |
254 } | |
255 | |
256 /** | |
257 * Creates the toolbar for the application | |
258 */ | |
259 protected ToolBarManager createToolBarManager(int style) { | |
260 // Create the toolbar manager | |
261 ToolBarManager tbm = new ToolBarManager(style); | |
262 | |
263 // Add the file actions | |
264 tbm.add(newAction); | |
265 tbm.add(openAction); | |
266 tbm.add(saveAction); | |
267 tbm.add(saveAsAction); | |
268 | |
269 // Add a separator | |
270 tbm.add(new Separator()); | |
271 | |
272 // Add the book actions | |
273 tbm.add(addBookAction); | |
274 tbm.add(removeBookAction); | |
275 | |
276 // Add a separator | |
277 tbm.add(new Separator()); | |
278 | |
279 // Add the show book count, which will appear as a toggle button | |
280 tbm.add(showBookCountAction); | |
281 | |
282 // Add a separator | |
283 tbm.add(new Separator()); | |
284 | |
285 // Add the about action | |
286 tbm.add(aboutAction); | |
287 | |
288 return tbm; | |
289 } | |
290 /+ | |
291 /** | |
292 * Creates the coolbar for the application | |
293 */ | |
294 protected CoolBarManager createCoolBarManager(int style) { | |
295 // Create the coolbar manager | |
296 CoolBarManager cbm = new CoolBarManager(style); | |
297 | |
298 // Add the toolbar | |
299 cbm.add(createToolBarManager(DWT.FLAT)); | |
300 | |
301 return cbm; | |
302 } | |
303 +/ | |
304 /** | |
305 * Creates the status line manager | |
306 */ | |
307 protected StatusLineManager createStatusLineManager() { | |
308 return new StatusLineManager(); | |
309 } | |
310 | |
311 /** | |
312 * Adds a book | |
313 */ | |
314 public void addBook() { | |
315 library.add(new Book("[Enter Title]")); | |
316 refreshView(); | |
317 } | |
318 | |
319 /** | |
320 * Removes the selected book | |
321 */ | |
322 public void removeSelectedBook() { | |
323 Book book = cast(Book) (cast(IStructuredSelection) viewer.getSelection()) | |
324 .getFirstElement(); | |
325 if (book !is null) library.remove(book); | |
326 refreshView(); | |
327 } | |
328 | |
329 /** | |
330 * Opens a file | |
331 * | |
332 * @param fileName the file name | |
333 */ | |
334 public void openFile(String fileName) { | |
335 if (checkOverwrite()) { | |
336 // Disable the actions, so user can't change library while loading | |
337 enableActions(false); | |
338 | |
339 library = new Library(); | |
340 try { | |
341 // Launch the Open runnable | |
72
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
342 ModalContext.run( dgIRunnableWithProgress( &internalOpen, fileName ), |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
343 true, getStatusLineManager().getProgressMonitor(), getShell().getDisplay()); |
66 | 344 } catch (InterruptedException e) { |
345 } catch (InvocationTargetException e) { | |
346 } finally { | |
347 // Enable actions | |
348 enableActions(true); | |
349 } | |
350 } | |
351 } | |
72
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
352 private void internalOpen( IProgressMonitor progressMonitor,String filename ){ |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
353 try { |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
354 progressMonitor.beginTask("Loading", IProgressMonitor.UNKNOWN); |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
355 library.load(filename); |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
356 progressMonitor.done(); |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
357 viewer.setInput(library); |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
358 refreshView(); |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
359 } catch (IOException e) { |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
360 showError( Format("Can't load file {}\r{}", filename, e.msg)); |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
361 } |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
362 } |
66 | 363 /** |
364 * Creates a new file | |
365 */ | |
366 public void newFile() { | |
367 if (checkOverwrite()) { | |
368 library = new Library(); | |
72
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
369 viewer.setInput(library); |
66 | 370 } |
371 } | |
372 | |
373 /** | |
374 * Saves the current file | |
375 */ | |
376 public void saveFile() { | |
377 String fileName = library.getFileName(); | |
378 if (fileName is null) { | |
379 fileName = (new SafeSaveDialog(getShell())).open(); | |
380 } | |
72
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
381 if (fileName is null) { |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
382 return; |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
383 } |
66 | 384 saveFileAs(fileName); |
385 } | |
386 | |
387 /** | |
388 * Saves the current file using the specified file name | |
389 * | |
390 * @param fileName the file name | |
391 */ | |
392 public void saveFileAs(String fileName) { | |
393 // Disable the actions, so user can't change file while it's saving | |
394 enableActions(false); | |
395 try { | |
71 | 396 auto pm = getStatusLineManager().getProgressMonitor(); |
397 auto disp = getShell().getDisplay(); | |
72
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
398 // Launch the Save runnable |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
399 ModalContext.run( dgIRunnableWithProgress( &internalSave, fileName ), true, pm, disp); |
71 | 400 |
66 | 401 } catch (InterruptedException e) { |
402 } catch (InvocationTargetException e) { | |
403 } finally { | |
404 // Enable the actions | |
405 enableActions(true); | |
406 } | |
407 } | |
408 | |
72
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
409 private void internalSave(IProgressMonitor progressMonitor,String filename ){ |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
410 try { |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
411 progressMonitor.beginTask("Saving", IProgressMonitor.UNKNOWN ); |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
412 library.save(filename); |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
413 progressMonitor.done(); |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
414 } catch (IOException e) { |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
415 showError(Format("Can't save file {}\r{}", library.getFileName(), e.msg )); |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
416 } |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
417 } |
66 | 418 /** |
72
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
419 * Shows an error |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
420 * |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
421 * @param msg the error |
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
422 */ |
66 | 423 public void showError(String msg) { |
424 MessageDialog.openError(getShell(), "Error", msg); | |
425 } | |
426 | |
427 /** | |
428 * Refreshes the view | |
429 */ | |
430 public void refreshView() { | |
431 // Refresh the view | |
432 viewer.refresh(); | |
433 | |
434 // Repack the columns | |
435 for (int i = 0, n = viewer.getTable().getColumnCount(); i < n; i++) { | |
436 viewer.getTable().getColumn(i).pack(); | |
437 } | |
438 | |
439 getStatusLineManager().setMessage( | |
440 showBookCountAction.isChecked() ? Format( "Book Count: {}", | |
441 library.getBooks().size()) : ""); | |
442 } | |
443 | |
444 /** | |
445 * Checks the current file for unsaved changes. If it has unsaved changes, | |
446 * confirms that user wants to overwrite | |
447 * | |
448 * @return bool | |
449 */ | |
450 public bool checkOverwrite() { | |
451 bool proceed = true; | |
452 if (library.isDirty()) { | |
453 proceed = MessageDialog.openConfirm(getShell(), "Are you sure?", | |
454 "You have unsaved changes--are you sure you want to lose them?"); | |
455 } | |
456 return proceed; | |
457 } | |
458 | |
459 /** | |
460 * Sets the current library dirty | |
461 */ | |
462 public void setLibraryDirty() { | |
463 library.setDirty(); | |
464 } | |
465 | |
466 /** | |
467 * Closes the application | |
468 */ | |
469 public bool close() { | |
470 if (checkOverwrite()) return super.close(); | |
471 return false; | |
472 } | |
473 | |
474 /** | |
475 * Enables or disables the actions | |
476 * | |
477 * @param enable true to enable, false to disable | |
478 */ | |
479 private void enableActions(bool enable) { | |
480 newAction.setEnabled(enable); | |
481 openAction.setEnabled(enable); | |
482 saveAction.setEnabled(enable); | |
483 saveAsAction.setEnabled(enable); | |
484 exitAction.setEnabled(enable); | |
485 addBookAction.setEnabled(enable); | |
486 removeBookAction.setEnabled(enable); | |
487 aboutAction.setEnabled(enable); | |
488 showBookCountAction.setEnabled(enable); | |
489 } | |
490 } | |
491 | |
492 | |
493 /** | |
494 * This action class responds to requests to save a file | |
495 */ | |
496 public class SaveAction : Action { | |
497 /** | |
498 * SaveAction constructor | |
499 */ | |
500 public this() { | |
501 super("&Save@Ctrl+S", ImageDescriptor.createFromFile( getImportData!("jface.librarian.save.gif"))); | |
502 setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledSave.gif"))); | |
503 setToolTipText("Save"); | |
504 } | |
505 | |
506 /** | |
507 * Saves the file | |
508 */ | |
509 public void run() { | |
510 Librarian.getApp().saveFile(); | |
511 } | |
512 } | |
513 | |
514 | |
515 | |
516 | |
517 /** | |
518 * This action class responds to requests open a file | |
519 */ | |
520 public class OpenAction : Action { | |
521 /** | |
522 * OpenAction constructor | |
523 */ | |
524 public this() { | |
525 super("&Open...@Ctrl+O", ImageDescriptor.createFromFile(getImportData!("jface.librarian.open.gif"))); | |
526 setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledOpen.gif"))); | |
527 setToolTipText("Open"); | |
528 } | |
529 | |
530 /** | |
531 * Opens an existing file | |
532 */ | |
533 public void run() { | |
534 // Use the file dialog | |
535 FileDialog dlg = new FileDialog(Librarian.getApp().getShell(), DWT.OPEN); | |
536 String fileName = dlg.open(); | |
537 if (fileName !is null) { | |
538 Librarian.getApp().openFile(fileName); | |
539 } | |
540 } | |
541 } | |
542 | |
543 /** | |
544 * This action class reponds to requests for a new file | |
545 */ | |
546 public class NewAction : Action { | |
547 /** | |
548 * NewAction constructor | |
549 */ | |
550 public this() { | |
551 super("&New@Ctrl+N", ImageDescriptor.createFromFile(getImportData!("jface.librarian.new.gif"))); | |
552 setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledNew.gif"))); | |
553 setToolTipText("New"); | |
554 } | |
555 | |
556 /** | |
557 * Creates a new file | |
558 */ | |
559 public void run() { | |
560 Librarian.getApp().newFile(); | |
561 } | |
562 } | |
563 | |
564 /** | |
565 * This action class responds to requests to save a file as . . . | |
566 */ | |
567 public class SaveAsAction : Action { | |
568 /** | |
569 * SaveAsAction constructor | |
570 */ | |
571 public this() { | |
572 super("Save As...", ImageDescriptor.createFromFile(getImportData!("jface.librarian.saveAs.gif"))); | |
573 setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledSaveAs.gif"))); | |
574 setToolTipText("Save As"); | |
575 } | |
576 | |
577 /** | |
578 * Saves the file | |
579 */ | |
580 public void run() { | |
581 SafeSaveDialog dlg = new SafeSaveDialog(Librarian.getApp().getShell()); | |
582 String fileName = dlg.open(); | |
583 if (fileName !is null) { | |
72
fc7a8f537871
Open/Save with experimental runner factory.
Frank Benoit <benoit@tionex.de>
parents:
71
diff
changeset
|
584 Librarian.getApp().saveFileAs(fileName); |
66 | 585 } |
586 } | |
587 } | |
588 | |
589 | |
590 /** | |
591 * This action class deletes a book | |
592 */ | |
593 public class RemoveBookAction : Action { | |
594 /** | |
595 * RemoveBookAction constructor | |
596 */ | |
597 public this() { | |
598 super("&Remove Book@Ctrl+X", ImageDescriptor.createFromFile(getImportData!("jface.librarian.removeBook.gif"))); | |
599 setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledRemoveBook.gif"))); | |
600 setToolTipText("Remove"); | |
601 } | |
602 | |
603 /** | |
604 * Removes the selected book after confirming | |
605 */ | |
606 public void run() { | |
607 if (MessageDialog.openConfirm(Librarian.getApp().getShell(), "Are you sure?", | |
608 "Are you sure you want to remove the selected book?")) { | |
609 Librarian.getApp().removeSelectedBook(); | |
610 } | |
611 } | |
612 } | |
613 | |
614 | |
615 /** | |
616 * This action class adds a book | |
617 */ | |
618 public class AddBookAction : Action { | |
619 /** | |
620 * AddBookAction constructor | |
621 */ | |
622 public this() { | |
623 super("&Add Book@Ctrl+B", ImageDescriptor.createFromFile(getImportData!("jface.librarian.addBook.gif"))); | |
624 setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledAddBook.gif"))); | |
625 setToolTipText("Add"); | |
626 } | |
627 | |
628 /** | |
629 * Adds a book to the current library | |
630 */ | |
631 public void run() { | |
632 Librarian.getApp().addBook(); | |
633 } | |
634 } | |
635 | |
636 /** | |
637 * This action class exits the application | |
638 */ | |
639 public class ExitAction : Action { | |
640 /** | |
641 * ExitAction constructor | |
642 */ | |
643 public this() { | |
644 super("E&xit@Alt+F4"); | |
645 setToolTipText("Exit"); | |
646 } | |
647 | |
648 /** | |
649 * Exits the application | |
650 */ | |
651 public void run() { | |
652 Librarian.getApp().close(); | |
653 } | |
654 } | |
655 | |
656 /** | |
657 * This action class shows an About box | |
658 */ | |
659 public class AboutAction : Action { | |
660 /** | |
661 * AboutAction constructor | |
662 */ | |
663 public this() { | |
664 super("&About@Ctrl+A", ImageDescriptor.createFromFile(getImportData!("jface.librarian.about.gif"))); | |
665 setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledAbout.gif"))); | |
666 setToolTipText("About"); | |
667 } | |
668 | |
669 /** | |
670 * Shows an about box | |
671 */ | |
672 public void run() { | |
673 MessageDialog.openInformation(Librarian.getApp().getShell(), "About", | |
674 "Librarian--to manage your books"); | |
675 } | |
676 } | |
677 | |
678 | |
679 | |
680 /** | |
681 * This action class determines whether to show the book count | |
682 */ | |
683 public class ShowBookCountAction : Action { | |
684 public this() { | |
685 super("&Show Book Count@Ctrl+C", IAction.AS_CHECK_BOX); | |
686 setChecked(true); | |
687 setImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.count.gif"))); | |
688 setDisabledImageDescriptor(ImageDescriptor.createFromFile(getImportData!("jface.librarian.disabledCount.gif"))); | |
689 } | |
690 } | |
691 | |
692 /** | |
693 * This class represents a book | |
694 */ | |
695 public class Book { | |
696 private String title; | |
697 private String checkedOutTo; | |
698 | |
699 /** | |
700 * Book constructor | |
701 * @param title the title | |
702 */ | |
703 public this(String title) { | |
704 setTitle(title); | |
705 } | |
706 | |
707 /** | |
708 * Sets the title | |
709 * @param title the title | |
710 */ | |
711 public void setTitle(String title) { | |
712 this.title = title; | |
713 } | |
714 | |
715 /** | |
716 * Gets the title | |
717 * @return String | |
718 */ | |
719 public String getTitle() { | |
720 return title; | |
721 } | |
722 | |
723 /** | |
724 * Check out | |
725 * @param who the person checking this book out | |
726 */ | |
727 public void checkOut(String who) { | |
728 checkedOutTo = who; | |
729 if (checkedOutTo.length is 0) checkedOutTo = null; | |
730 } | |
731 | |
732 public bool isCheckedOut() { | |
733 return checkedOutTo !is null && checkedOutTo.length > 0; | |
734 } | |
735 | |
736 public void checkIn() { | |
737 checkedOutTo = null; | |
738 } | |
739 | |
740 /** | |
741 * Gets who this book is checked out to | |
742 * @return String | |
743 */ | |
744 public String getCheckedOutTo() { | |
745 return checkedOutTo; | |
746 } | |
747 } | |
748 | |
749 | |
750 /** | |
751 * This class provides a facade for the "save" | |
752 * FileDialog class. If the selected file already | |
753 * exists, the user is asked to confirm before | |
754 * overwriting. | |
755 */ | |
756 public class SafeSaveDialog | |
757 { | |
758 // The wrapped FileDialog | |
759 private FileDialog dlg; | |
760 | |
761 /** | |
762 * SafeSaveDialog constructor | |
763 * @param shell the parent shell | |
764 */ | |
765 public this(Shell shell) | |
766 { | |
767 dlg = new FileDialog(shell, DWT.SAVE); | |
768 } | |
769 | |
770 public String open() | |
771 { | |
772 // We store the selected file name in fileName | |
773 String fileName = null; | |
774 | |
775 // The user has finished when one of the | |
776 // following happens: | |
777 // 1) The user dismisses the dialog by pressing Cancel | |
778 // 2) The selected file name does not exist | |
779 // 3) The user agrees to overwrite existing file | |
780 bool done = false; | |
781 | |
782 while (!done) | |
783 { | |
784 // Open the File Dialog | |
785 fileName = dlg.open(); | |
786 if (fileName is null) | |
787 { | |
788 // User has cancelled, so quit and return | |
789 done = true; | |
790 } | |
791 else | |
792 { | |
793 // User has selected a file; see if it already exists | |
794 FilePath file = new FilePath(fileName); | |
795 if (file.exists()) | |
796 { | |
797 // The file already exists; asks for confirmation | |
798 MessageBox mb = new MessageBox(dlg.getParent(), | |
799 DWT.ICON_WARNING | DWT.YES | DWT.NO); | |
800 | |
801 // We really should read this string from a | |
802 // resource bundle | |
803 mb.setMessage(fileName ~ " already exists. Do you want to replace it?"); | |
804 | |
805 // If they click Yes, we're done and we drop out. If | |
806 // they click No, we redisplay the File Dialog | |
807 done = mb.open() is DWT.YES; | |
808 } | |
809 else | |
810 { | |
811 // File does not exist, so drop out | |
812 done = true; | |
813 } | |
814 } | |
815 } | |
816 return fileName; | |
817 } | |
818 | |
819 public String getFileName() | |
820 { | |
821 return dlg.getFileName(); | |
822 } | |
823 | |
824 public String[] getFileNames() | |
825 { | |
826 return dlg.getFileNames(); | |
827 } | |
828 | |
829 public String[] getFilterExtensions() | |
830 { | |
831 return dlg.getFilterExtensions(); | |
832 } | |
833 | |
834 public String[] getFilterNames() | |
835 { | |
836 return dlg.getFilterNames(); | |
837 } | |
838 | |
839 public String getFilterPath() | |
840 { | |
841 return dlg.getFilterPath(); | |
842 } | |
843 | |
844 public void setFileName(String string) | |
845 { | |
846 dlg.setFileName(string); | |
847 } | |
848 | |
849 public void setFilterExtensions(String[] extensions) | |
850 { | |
851 dlg.setFilterExtensions(extensions); | |
852 } | |
853 | |
854 public void setFilterNames(String[] names) | |
855 { | |
856 dlg.setFilterNames(names); | |
857 } | |
858 | |
859 public void setFilterPath(String string) | |
860 { | |
861 dlg.setFilterPath(string); | |
862 } | |
863 | |
864 public Shell getParent() | |
865 { | |
866 return dlg.getParent(); | |
867 } | |
868 | |
869 public int getStyle() | |
870 { | |
871 return dlg.getStyle(); | |
872 } | |
873 | |
874 public String getText() | |
875 { | |
876 return dlg.getText(); | |
877 } | |
878 | |
879 public void setText(String string) | |
880 { | |
881 dlg.setText(string); | |
882 } | |
883 } | |
884 | |
885 | |
886 /** | |
887 * This class is the cell modifier for the Librarian program | |
888 */ | |
889 public class LibraryCellModifier : ICellModifier { | |
890 /** | |
891 * Gets whether the specified property can be modified | |
892 * | |
893 * @param element the book | |
894 * @param property the property | |
895 * @return bool | |
896 */ | |
897 public bool canModify(Object element, String property) { | |
898 return true; | |
899 } | |
900 | |
901 /** | |
902 * Gets the value for the property | |
903 * | |
904 * @param element the book | |
905 * @param property the property | |
906 * @return Object | |
907 */ | |
908 public Object getValue(Object element, String property) { | |
909 Book book = cast(Book) element; | |
910 if (Librarian.TITLE.equals(property)) | |
911 return stringcast(book.getTitle()); | |
912 else if (Librarian.CHECKED_OUT.equals(property)) | |
913 return Boolean.valueOf(book.isCheckedOut()); | |
914 else if (Librarian.WHO.equals(property)) | |
915 return stringcast( book.getCheckedOutTo() is null ? "" : book.getCheckedOutTo()); | |
916 else | |
917 return null; | |
918 } | |
919 | |
920 /** | |
921 * Modifies the element | |
922 * | |
923 * @param element the book | |
924 * @param property the property | |
925 * @param value the new value | |
926 */ | |
927 public void modify(Object element, String property, Object value) { | |
928 if ( auto item = cast(Item)element ){ | |
929 element = item.getData(); | |
930 } | |
931 | |
932 Book book = cast(Book) element; | |
933 if (Librarian.TITLE.equals(property)) | |
934 book.setTitle(stringcast(value)); | |
935 else if (Librarian.CHECKED_OUT.equals(property)) { | |
936 bool b = (cast(Boolean) value).booleanValue(); | |
937 if (b) | |
938 book.checkOut("[Enter Name]"); | |
939 else | |
940 book.checkIn(); | |
941 } else if (Librarian.WHO.equals(property)) | |
942 book.checkOut(stringcast(value)); | |
943 | |
944 // Refresh the view | |
945 Librarian.getApp().refreshView(); | |
946 | |
947 // Set the library dirty | |
948 Librarian.getApp().setLibraryDirty(); | |
949 } | |
950 } | |
951 | |
952 /** | |
953 * This class holds all the books in a library. It also handles loading from and | |
954 * saving to disk | |
955 */ | |
956 public class Library { | |
957 private static const String SEP = "|"; | |
958 | |
959 // The filename | |
960 private String filename; | |
961 | |
962 // The books | |
963 private LinkSeq!(Book) books; | |
964 | |
965 // The dirty flag | |
966 private bool dirty; | |
967 | |
968 /** | |
969 * Library constructor Note the signature :-) | |
970 */ | |
971 public this() { | |
972 books = new LinkSeq!(Book); | |
973 } | |
974 | |
975 /** | |
976 * Loads the library from a file | |
977 * | |
978 * @param filename the filename | |
979 * @throws IOException | |
980 */ | |
981 public void load(String filename) { | |
982 auto istr = (new FileInput(filename)).input; | |
983 auto lines = new LineIterator!(char)(istr); | |
984 String line; | |
985 foreach (line; lines ) { | |
986 auto tokens = tango.text.Util.delimit(line, SEP); | |
987 Book book = null; | |
988 if ( tokens.length > 0 ) book = new Book( tokens[0].dup ); | |
989 if (tokens.length > 1) book.checkOut(tokens[1].dup ); | |
990 if (book !is null) add(book); | |
991 } | |
992 istr.close(); | |
993 this.filename = filename; | |
994 dirty = false; | |
995 } | |
996 | |
997 /** | |
998 * Saves the library to a file | |
999 * | |
1000 * @param filename the filename | |
1001 * @throws IOException | |
1002 */ | |
1003 public void save(String filename) { | |
1004 scope ostr = (new FileOutput(filename)).output; | |
1005 scope printer = new Print!(char)( Format, ostr ); | |
1006 foreach ( book; books ) { | |
1007 printer.formatln( "{}|{}",book.getTitle(), (book.getCheckedOutTo() is null ? "" : book.getCheckedOutTo())); | |
1008 } | |
1009 ostr.close(); | |
1010 this.filename = filename; | |
1011 dirty = false; | |
1012 } | |
1013 | |
1014 /** | |
1015 * Adds a book | |
1016 * | |
1017 * @param book the book to add | |
1018 * @return bool | |
1019 */ | |
1020 public bool add(Book book) { | |
1021 books.append(book); | |
1022 setDirty(); | |
1023 return true; | |
1024 } | |
1025 | |
1026 /** | |
1027 * Removes a book | |
1028 * | |
1029 * @param book the book to remove | |
1030 */ | |
1031 public void remove(Book book) { | |
1032 books.remove(book); | |
1033 setDirty(); | |
1034 } | |
1035 | |
1036 /** | |
1037 * Gets the books | |
1038 * | |
1039 * @return Collection | |
1040 */ | |
1041 public LinkSeq!(Book) getBooks() { | |
1042 return books; | |
1043 } | |
1044 | |
1045 /** | |
1046 * Gets the file name | |
1047 * | |
1048 * @return String | |
1049 */ | |
1050 public String getFileName() { | |
1051 return filename; | |
1052 } | |
1053 | |
1054 /** | |
1055 * Gets whether this file is dirty | |
1056 * | |
1057 * @return bool | |
1058 */ | |
1059 public bool isDirty() { | |
1060 return dirty; | |
1061 } | |
1062 | |
1063 /** | |
1064 * Sets this file as dirty | |
1065 */ | |
1066 public void setDirty() { | |
1067 dirty = true; | |
1068 } | |
1069 } | |
1070 | |
1071 | |
1072 /** | |
1073 * This class provides the content for the library table | |
1074 */ | |
1075 public class LibraryContentProvider : IStructuredContentProvider { | |
1076 /** | |
1077 * Gets the books | |
1078 * | |
1079 * @param inputElement the library | |
1080 * @return Object[] | |
1081 */ | |
1082 public Object[] getElements(Object inputElement) { | |
1083 return (cast(Library) inputElement).getBooks().toArray(); | |
1084 } | |
1085 | |
1086 /** | |
1087 * Disposes any resources | |
1088 */ | |
1089 public void dispose() { | |
1090 // Do nothing | |
1091 } | |
1092 | |
1093 /** | |
1094 * Called when the input changes | |
1095 * | |
1096 * @param viewer the viewer | |
1097 * @param oldInput the old library | |
1098 * @param newInput the new library | |
1099 */ | |
1100 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { | |
1101 // Ignore | |
1102 } | |
1103 } | |
1104 | |
1105 | |
1106 /** | |
1107 * This class provides the labels for the library table | |
1108 */ | |
1109 public class LibraryLabelProvider : ITableLabelProvider { | |
1110 private Image checked; | |
1111 private Image unchecked; | |
1112 | |
1113 /** | |
1114 * LibraryLabelProvider constructor | |
1115 */ | |
1116 public this() { | |
1117 // Create the check mark images | |
1118 checked = new Image(null, new ImageData( new ByteArrayInputStream( cast(byte[])import("jface.librarian.checked.gif")))); | |
1119 unchecked = new Image(null,new ImageData( new ByteArrayInputStream( cast(byte[])import("jface.librarian.unchecked.gif")))); | |
1120 } | |
1121 | |
1122 /** | |
1123 * Gets the column image | |
1124 * | |
1125 * @param element the book | |
1126 * @param columnIndex the column index | |
1127 * @return Image | |
1128 */ | |
1129 public Image getColumnImage(Object element, int columnIndex) { | |
1130 // For the "Checked Out" column, return the check mark | |
1131 // if the book is checked out | |
1132 if (columnIndex is 1) | |
1133 return (cast(Book) element).isCheckedOut() ? checked : unchecked; | |
1134 return null; | |
1135 } | |
1136 | |
1137 /** | |
1138 * Gets the column text | |
1139 * | |
1140 * @param element the book | |
1141 * @param columnIndex the column index | |
1142 * @return String | |
1143 */ | |
1144 public String getColumnText(Object element, int columnIndex) { | |
1145 Book book = cast(Book) element; | |
1146 String text = null; | |
1147 switch (columnIndex) { | |
1148 case 0: | |
1149 text = book.getTitle(); | |
1150 break; | |
1151 case 2: | |
1152 text = book.getCheckedOutTo(); | |
1153 break; | |
1154 default: | |
1155 } | |
1156 return text is null ? "" : text; | |
1157 } | |
1158 | |
1159 /** | |
1160 * Adds a listener | |
1161 */ | |
1162 public void addListener(ILabelProviderListener listener) { | |
1163 // Ignore | |
1164 } | |
1165 | |
1166 /** | |
1167 * Disposes any resources | |
1168 */ | |
1169 public void dispose() { | |
1170 if (checked !is null) checked.dispose(); | |
1171 if (unchecked !is null) unchecked.dispose(); | |
1172 } | |
1173 | |
1174 /** | |
1175 * Gets whether this is a label property | |
1176 * | |
1177 * @param element the book | |
1178 * @param property the property | |
1179 * @return bool | |
1180 */ | |
1181 public bool isLabelProperty(Object element, String property) { | |
1182 return false; | |
1183 } | |
1184 | |
1185 /** | |
1186 * Removes a listener | |
1187 * | |
1188 * @param listener the listener | |
1189 */ | |
1190 public void removeListener(ILabelProviderListener listener) { | |
1191 // Ignore | |
1192 } | |
1193 } | |
1194 | |
1195 | |
1196 | |
1197 | |
1198 | |
1199 |