From 221e85d1612fb065ceaf2cb7757e235b7681990f Mon Sep 17 00:00:00 2001 From: _N0x Date: Tue, 16 Feb 2021 13:14:55 +0100 Subject: [PATCH] Cleanup, better error handling, better code structure, added some icons, added "about" information --- PhotoViewer.iml | 2 +- {pic => demoPics}/image1.jpg | Bin {pic => demoPics}/image2.jpg | Bin {pic => demoPics}/image3.jpg | Bin icons/left-arrow.png | Bin 0 -> 2646 bytes icons/right-arrow.png | Bin 0 -> 9087 bytes .../{Controller.java => PVController.java} | 218 ++++++++++++------ .../thm/tlf/photoViewer/PictureHandler.java | 21 +- 8 files changed, 173 insertions(+), 68 deletions(-) rename {pic => demoPics}/image1.jpg (100%) rename {pic => demoPics}/image2.jpg (100%) rename {pic => demoPics}/image3.jpg (100%) create mode 100644 icons/left-arrow.png create mode 100644 icons/right-arrow.png rename src/de/thm/tlf/photoViewer/{Controller.java => PVController.java} (67%) diff --git a/PhotoViewer.iml b/PhotoViewer.iml index b8db988..c769145 100644 --- a/PhotoViewer.iml +++ b/PhotoViewer.iml @@ -7,6 +7,6 @@ - + \ No newline at end of file diff --git a/pic/image1.jpg b/demoPics/image1.jpg similarity index 100% rename from pic/image1.jpg rename to demoPics/image1.jpg diff --git a/pic/image2.jpg b/demoPics/image2.jpg similarity index 100% rename from pic/image2.jpg rename to demoPics/image2.jpg diff --git a/pic/image3.jpg b/demoPics/image3.jpg similarity index 100% rename from pic/image3.jpg rename to demoPics/image3.jpg diff --git a/icons/left-arrow.png b/icons/left-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..d9315870250701333c7d0357183ba18e6b15e39f GIT binary patch literal 2646 zcmeHJX;4#V6n%LlWr?`9K~cmi6cs|T$ReOYhgDe=a6!OG(L^OcAb|&heNm~3ir^sP z22rUSB0*LSB2imWEK5{~hzThmCJ=&1V$hiP`e-|j&Nx$B{nx&k@0|PHbLYF~-d`_c zd4RXEk*N^?0LH#P9zg&AVj&0^=wWp0ti>IS^jJ%LLktWII(`e3Vpl_^Pbdoj#?nU* zE-Pb4JeHio_FTgbj-#=m$b^jm1VOf&W20G7k<5*@aS8O}N;gyNRs3?l5Kk0EvHJhN z|MCV7MmC3F^Iv2K1q1^)P!CV|Lf^oUIA-j)@e?L~`4wr3>2&iMUt3sO&7L#Y+J^k? zdbAg{)k)CUk9Bcmy?aBaOZ(nh_J1z+ywmTT?kZ(s%9N zv;RO=&Y|4AW5)})Cr_O@cfROi@ud=8>E*JD%Bt!sSNS#9>jbxcx!rKDu|;_Q!NWGu zqxQ#7q+Q)TPkW!q^d9FqKaK&*vC zdeiEMZWkXsv}~{KcRh|dTFZ1hQMk2c*{M6dZA)YCl4t(BVQ$_-ni{dvH7scDJ>fv* zin`S%ifh~~R#MZ;S3gjK&pw*BuD;8=Aho-2a2K?#EWWYmjJ=t~7W=#sZ6$JDs8PCh zga$c61DnifVYbk*^!yC9G8xQ(eSG8L6eWYjEIc?WAl8m!m@PKWVIH)KYMAouSWQp!-%B zy#GOo>R{JO&e5)}RU8rOE>2Hqk|BvQQ+^Noi0`hMX}Oi?mhWk}_)2ZSk= zPa+GoB4zLi$E)y4UWb>4hpW$2QuWU+h)Y0=qQy>pxK=6<>iVNi4q)jM&U`qRm-DNV zidY^I*O6RVY?R-ak3FFtYbLIPstwRz3@8#Lw#{W3(oJ<4078OnZ+Amb-X z;N2{54ey-Tl@F)n`6Qu`nHwLDkaY=l+Hf~MDg&(omDDWP6gKK#Uz3u64lJ5%DuxH$ zoC1{;MP*mJj+eyJ`NI!7RZjnsL{wO({&e{F21bp44hPsA;_y$|gwuO2DD>Lb-aL8; z+SAxk2*04Eoq<)7Hpa2Agt8|4>AtH?KEP+*rW!&0ItaKX>5!U#jiiM}(msN6Z zEk%_jVe87BsHh^bpIdue)hxM`gOfh9-5uMi_G{pABJdS`{Jk7m{#v{TFD9L%7&w1- zBC{l_x@(mQPFPc7ut!o636@n~#saaYyDDJ%%o(W~OzMAgn4=(DgQrE;GqGUgM~)&Q zC7YvIxE#M>&=V{Z4Y}a(_1h4u8$-?H=qxL6Wlz&Wkf)J$~{( zBL8a~^}Ai|=4iLSZE6!NNc(eF#hz^eZ@c~NER$@cHr~yo=koa&wupLV?cj9QFlo~B zJ`3WN8;#|JF$F!nST5-W1D8s3PO0Lov@Ia7@05??(VcXn3>swM>H-rnTHi+E02+-Y4l7|Y1@iILfSmBe-1%W z(0}?a=#~0p7@jT7HPmDBqP>V~BJUF7zb(puvB*x zY|AW1jjFfw9td+Ncry#)heSd5ka=2^eZk%#dEa&OLX^I4Qiq~(tGs2!3-jdr%f6pl zH!N`pLUu;eTmx^~rl6&-v?eb84YbbTraP3r!TuWEe0s)Xm8JEnxRGRL^0PK4F03kQ cB5CCaDC6Y2O`HZwNB?JhJp(*SmaO0LJI${AQvd(} literal 0 HcmV?d00001 diff --git a/icons/right-arrow.png b/icons/right-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..54443e72949f5a951d20e7f6196aa219d00e66d6 GIT binary patch literal 9087 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 W(}Rm$wI`vP515-+8ecWs74>%+(Z*{4 literal 0 HcmV?d00001 diff --git a/src/de/thm/tlf/photoViewer/Controller.java b/src/de/thm/tlf/photoViewer/PVController.java similarity index 67% rename from src/de/thm/tlf/photoViewer/Controller.java rename to src/de/thm/tlf/photoViewer/PVController.java index 06b5ff5..8177f87 100644 --- a/src/de/thm/tlf/photoViewer/Controller.java +++ b/src/de/thm/tlf/photoViewer/PVController.java @@ -10,10 +10,12 @@ import javafx.concurrent.Task; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; +import javafx.geometry.Orientation; import javafx.geometry.Pos; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.*; +import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -23,6 +25,8 @@ import javafx.stage.FileChooser; import javafx.stage.Stage; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.util.List; /** @@ -31,12 +35,17 @@ import java.util.List; * * @author Tim Lukas Förster * @version 1.0 + * repository: https://gitlab.com/n0x_io/PhotoViewer */ -public class Controller extends Application { +public class PVController extends Application { //////////////////////////// //------ Attributes ------// //////////////////////////// + // Constants // + private static final String ARROWPREV = "icons/left-arrow.png"; + private static final String ARROWNEXT = "icons/right-arrow.png"; + // CENTER // private final ScrollPane currentViewSP = new ScrollPane(); private final ImageView centerImageView = new ImageView(); @@ -46,17 +55,18 @@ public class Controller extends Application { private final MenuBar menuBar = new MenuBar(); private final Menu fileMenu = new Menu("File"); private final Menu aboutMenu = new Menu("About"); - private final MenuItem openFiles = new MenuItem("Open"); - private final MenuItem clearViewer = new Menu("Close all"); - private final MenuItem startSlideShow = new MenuItem("Start Slide Show"); - private final MenuItem exitViewer = new Menu("Exit"); - private final MenuItem showInfo = new Menu("Information"); + private final MenuItem menuItemOpenFiles = new MenuItem("Open"); + private final MenuItem menuItemClearViewer = new Menu("Close all"); + private final MenuItem menuItemStartSlideShow = new MenuItem("Start Slide Show"); + private final MenuItem menuItemExitViewer = new Menu("Exit"); + private final MenuItem menuItemShowInfo = new Menu("Information"); // BOTTOM // private final VBox bottomPanel = new VBox(); - private final HBox selectionPane = new HBox(); - private final ScrollPane pictureSelector = new ScrollPane(); + //private final HBox selectionPane = new HBox(); + private final ListView previewPane = new ListView<>(); + private final VBox pictureSelector = new VBox(); private final BorderPane bottomLowerPanel = new BorderPane(); private final HBox bottomLeft = new HBox(); @@ -77,11 +87,13 @@ public class Controller extends Application { private PictureHandler picHandler; // Etc. // + private Thread slideShowThread; private boolean bIsFullScreen = false; private boolean bSlideShowActive = false; private final DoubleProperty slideShowSpeed = new SimpleDoubleProperty(4); private final DoubleProperty zoomProperty = new SimpleDoubleProperty(200); + // Key Combinations & Shortcuts // private final KeyCombination keyCrtlQ = new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_ANY); //////////////////////////////// //------ End Attributes ------// @@ -116,7 +128,7 @@ public class Controller extends Application { // Create all Actions // createSliderActions(); createMenuActions(primaryStage); - createButtonActions(primaryStage); + createClickActions(primaryStage); // Keypress Actions // mainScene.setOnKeyPressed(event -> { @@ -151,12 +163,11 @@ public class Controller extends Application { primaryStage.show(); } - /** * Task used to run the slideshow in separate Threat. */ @SuppressWarnings("rawtypes") - Task slideShowTask = new Task(){ + private final Task slideShowTask = new Task(){ @Override @SuppressWarnings("BusyWait") protected Void call() throws Exception { @@ -179,10 +190,26 @@ public class Controller extends Application { /** * Event wrapper for clear function - * @return EventHandle executing the clear function + * @return EventHandle executing the clearPreviewView function */ private EventHandler clearPreviewViewEvent(){ - return e -> clearPreviewView(); + return e -> clearViewer(); + } + + /** + * Event wrapper for showAboutDialog function + * @return EventHandle executing the showAboutDialog function + */ + private EventHandler showAboutDialogEvent(){ + return e -> showAboutDialog(); + } + + /** + * Event wrapper for showAboutDialog function + * @return EventHandle executing the showAboutDialog function + */ + private EventHandler toggleSlidesHowEvent(){ + return e -> toggleSlideShow(); } //////////////////////////////// @@ -192,6 +219,7 @@ public class Controller extends Application { * Helper method for handling sliders */ private void createSliderActions() { + //TODO: Zoom kinda wonky... should be redone. // Zoom Action // zoomProperty.addListener(observable -> { centerImageView.setFitWidth(zoomProperty.get() * 4); @@ -217,18 +245,22 @@ public class Controller extends Application { * @param stage the primary stage, used to display the file-open-dialog */ private void createMenuActions(Stage stage) { - openFiles.setOnAction(openFileDialogEvent(stage)); - exitViewer.setOnAction( e -> Platform.exit()); - clearViewer.setOnAction(clearPreviewViewEvent()); + menuItemOpenFiles.setOnAction(openFileDialogEvent(stage)); + menuItemExitViewer.setOnAction(e -> Platform.exit()); + menuItemClearViewer.setOnAction(clearPreviewViewEvent()); + menuItemStartSlideShow.setOnAction(toggleSlidesHowEvent()); + menuItemShowInfo.setOnAction(showAboutDialogEvent()); } /** * Helper method for handling button interaction * @param stage the primary stage, used to display the file-open-dialog and control fullscreen functions */ - private void createButtonActions(Stage stage) { + private void createClickActions(Stage stage) { + // Opens the File dialog openFilesButton.setOnAction(openFileDialogEvent(stage)); + // Displays the previous Picture prevPicBtn.setOnAction(e -> { try{ centerImageView.setImage(picHandler.getPrevPicture().getImage()); @@ -236,6 +268,7 @@ public class Controller extends Application { catch (NoPicturesLoadedException npl){ showNoPicturesLoadedWarning();} }); + // Displays the next picture nextPicBtn.setOnAction(e -> { try{ centerImageView.setImage(picHandler.getNextPicture().getImage()); @@ -243,36 +276,54 @@ public class Controller extends Application { catch (NoPicturesLoadedException npl){ showNoPicturesLoadedWarning();} }); + // Sets the PictureViewer to fullscreen fullScreenBtn.setOnAction(e -> { stage.setFullScreen(!bIsFullScreen); bIsFullScreen ^= true; }); - slideShowBtn.setOnAction(new EventHandler<>() { - Thread th; + //slideShowBtn.setOnAction( }); + + // Starts the slideshow on first click, stops it on the next one + slideShowBtn.setOnAction(toggleSlidesHowEvent()); + + // Clicking on any picture in the Previews opens said picture in the main view + previewPane.setOnMouseClicked(e -> { + try { + centerImageView.setImage(picHandler.getPictureByID(previewPane.getSelectionModel().getSelectedIndex()).getImage()); + } catch (NoPicturesLoadedException ignored) { - @Override - public void handle(ActionEvent actionEvent) { - try { - if (!bSlideShowActive) { - // This statement is to catch any errors regarding no images loaded - centerImageView.setImage(picHandler.getNextPicture().getImage()); - bSlideShowActive = true; - slideShowBtn.setText("Stop Slide Show"); - th = new Thread(slideShowTask); - th.start(); - } else { - bSlideShowActive = false; - slideShowBtn.setText("Slide Show"); - th.interrupt(); - } - } catch (NoPicturesLoadedException npl){ - showNoPicturesLoadedWarning(); - } } }); } + /** + * Method that will start and stop (toggle) the Slide show and set the corresponding texts to all buttons etc. + */ + private void toggleSlideShow(){ + try { + if (!bSlideShowActive) { + // This statement is to catch any errors regarding no images loaded + centerImageView.setImage(picHandler.getNextPicture().getImage()); + bSlideShowActive = true; + slideShowThread = new Thread(slideShowTask); + slideShowThread.start(); + // Change text of slideshow switches + slideShowBtn.setText("Stop Slide Show"); + menuItemStartSlideShow.setText("Stop Slide Show"); + } else { + bSlideShowActive = false; + // Change text of slideshow switches + slideShowBtn.setText("Slide Show"); + menuItemStartSlideShow.setText("Slide Show"); + assert slideShowThread != null; + slideShowThread.interrupt(); + } + } catch (NoPicturesLoadedException npl){ + showNoPicturesLoadedWarning(); + } + } + /** * Open file-dialog allowing to select multiple pictures (via filter), * adds them to the PictureHandler and updates the picture preview @@ -287,7 +338,7 @@ public class Controller extends Application { if (selectedPictures != null) { try { picHandler.loadPictures(selectedPictures); - Controller.this.updatePreviewView(); + PVController.this.updatePreviewView(); centerImageView.setImage(picHandler.getNextPicture().getImage()); } catch (NoPicturesLoadedException npl) { showNoPicturesLoadedWarning(); @@ -299,26 +350,55 @@ public class Controller extends Application { * Method that updates the preview Pane with all PreviewPictures provided by the Picture Handler */ private void updatePreviewView(){ - clearPreviewView(); - selectionPane.setPadding(new Insets(5,5,5,5)); + clearViewer(); + //previewPane.setPadding(new Insets(5,5,5,5)); for(PicturePreview pp: picHandler.getPreviews()){ ImageView iv = new ImageView(pp.getImage()); iv.setFitWidth(150); iv.setSmooth(true); iv.setPreserveRatio(true); - selectionPane.getChildren().add(iv); + previewPane.getItems().add(iv); } } /** - * Used to clear the preview and center panel when the viewer is cleared + * Used to clear the preview and center panel */ - private void clearPreviewView(){ - selectionPane.getChildren().clear(); - selectionPane.setPadding(new Insets(5,155,5,5)); + private void clearViewer(){ + previewPane.getItems().clear(); + //previewPane.setPadding(new Insets(5,5,5,5)); centerImageView.setImage(null); } + /** + * Show a dialogue displaying copyright information about the program. + */ + private void showAboutDialog(){ + Dialog aboutDialog = new Dialog<>(); + aboutDialog.setTitle("About this program"); + ButtonType btnType = new ButtonType("Ok", ButtonBar.ButtonData.OK_DONE); + aboutDialog.setContentText(""" + Created by Tim Lukas Förster + Icons made by www.flaticon.com/authors/roundicons for www.flaticon.com"""); + + + //Adding buttons to the aboutDialog pane + aboutDialog.getDialogPane().getButtonTypes().add(btnType); + } + + /** + * Displays a warning dialogue informing the user that no pictures has been loaded yet + * and the executed action is not possible. + */ + private void showNoPicturesLoadedWarning(){ + Alert alert = new Alert(Alert.AlertType.WARNING); + alert.setTitle("No pictures loaded"); + alert.setContentText("No pictures have been loaded" + + "\nPlease select pictures via the menu or via the open button to view them."); + alert.showAndWait().ifPresent(rs -> { + }); + } + /** * Method that handles the settings and layout of the top Panel * @return Node, set up for displaying on the top of a GridPane @@ -326,9 +406,9 @@ public class Controller extends Application { private Node createTop(){ SeparatorMenuItem sep = new SeparatorMenuItem(); // File Menu - fileMenu.getItems().addAll(openFiles, clearViewer, sep, startSlideShow, exitViewer); + fileMenu.getItems().addAll(menuItemOpenFiles, menuItemClearViewer, sep, menuItemStartSlideShow, menuItemExitViewer); // About Menu - aboutMenu.getItems().addAll(showInfo); + aboutMenu.getItems().addAll(menuItemShowInfo); // Menu bar menuBar.getMenus().addAll(fileMenu, aboutMenu); // Adding Menus to Top Panel @@ -372,11 +452,31 @@ public class Controller extends Application { zoomSlider.setShowTickMarks(true); Label zoomLabel = new Label("Zoom:"); bottomLeft.getChildren().addAll(openFilesButton, zoomLabel, zoomSlider); - //bottomLeft.getChildren().addAll(zoomLabel, zoomSlider); bottomLeft.setSpacing(5); bottomLowerPanel.setLeft(bottomLeft); // Middle Bottom Part + try { + // Set pictures as prev/next buttons + ImageView prevPic = new ImageView(new Image(new FileInputStream(ARROWPREV))); + prevPic.setFitHeight(10); + prevPic.setPreserveRatio(true); + prevPicBtn.setText(null); + prevPicBtn.setGraphic(prevPic); + + ImageView nextPic = new ImageView(new Image(new FileInputStream(ARROWNEXT))); + nextPic.setFitHeight(10); + nextPic.setPreserveRatio(true); + nextPicBtn.setText(null); + nextPicBtn.setGraphic(nextPic); + } catch (FileNotFoundException ignored){ + // fallback to text + prevPicBtn.setGraphic(null); + nextPicBtn.setGraphic(null); + + prevPicBtn.setText("<-"); + nextPicBtn.setText("->"); + } bottomMid.setAlignment(Pos.CENTER); bottomMid.setSpacing(5); bottomMid.getChildren().addAll(prevPicBtn, slideShowBtn, nextPicBtn); @@ -391,28 +491,16 @@ public class Controller extends Application { bottomLowerPanel.setRight(bottomRight); // Bottom upper Part -> Picture preview - selectionPane.setPadding(new Insets(5,5,155,5)); - selectionPane.autosize(); - selectionPane.setSpacing(5); - pictureSelector.setContent(selectionPane); + pictureSelector.setPadding(new Insets(2,2,2,2)); + previewPane.setOrientation(Orientation.HORIZONTAL); + previewPane.setMaxHeight(150); + //selectionPane.setSpacing(5); + pictureSelector.getChildren().add(previewPane); bottomPanel.getChildren().addAll(pictureSelector, bottomLowerPanel); return (bottomPanel); } - - /** - * Displays a warning dialogue informing the user that no pictures has been loaded yet - * and the executed action is not possible. - */ - private void showNoPicturesLoadedWarning(){ - Alert alert = new Alert(Alert.AlertType.WARNING); - alert.setTitle("No pictures loaded"); - alert.setContentText("No pictures have been loaded" + - "\nPlease select pictures via the menu or via the open button to view them."); - alert.showAndWait().ifPresent(rs -> { - }); - } //////////////////////////////////// //------ End Helper-Methods ------// //////////////////////////////////// diff --git a/src/de/thm/tlf/photoViewer/PictureHandler.java b/src/de/thm/tlf/photoViewer/PictureHandler.java index fbf0653..51bac9c 100644 --- a/src/de/thm/tlf/photoViewer/PictureHandler.java +++ b/src/de/thm/tlf/photoViewer/PictureHandler.java @@ -62,7 +62,8 @@ public final class PictureHandler { } /** - * Determines the next picture that should be displayed + * Determines the next picture that should be displayed. + * Wraps around to the beginning of the list if picture after the last one is requested. * @return Picture object that should be displayed next from the ArrayList pictures * @throws NoPicturesLoadedException Exception for when no pictures are loaded yet but tried to access them */ @@ -77,7 +78,8 @@ public final class PictureHandler { } /** - * Determines the previous picture that should be displayed + * Determines the previous picture that should be displayed. + * Wraps around to the end of the list if picture before the first one is requested. * @return Picture object that should be displayed next from the ArrayList pictures * @throws NoPicturesLoadedException Exception for when no pictures are loaded yet but tried to access them */ @@ -90,6 +92,21 @@ public final class PictureHandler { return pictures.get(currentPictureID); } } + + /** + * Method to acquire picture by the list-ID of a picture + * @param pictureID the ID of the Picture that is being requested + * @return Picture from the pictures ArrayList on position of the provided ID + * @throws NoPicturesLoadedException Exception for when no pictures are loaded yet but tried to access them + */ + public Picture getPictureByID(int pictureID) throws NoPicturesLoadedException{ + if(pictures.size() <= 0){ + throw new NoPicturesLoadedException("No pictures have been loaded"); + } + else { + return pictures.get(pictureID); + } + } //------ End Methods ------// }