1 /***
2 * Created by IntelliJ IDEA.
3 * User: Lennart
4 * Date: 26-aug-2003
5 * Time: 14:54:33
6 */
7 package comics.gui;
8
9 import comics.gui.progressbars.DefaultProgressBar;
10
11 import javax.swing.*;
12 import java.awt.*;
13 import java.awt.event.*;
14 import java.io.File;
15 import java.io.InputStream;
16 import java.io.IOException;
17 import java.util.*;
18
19 /*
20 * CVS information:
21 *
22 * $Revision: 1.5 $
23 * $Date: 2003/12/13 16:54:53 $
24 */
25
26 /***
27 * This class embodies a JPanel one can use to draw a picture in.
28 *
29 * @author Lennart Martens
30 */
31 public class PicturePanel extends JPanel {
32
33 /***
34 * This JLabel will hold the picture.
35 */
36 private JLabel lblPicture = null;
37
38 /***
39 * Contains the currently displayed image.
40 */
41 private ImageIcon imgPicture = null;
42
43 /***
44 * The label with the caption for the picture.
45 */
46 private JLabel lblCaption = null;
47
48 /***
49 * The parent folder for all the comics.
50 */
51 private String iParentFolder = null;
52
53 /***
54 * The Vector with all the files for the comic.
55 */
56 private Vector allFiles = new Vector();
57
58 /***
59 * This HashMap contains all the available comics.
60 */
61 private HashMap comics = null;
62
63 /***
64 * The index of the comic file in the 'allFiles' Vector,
65 * that is currently on view.
66 */
67 private int index = 0;
68
69 /***
70 * The progressbar, if desired.
71 */
72 private DefaultProgressBar progress = null;
73
74 /***
75 * A dummy frame for the progressbar.
76 */
77 private JFrame progressFrame = null;
78
79 /***
80 * The combobox with all the available comics.
81 */
82 private JComboBox cmbComics = new JComboBox();
83
84 /***
85 * This JButton selects the comic currently in the
86 * cmbComics for display.
87 */
88 private JButton btnSelectComic = new JButton("Select");
89
90 /***
91 * This JCheckbox allows automatic frame size changes whenever the comic does not fit the current
92 * screen.
93 */
94 private JCheckBox chkAutoResize = new JCheckBox("Adjust screen size to comic");
95
96 /***
97 * The button to navigate to the first comic.
98 */
99 private JButton first = new JButton("First");
100 /***
101 * The button to navigate to the last comic.
102 */
103 private JButton last = new JButton("Last");
104 /***
105 * The button to navigate to the next comic.
106 */
107 private JButton next = new JButton("Next");
108 /***
109 * The button to navigate to the previous comic.
110 */
111 private JButton previous = new JButton("Previous");
112 /***
113 * The button to navigate to a random comic.
114 */
115 private JButton random = new JButton("Random");
116
117 /***
118 * This button allows the selection of a parent folder.
119 */
120 private JButton chooseFolder = new JButton("Choose parent folder...");
121
122 /***
123 * This variable shows whether or not a comic was selected already.
124 */
125 private boolean somethingSelected = false;
126
127 /***
128 * Reference to the parent frame so that we might call resize on it when its initialized.
129 */
130 private JFrame iParentFrame = null;
131
132 /***
133 * This variable caches the maximum height of the display which is used when
134 * auto-adjusting window size to fit comic. If the window size has to be adjusted outside of
135 * max height or width, no resizing is done.
136 */
137 private int iMaxHeight = 0;
138
139 /***
140 * This variable caches the maximum width of the display which is used when
141 * auto-adjusting window size to fit comic. If the window size has to be adjusted outside of
142 * max height or width, no resizing is done.
143 */
144 private int iMaxWidth = 0;
145
146 /***
147 * The properties file to convert ucomics comic designations
148 * into full names.
149 */
150 private static Properties conversion = null;
151
152 /***
153 * This constructor takes care of creating the GUI.
154 */
155 public PicturePanel() {
156 JPanel comp = new JPanel(new BorderLayout(0, 5));
157
158 lblPicture = new JLabel();
159 lblPicture.setToolTipText("Click left button to enlarge, right button to shrink.");
160 lblPicture.addMouseListener(new MouseAdapter() {
161 /***
162 * Invoked when a mouse button has been pressed on a component.
163 */
164 public void mousePressed(MouseEvent e) {
165 if(e.getButton() == MouseEvent.BUTTON2 || e.getButton() == MouseEvent.BUTTON3) {
166 rescalePicture(-1.5);
167 } else {
168 rescalePicture(1.5);
169 }
170 }
171 });
172 lblPicture.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
173 lblPicture.setHorizontalAlignment(JLabel.CENTER);
174 lblPicture.setVerticalAlignment(JLabel.CENTER);
175 lblPicture.setVerticalTextPosition(JLabel.CENTER);
176 lblPicture.setHorizontalTextPosition(JLabel.CENTER);
177 comp.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLoweredBevelBorder(), BorderFactory.createEmptyBorder(5,5,5,5)));
178
179 lblCaption = new JLabel();
180 lblCaption.setHorizontalAlignment(JLabel.CENTER);
181 lblCaption.setHorizontalTextPosition(JLabel.CENTER);
182
183 comp.add(new JScrollPane(lblPicture), BorderLayout.CENTER);
184 comp.add(lblCaption, BorderLayout.SOUTH);
185
186 JPanel jpanIntermediate = new JPanel();
187 jpanIntermediate.add(cmbComics);
188 btnSelectComic.setMnemonic(KeyEvent.VK_S);
189 btnSelectComic.addActionListener(new ActionListener() {
190 public void actionPerformed(ActionEvent e) {
191 String key = (String)cmbComics.getSelectedItem();
192 String name = (String)comics.get(key);
193 somethingSelected = true;
194 setRootFolder(iParentFolder + name);
195 }
196 });
197 jpanIntermediate.add(btnSelectComic);
198 chkAutoResize.setSelected(true);
199 jpanIntermediate.add(chkAutoResize);
200
201
202 this.setLayout(new BorderLayout(0, 10));
203 this.add(this.getButtons(), BorderLayout.SOUTH);
204 this.add(comp, BorderLayout.CENTER);
205 this.add(jpanIntermediate, BorderLayout.NORTH);
206
207
208 // Load the conversion properties file.
209 try {
210 if(conversion == null) {
211 conversion = new Properties();
212 InputStream is = this.getClass().getClassLoader().getResourceAsStream("comics.properties");
213 if(is != null) {
214 conversion.load(is);
215 String folder = conversion.getProperty("rootfolder");
216 File test = new File(folder);
217 if(!test.exists()) {
218 throw new IOException("Unable to find specified folder!");
219 }
220 this.setParentFolder(folder);
221 is.close();
222 }
223 }
224 } catch(Exception e) {
225 // Let the user select the parent folder manually.
226 selectParentFolder();
227 if(iParentFolder == null) {
228 System.exit(0);
229 }
230 }
231 }
232
233 /***
234 * This constructor creates the GUI and keeps a reference to the parent frame which wan be used for resizing.
235 *
236 * @param aParent JFrame with the parent frame.
237 */
238 public PicturePanel(JFrame aParent) {
239 this();
240 this.iParentFrame = aParent;
241 // Also record the screen boundaries here.
242 Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
243 this.iMaxHeight = screensize.height;
244 this.iMaxWidth = screensize.width;
245 }
246
247 /***
248 * This method allows the setting of a new picture on the panel.
249 *
250 * @param aFilename String with the filename for the picture to load.
251 */
252 public void setPicture(String aFilename) {
253 this.imgPicture = new ImageIcon(aFilename, aFilename);
254 // See if we should check for resizing.
255 if(chkAutoResize.isSelected()){
256 // Do the resize if necessary.
257 boolean resizeNecessary = false;
258 int height = 0;
259 int width = 0;
260 if(imgPicture.getIconHeight()+40 > lblPicture.getHeight()) {
261 resizeNecessary = true;
262 height = (imgPicture.getIconHeight()+40) - lblPicture.getHeight();
263 }
264 if(imgPicture.getIconWidth()+40 > lblPicture.getWidth()) {
265 resizeNecessary = true;
266 width = (imgPicture.getIconWidth()+40) - lblPicture.getWidth();
267 }
268 // Resize? And if so, do we have a the reference to the parent frame to resize it?
269 if(resizeNecessary && iParentFrame != null) {
270 int newHeight = iParentFrame.getHeight()+height;
271 int newWidth = iParentFrame.getWidth()+width;
272 // See if we are within screen limits.
273 if(newHeight < this.iMaxHeight && newWidth < this.iMaxWidth) {
274 iParentFrame.setSize(newWidth, newHeight);
275 }
276 }
277 }
278 lblPicture.setIcon(imgPicture);
279 lblCaption.setText(aFilename);
280 }
281
282 /***
283 * This method allows the setting of a new picture on the panel.
284 *
285 * @param aFilename File with the filename for the picture to load.
286 */
287 public void setPicture(File aFilename) {
288 try {
289 this.setPicture(aFilename.getCanonicalPath());
290 } catch(Exception e) {
291 e.printStackTrace();
292 }
293 }
294
295 /***
296 * This method will rescale the picture according to the multiplication
297 * specified. If this is a negative multiplication, it will be converted into the
298 * (-1/x) form. EG., -4 becomes (-1/-4) = 0.25.
299 *
300 * @param times double with the scaling factor (if negative, becomes (-1/x) - see above.
301 */
302 public void rescalePicture(double times) {
303 if(!checkSelected()) {
304 return;
305 }
306 if(times < 0) {
307 times = -1.0/times;
308 }
309 Image image = this.imgPicture.getImage();
310 int width = image.getWidth(null);
311 int height = image.getHeight(null);
312 image = image.getScaledInstance((int)(width*times), (int)(height*times), Image.SCALE_SMOOTH);
313 imgPicture = new ImageIcon(image, imgPicture.getDescription());
314 lblPicture.setIcon(imgPicture);
315 }
316
317
318 /***
319 * This method takes a root path from which all pictures are read, and each of these can be displayed.
320 *
321 * @param aFolder String with the path for the root folder.
322 */
323 public void setRootFolder(String aFolder) {
324 this.allFiles = new Vector();
325 File root = new File(aFolder);
326 addContents(root);
327 // Sort.
328 Collections.sort(allFiles);
329 index = 0;
330 if(somethingSelected) {
331 this.setPicture((File)allFiles.get(index));
332 previous.setEnabled(false);
333 }
334 }
335
336 /***
337 * This method allows the setting of the parent folder for all the comics.
338 *
339 * @param aFolder String with the parent folder (the one above all the comments).
340 */
341 public void setParentFolder(String aFolder) {
342 comics = new HashMap();
343 this.iParentFolder = aFolder.trim();
344 if(!iParentFolder.endsWith("//") || !iParentFolder.endsWith("/")) {
345 iParentFolder += "/";
346 }
347 File[] files = new File(aFolder).listFiles();
348 for(int i = 0; i < files.length; i++) {
349 File lFile = files[i];
350 if(lFile.isDirectory()) {
351 String name = lFile.getName().trim();
352 String key = name;
353 if(conversion.containsKey(name)) {
354 key = conversion.getProperty(name);
355 }
356 this.comics.put(key, name);
357 }
358 }
359 Object[] names = comics.keySet().toArray();
360 Arrays.sort(names);
361 cmbComics.setModel(new DefaultComboBoxModel(names));
362 }
363
364 /***
365 * Main method is for testing purposes.
366 *
367 * @param args String[] with the start-up arguments.
368 */
369 public static void main(String[] args) {
370
371 final JFrame tc = new JFrame("Comics!");
372 tc.addWindowListener(new WindowAdapter() {
373 /***
374 * Invoked when a window is in the process of being closed.
375 * The close operation can be overridden at this point.
376 */
377 public void windowClosing(WindowEvent e) {
378 tc.dispose();
379 System.exit(0);
380 }
381 });
382 PicturePanel pp = new PicturePanel(tc);
383 tc.getContentPane().add(pp, BorderLayout.CENTER);
384 tc.setBounds(300, 300, 800, 400);
385 tc.setVisible(true);
386 }
387
388 /***
389 * This method recurses through the parent directory and reads all the gif, jpeg and jpg
390 * files into a Vector.
391 *
392 * @param aFolder File with the root folder to recurse from.
393 */
394 private void addContents(File aFolder) {
395 File[] list = aFolder.listFiles();
396 progressFrame = new JFrame();
397 progress = new DefaultProgressBar(progressFrame, "Loading comics", 0, list.length, "Loading from '" + aFolder.getName() + "'...");
398 InnerRecursion ir = new InnerRecursion(list, progress);
399 progress.setSize(300, progress.getPreferredSize().height);
400 Thread t = new Thread(ir);
401 t.start();
402 progress.setVisible(true);
403 progressFrame.dispose();
404 // verify that we have found something.
405 // Otherwise signal the lack of selection via the somethingSelected boolean.
406 if(allFiles.size() == 0) {
407 JOptionPane.showMessageDialog(this, "No graphics files (.gif, .jpg or .jpeg) found in the specified path!", "No graphics files found!", JOptionPane.WARNING_MESSAGE);
408 somethingSelected = false;
409 }
410 }
411
412 /***
413 * This methods generates the button panel for the application.
414 *
415 * @return JPanel with the buttons.
416 */
417 private JPanel getButtons() {
418 // The buttonpanel.
419 JPanel jpanButtons = new JPanel();
420 jpanButtons.setLayout(new BoxLayout(jpanButtons, BoxLayout.X_AXIS));
421
422 // First button.
423 first.setMnemonic(KeyEvent.VK_F);
424 first.addActionListener(new ActionListener() {
425 public void actionPerformed(ActionEvent e) {
426 if(!checkSelected()) {
427 return;
428 }
429 index = 0;
430 setPicture((File)allFiles.get(index));
431 previous.setEnabled(false);
432 if(!next.isEnabled()) {
433 next.setEnabled(true);
434 }
435 }
436 });
437
438 // Last button.
439 last.setMnemonic(KeyEvent.VK_L);
440 last.addActionListener(new ActionListener() {
441 public void actionPerformed(ActionEvent e) {
442 if(!checkSelected()) {
443 return;
444 }
445 index = allFiles.size()-1;
446 setPicture((File)allFiles.get(index));
447 next.setEnabled(false);
448 if(!previous.isEnabled()) {
449 previous.setEnabled(true);
450 }
451 }
452 });
453
454 // Random button.
455 random.setMnemonic(KeyEvent.VK_R);
456 random.addActionListener(new ActionListener() {
457 public void actionPerformed(ActionEvent e) {
458 if(!checkSelected()) {
459 return;
460 }
461 index = (int)(Math.random()*allFiles.size());
462 setPicture((File)allFiles.get(index));
463 if(index > 0 && !previous.isEnabled()) {
464 previous.setEnabled(true);
465 }
466 if (index < allFiles.size()-1 && !next.isEnabled()) {
467 next.setEnabled(true);
468 }
469 }
470 });
471
472 // Next button.
473 next.setMnemonic(KeyEvent.VK_N);
474 next.addActionListener(new ActionListener() {
475 public void actionPerformed(ActionEvent e) {
476 if(!checkSelected()) {
477 return;
478 }
479 if(index < allFiles.size()-1) {
480 index++;
481 setPicture((File)allFiles.get(index));
482 if(!previous.isEnabled()) {
483 previous.setEnabled(true);
484 }
485 } else {
486 next.setEnabled(false);
487 }
488 }
489 });
490
491 // Previous button.
492 previous.setMnemonic(KeyEvent.VK_P);
493 previous.addActionListener(new ActionListener() {
494 public void actionPerformed(ActionEvent e) {
495 if(!checkSelected()) {
496 return;
497 }
498 if(index > 0) {
499 index--;
500 setPicture((File)allFiles.get(index));
501 if(!next.isEnabled()) {
502 next.setEnabled(true);
503 }
504 } else {
505 previous.setEnabled(false);
506 }
507 }
508 });
509
510 // Select parent folder button.
511 chooseFolder.setMnemonic(KeyEvent.VK_C);
512 chooseFolder.addActionListener(new ActionListener() {
513 public void actionPerformed(ActionEvent e) {
514 selectParentFolder();
515 }
516 });
517
518 // Adding the buttons to the panel.
519 jpanButtons.add(Box.createHorizontalStrut(15));
520 jpanButtons.add(chooseFolder);
521 jpanButtons.add(Box.createHorizontalGlue());
522 jpanButtons.add(random);
523 jpanButtons.add(Box.createHorizontalStrut(5));
524 jpanButtons.add(first);
525 jpanButtons.add(Box.createHorizontalStrut(5));
526 jpanButtons.add(previous);
527 jpanButtons.add(Box.createHorizontalStrut(5));
528 jpanButtons.add(next);
529 jpanButtons.add(Box.createHorizontalStrut(5));
530 jpanButtons.add(last);
531 jpanButtons.add(Box.createHorizontalStrut(15));
532
533
534 return jpanButtons;
535 }
536
537 /***
538 * This method returns 'true' when some comic was selected,
539 * and displays a warning message and returns 'false' otherwise.
540 *
541 * @return boolean to indicate whether a comic was selected.
542 */
543 private boolean checkSelected() {
544 if(!somethingSelected) {
545 JOptionPane.showMessageDialog(this, "No comic selected to perform requested operation on!", "No comic selected!", JOptionPane.WARNING_MESSAGE);
546 }
547 return this.somethingSelected ;
548 }
549
550 /***
551 * This method pops up a GUI component (JFileChooser) where the user can select a parent folder.
552 */
553 private void selectParentFolder() {
554 JFileChooser fc = new JFileChooser("/");
555 fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
556 if(fc.showDialog(this, "Select folder") == JFileChooser.CANCEL_OPTION) {
557 return;
558 }
559 File f = fc.getSelectedFile();
560 String parentDir = f.getAbsolutePath();
561 this.setParentFolder(parentDir);
562 }
563
564 /***
565 * Inner class for the recursive reading of the selected comic root folder.
566 */
567 private class InnerRecursion implements Runnable {
568
569 /***
570 * The list of files in the root folder.
571 */
572 private File[] list = null;
573
574 /***
575 * The progressbar.
576 */
577 private DefaultProgressBar progress = null;
578
579 /***
580 * This constructor takes the list of files in the root folder, as
581 * well as a progress bar.
582 *
583 * @param aList File[] with the listing of the root folder.
584 * @param aProgress DefaultProgressBar with the progressbar.
585 */
586 public InnerRecursion(File[] aList, DefaultProgressBar aProgress) {
587 list = aList;
588 progress = aProgress;
589 }
590
591 /***
592 * Run method for the thread.
593 */
594 public void run() {
595 // Cycling through the root folder.
596 for(int i = 0; i < list.length; i++) {
597 // Set the progress and a new message.
598 progress.setValue(i);
599 progress.setMessage("Reading through " + list[i]);
600 // List all files.
601 File item = list[i];
602 // If it's a directory, recurse, if it's a file with the
603 // correct extension, add it to the full list.
604 if(item.isDirectory()) {
605 this.recurse(item);
606 } else if(item.getName().endsWith(".gif") || item.getName().endsWith(".jpg") || item.getName().endsWith(".GIF") || item.getName().endsWith(".JPG") || item.getName().endsWith(".jpeg") || item.getName().endsWith(".JPEG")) {
607 allFiles.add(item);
608 }
609 }
610 // Set progressbar to full length.
611 progress.setValue(progress.getMaximum());
612 }
613
614 /***
615 * This method allows the recursing through the specified directory.
616 *
617 * @param aFile File with the directory to recurse through.
618 */
619 private void recurse(File aFile) {
620 // List all files.
621 File[] lList = aFile.listFiles();
622 // Cycle all the files.
623 // If it's a directory, recurse.
624 // Else if it's a file with the correct extension, add it
625 // to the full list.
626 for(int i = 0; i < lList.length; i++) {
627 File item = lList[i];
628 if(item.isDirectory()) {
629 this.recurse(item);
630 } else if(item.getName().endsWith(".gif") || item.getName().endsWith(".jpg") || item.getName().endsWith(".GIF") || item.getName().endsWith(".JPG") || item.getName().endsWith(".jpeg") || item.getName().endsWith(".JPEG")) {
631 allFiles.add(item);
632 }
633 }
634 }
635 }
636 }
This page was automatically generated by Maven