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