From 76bff4c84b65ffb0022cde154558b79ef9d07338 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Mon, 13 Jun 2016 20:18:09 +0200 Subject: [PATCH 01/65] Main: Icons and about button --- .../kauron/jstudy/controller/Controller.java | 17 +++ .../resources/es/kauron/jstudy/img/icon2.png | Bin 0 -> 19558 bytes .../resources/es/kauron/jstudy/view/main.fxml | 113 ++++++++++-------- 3 files changed, 82 insertions(+), 48 deletions(-) create mode 100644 src/main/resources/es/kauron/jstudy/img/icon2.png diff --git a/src/main/java/es/kauron/jstudy/controller/Controller.java b/src/main/java/es/kauron/jstudy/controller/Controller.java index ba8c9a8..d0f31a4 100644 --- a/src/main/java/es/kauron/jstudy/controller/Controller.java +++ b/src/main/java/es/kauron/jstudy/controller/Controller.java @@ -13,13 +13,18 @@ import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; import javafx.scene.Parent; import javafx.scene.control.*; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.stage.FileChooser; +import java.awt.*; import java.io.File; import java.io.IOException; +import java.net.URI; import java.net.URL; import java.util.*; +import java.util.List; public class Controller implements Initializable { @FXML @@ -65,6 +70,7 @@ public class Controller implements Initializable { dialog.getEditor().setPromptText("Table name"); dialog.setTitle("Creating new table"); dialog.setHeaderText("Please input a name for the new table"); + dialog.setGraphic(new ImageView(new Image(Main.class.getResource("img/Edit.png").toString()))); dialog.getDialogPane().setMinWidth(250); dialog.showAndWait(); dialog.setResultConverter(value -> value.getButtonData().equals(ButtonBar.ButtonData.OK_DONE) ? value.getText() : ""); @@ -152,4 +158,15 @@ public class Controller implements Initializable { e.printStackTrace(); } } + + @FXML + protected void onAboutAction(ActionEvent event) { + if (Desktop.isDesktopSupported()) { + try { + Desktop.getDesktop().browse(URI.create("https://kauron.github.io/jstudy")); + } catch (IOException e) { + e.printStackTrace(); + } + } + } } diff --git a/src/main/resources/es/kauron/jstudy/img/icon2.png b/src/main/resources/es/kauron/jstudy/img/icon2.png new file mode 100644 index 0000000000000000000000000000000000000000..115c622ab0497e7900e2b6f60e2c4f657dc76f31 GIT binary patch literal 19558 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/es/kauron/jstudy/view/main.fxml b/src/main/resources/es/kauron/jstudy/view/main.fxml index 30607cd..c862dc4 100644 --- a/src/main/resources/es/kauron/jstudy/view/main.fxml +++ b/src/main/resources/es/kauron/jstudy/view/main.fxml @@ -4,65 +4,82 @@ - - +
- + - + + + + + + + + + + + - + - - - - - - - + - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - +
+ + + + + + + + + + +
-
-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + diff --git a/src/main/resources/es/kauron/jstudy/view/test.fxml b/src/main/resources/es/kauron/jstudy/view/test.fxml index 835252b..e43cdf5 100644 --- a/src/main/resources/es/kauron/jstudy/view/test.fxml +++ b/src/main/resources/es/kauron/jstudy/view/test.fxml @@ -4,72 +4,79 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - + - - - - - + + + + - + - + + + + + + + + + + + + + + + + - + From 1b5f07bb7d1637f8b5b556dc11edb010b63282cf Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Thu, 12 Sep 2019 19:17:39 +0200 Subject: [PATCH 40/65] Auto-update from Gitlab's latest tag --- jstudy.iml | 4 +- pom.xml | 18 +++- .../kauron/jstudy/controller/Controller.java | 85 ++++++++++++++++++- .../java/es/kauron/jstudy/model/AppPrefs.java | 7 ++ src/main/main.iml | 1 + src/main/resources-filtered/version.txt | 1 + version | 1 - 7 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 src/main/resources-filtered/version.txt delete mode 100644 version diff --git a/jstudy.iml b/jstudy.iml index cb9b265..82289b2 100644 --- a/jstudy.iml +++ b/jstudy.iml @@ -5,13 +5,15 @@ - + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 1493ac1..82d9fc4 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ jstudy - http://maven.apache.org + http://gitlab.com/kauron/jstudy junit @@ -27,8 +27,24 @@ jfoenix 8.0.9 + + org.json + json + 20190722 + bundle + + + + src/main/resources + false + + + src/main/resources-filtered + true + + maven-compiler-plugin diff --git a/src/main/java/es/kauron/jstudy/controller/Controller.java b/src/main/java/es/kauron/jstudy/controller/Controller.java index 7487d31..d695568 100644 --- a/src/main/java/es/kauron/jstudy/controller/Controller.java +++ b/src/main/java/es/kauron/jstudy/controller/Controller.java @@ -24,16 +24,25 @@ import javafx.scene.layout.BorderPane; import javafx.stage.FileChooser; import javafx.stage.Window; import javafx.stage.WindowEvent; +import org.json.JSONArray; +import org.json.JSONObject; import java.awt.*; -import java.io.File; -import java.io.IOException; +import java.io.*; +import java.net.HttpURLConnection; import java.net.URI; import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; import java.util.List; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; public class Controller implements Initializable { + private static final String PROJECT_URL = "https://gitlab.com/kauron/jstudy"; + @FXML private TabPane tabPane; @@ -45,6 +54,7 @@ public class Controller implements Initializable { private final BooleanProperty tabIsTable = new SimpleBooleanProperty(false); private final Map tabMap = new HashMap<>(); + private String updateURL, updateFileName; @Override public void initialize(URL url, ResourceBundle resourceBundle) { @@ -65,6 +75,75 @@ public class Controller implements Initializable { } }) ); + new Thread(this::checkUpdate).start(); + } + + private void checkUpdate() { + // Check new version via gitlab's REST API + String newVersion; + File jarFile; + BufferedReader br; + try { + URL apiUrl = new URL("https://gitlab.com/api/v4/projects/9264549/releases"); + HttpURLConnection connection = (HttpURLConnection) apiUrl.openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty("Accept", "application/json"); + if (connection.getResponseCode() != 200) { + System.err.println("Error connecting to Gitlab API"); + } + br = new BufferedReader(new InputStreamReader(connection.getInputStream())); + } catch (IOException e) { + return; + } + String output = br.lines().collect(Collectors.joining()); + JSONArray tags = new JSONArray(output); + JSONObject latest = tags.getJSONObject(0); + newVersion = latest.getString("tag_name").substring(1); + if (!isNewVersion(AppPrefs.getVersion(), newVersion)) + return; + String desc = latest.getString("description"); + Matcher matcher = Pattern.compile("\\[(.*\\.jar)]" + + "\\((/uploads/.*/.*\\.jar)\\)").matcher(desc); + if (!matcher.find()) + return; + updateURL = matcher.group(2); + updateFileName = matcher.group(1); + // Ask user whether to update or not. + Platform.runLater(this::onUpdate); + } + + private void onUpdate() { + Optional res = new Alert(Alert.AlertType.INFORMATION, + "There is an update ready. Would you like to download it and open it?", + ButtonType.YES, ButtonType.NO).showAndWait(); + if (!res.isPresent() || !res.get().equals(ButtonType.YES)) + return; + try (InputStream inputStream = new URL(PROJECT_URL + updateURL).openStream(); + ReadableByteChannel readableByteChannel = Channels.newChannel(inputStream); + FileOutputStream fileOutputStream = new FileOutputStream(updateFileName)) { + fileOutputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE); + } catch (IOException e) { + return; + } + // Launch new version + try { + new ProcessBuilder("java", "-jar", updateFileName).start(); + } catch (IOException e) { + return; + } + onQuit(null); + } + + private boolean isNewVersion(String version, String newVersion) { + String[] o = version.split("\\."); + String[] n = newVersion.split("\\."); + for (int i = 0; i < o.length; i++) { + int a = Integer.parseInt(n[i]); + int b = Integer.parseInt(o[i]); + if (a != b) + return a > b; + } + return false; } @FXML @@ -248,7 +327,7 @@ public class Controller implements Initializable { protected void onAboutAction(ActionEvent event) { if (Desktop.isDesktopSupported()) { try { - Desktop.getDesktop().browse(URI.create("https://gitlab.com/kauron/jstudy")); + Desktop.getDesktop().browse(URI.create(PROJECT_URL)); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/es/kauron/jstudy/model/AppPrefs.java b/src/main/java/es/kauron/jstudy/model/AppPrefs.java index 81f909c..96670eb 100644 --- a/src/main/java/es/kauron/jstudy/model/AppPrefs.java +++ b/src/main/java/es/kauron/jstudy/model/AppPrefs.java @@ -4,6 +4,7 @@ import es.kauron.jstudy.Main; import javafx.beans.property.SimpleBooleanProperty; import java.io.File; +import java.util.Scanner; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; @@ -33,6 +34,12 @@ public class AppPrefs { flushPrefs(); } + public static String getVersion() { + String v = new Scanner(AppPrefs.class.getResourceAsStream("/version.txt")).nextLine(); + assert v.matches("\\d\\.\\d\\.\\d"); + return v; + } + public static class BooleanPref extends SimpleBooleanProperty { private final String name; diff --git a/src/main/main.iml b/src/main/main.iml index a9e9bd0..7533b96 100644 --- a/src/main/main.iml +++ b/src/main/main.iml @@ -9,5 +9,6 @@ + \ No newline at end of file diff --git a/src/main/resources-filtered/version.txt b/src/main/resources-filtered/version.txt new file mode 100644 index 0000000..e78e522 --- /dev/null +++ b/src/main/resources-filtered/version.txt @@ -0,0 +1 @@ +${version} \ No newline at end of file diff --git a/version b/version deleted file mode 100644 index 0bfccb0..0000000 --- a/version +++ /dev/null @@ -1 +0,0 @@ -0.4.5 From 62634a1800c6bbf6ef041cbbc1734bfd3e7a1d48 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Thu, 12 Sep 2019 17:45:34 +0000 Subject: [PATCH 41/65] Add LICENSE --- LICENSE | 661 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 661 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..300bd82 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + jstudy + Copyright (C) 2019 Carlos Galindo + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. From 0d4b50a78cf08bba74e0e474ab036994c72584b4 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Thu, 12 Sep 2019 19:55:45 +0200 Subject: [PATCH 42/65] Removed JFoenix library --- .idea/modules.xml | 2 -- jstudy.iml | 1 - pom.xml | 6 ------ .../es/kauron/jstudy/controller/SettingsController.java | 4 ++-- src/main/resources/es/kauron/jstudy/view/settings.fxml | 8 ++++---- 5 files changed, 6 insertions(+), 15 deletions(-) diff --git a/.idea/modules.xml b/.idea/modules.xml index 4add186..d608dd7 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -3,8 +3,6 @@ - - \ No newline at end of file diff --git a/jstudy.iml b/jstudy.iml index 82289b2..c33e5a0 100644 --- a/jstudy.iml +++ b/jstudy.iml @@ -13,7 +13,6 @@ - \ No newline at end of file diff --git a/pom.xml b/pom.xml index 82d9fc4..676eeab 100644 --- a/pom.xml +++ b/pom.xml @@ -22,16 +22,10 @@ 3.8.1 test - - com.jfoenix - jfoenix - 8.0.9 - org.json json 20190722 - bundle diff --git a/src/main/java/es/kauron/jstudy/controller/SettingsController.java b/src/main/java/es/kauron/jstudy/controller/SettingsController.java index a15150a..8f3baf0 100644 --- a/src/main/java/es/kauron/jstudy/controller/SettingsController.java +++ b/src/main/java/es/kauron/jstudy/controller/SettingsController.java @@ -1,16 +1,16 @@ package es.kauron.jstudy.controller; -import com.jfoenix.controls.JFXCheckBox; import es.kauron.jstudy.model.AppPrefs; import javafx.fxml.FXML; import javafx.fxml.Initializable; +import javafx.scene.control.CheckBox; import java.net.URL; import java.util.ResourceBundle; public class SettingsController implements Initializable { @FXML - private JFXCheckBox repeatMistakes, showFeedback, repeatImmediately; + private CheckBox repeatMistakes, showFeedback, repeatImmediately; @Override public void initialize(URL location, ResourceBundle resources) { diff --git a/src/main/resources/es/kauron/jstudy/view/settings.fxml b/src/main/resources/es/kauron/jstudy/view/settings.fxml index 2940ba2..9fb5496 100644 --- a/src/main/resources/es/kauron/jstudy/view/settings.fxml +++ b/src/main/resources/es/kauron/jstudy/view/settings.fxml @@ -1,14 +1,14 @@ - + - - - + + + From d3d07b754164800076b49332fe4b4f4dbb1141a3 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Thu, 12 Sep 2019 22:07:32 +0200 Subject: [PATCH 43/65] Test: option to lock switching tabs --- .../es/kauron/jstudy/controller/Controller.java | 16 ++++++++++++---- .../jstudy/controller/SettingsController.java | 3 ++- .../java/es/kauron/jstudy/model/AppPrefs.java | 1 + .../es/kauron/jstudy/view/settings.fxml | 1 + 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/java/es/kauron/jstudy/controller/Controller.java b/src/main/java/es/kauron/jstudy/controller/Controller.java index d695568..ea7eac9 100644 --- a/src/main/java/es/kauron/jstudy/controller/Controller.java +++ b/src/main/java/es/kauron/jstudy/controller/Controller.java @@ -7,6 +7,7 @@ import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; +import javafx.collections.ListChangeListener; import javafx.event.ActionEvent; import javafx.event.Event; import javafx.event.EventHandler; @@ -55,14 +56,20 @@ public class Controller implements Initializable { private final BooleanProperty tabIsTable = new SimpleBooleanProperty(false); private final Map tabMap = new HashMap<>(); private String updateURL, updateFileName; + private Tab theTest = null; @Override public void initialize(URL url, ResourceBundle resourceBundle) { tabPane.getSelectionModel().selectedItemProperty().addListener((ob, o, n) -> { - tabIsTable.set(tabMap.get(n) != null); - menuCloseTab.setDisable(!n.isClosable()); - menuSave.setDisable(!tabMap.containsKey(n) || tabMap.get(n).saved.get()); + if (theTest == o && AppPrefs.lockTabsOnTest.get()) { // optionally disallow switching from test + tabPane.getSelectionModel().select(o); + } else { // update if in table tab + tabIsTable.set(tabMap.get(n) != null); + menuCloseTab.setDisable(!n.isClosable()); + menuSave.setDisable(!tabMap.containsKey(n) || tabMap.get(n).saved.get()); + } }); + tabPane.getTabs().removeListener((ListChangeListener) c -> theTest = null); Platform.runLater(() -> root.getScene().getWindow().setOnCloseRequest(event -> { for (Tab tab : tabPane.getTabs()) { @@ -316,7 +323,8 @@ public class Controller implements Initializable { ((TestController) loader.getController()).setList(new ArrayList<>(list)); - tabPane.getTabs().add(new Tab("Test: " + tabPane.getSelectionModel().getSelectedItem().getText(), root)); + theTest = new Tab("Test: " + tabPane.getSelectionModel().getSelectedItem().getText(), root); + tabPane.getTabs().add(theTest); tabPane.getSelectionModel().selectLast(); } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/es/kauron/jstudy/controller/SettingsController.java b/src/main/java/es/kauron/jstudy/controller/SettingsController.java index 8f3baf0..eb719a1 100644 --- a/src/main/java/es/kauron/jstudy/controller/SettingsController.java +++ b/src/main/java/es/kauron/jstudy/controller/SettingsController.java @@ -10,7 +10,7 @@ import java.util.ResourceBundle; public class SettingsController implements Initializable { @FXML - private CheckBox repeatMistakes, showFeedback, repeatImmediately; + private CheckBox repeatMistakes, showFeedback, repeatImmediately, lockTabsOnTest; @Override public void initialize(URL location, ResourceBundle resources) { @@ -18,6 +18,7 @@ public class SettingsController implements Initializable { repeatImmediately.selectedProperty().bindBidirectional(AppPrefs.repeatImmediately); repeatMistakes.selectedProperty().bindBidirectional(AppPrefs.repeatWrong); showFeedback.selectedProperty().bindBidirectional(AppPrefs.showFeedback); + lockTabsOnTest.selectedProperty().bindBidirectional(AppPrefs.lockTabsOnTest); repeatMistakes.selectedProperty().addListener((obj, o, n) -> { if (!n) repeatImmediately.setSelected(false); }); diff --git a/src/main/java/es/kauron/jstudy/model/AppPrefs.java b/src/main/java/es/kauron/jstudy/model/AppPrefs.java index 96670eb..6343b7f 100644 --- a/src/main/java/es/kauron/jstudy/model/AppPrefs.java +++ b/src/main/java/es/kauron/jstudy/model/AppPrefs.java @@ -13,6 +13,7 @@ public class AppPrefs { public static final BooleanPref repeatWrong = new BooleanPref(false, "repeatWrong"); public static final BooleanPref showFeedback = new BooleanPref(true, "showFeedback"); public static final BooleanPref repeatImmediately = new BooleanPref(false, "repeatImmediately"); + public static final BooleanPref lockTabsOnTest = new BooleanPref(false, "lockTabsOnTest"); public static File lastDir; static { diff --git a/src/main/resources/es/kauron/jstudy/view/settings.fxml b/src/main/resources/es/kauron/jstudy/view/settings.fxml index 9fb5496..6397683 100644 --- a/src/main/resources/es/kauron/jstudy/view/settings.fxml +++ b/src/main/resources/es/kauron/jstudy/view/settings.fxml @@ -9,6 +9,7 @@ + From 7d835018e3f48ebbb72ecbd6355f32b8f9c33018 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Thu, 12 Sep 2019 23:34:33 +0200 Subject: [PATCH 44/65] Interface consistency bugs --- .../es/kauron/jstudy/controller/Controller.java | 3 +++ .../kauron/jstudy/controller/TestController.java | 14 +++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/java/es/kauron/jstudy/controller/Controller.java b/src/main/java/es/kauron/jstudy/controller/Controller.java index ea7eac9..0b117a3 100644 --- a/src/main/java/es/kauron/jstudy/controller/Controller.java +++ b/src/main/java/es/kauron/jstudy/controller/Controller.java @@ -66,7 +66,10 @@ public class Controller implements Initializable { } else { // update if in table tab tabIsTable.set(tabMap.get(n) != null); menuCloseTab.setDisable(!n.isClosable()); + menuSave.disableProperty().unbind(); menuSave.setDisable(!tabMap.containsKey(n) || tabMap.get(n).saved.get()); + if (tabMap.containsKey(n)) + menuSave.disableProperty().bind(tabMap.get(n).saved); } }); tabPane.getTabs().removeListener((ListChangeListener) c -> theTest = null); diff --git a/src/main/java/es/kauron/jstudy/controller/TestController.java b/src/main/java/es/kauron/jstudy/controller/TestController.java index 375cf85..d2fc4cc 100644 --- a/src/main/java/es/kauron/jstudy/controller/TestController.java +++ b/src/main/java/es/kauron/jstudy/controller/TestController.java @@ -44,7 +44,6 @@ public class TestController implements Initializable { void setList(List list) { this.list = list; int total = list.size(); - progress.setProgress(0); progressLabel.textProperty().bind(Bindings.format( String.format("%%.2f%%%% %%d / %d %%d mistakes", total), done.multiply(100.0).divide(total), done, errors)); @@ -75,18 +74,23 @@ public class TestController implements Initializable { } // Remove the question from the pool if the question was correctly answered or there is no repetition - if ((right && !correctingError.get()) || !AppPrefs.repeatWrong.get()) { + if (right || !AppPrefs.repeatWrong.get()) { + if (!correctingError.get()) + done.set(done.get() + 1); + correctingError.set(!right && AppPrefs.repeatImmediately.get()); list.remove(item.get()); - done.set(done.get() + 1); if (list.size() == 0) { onEndAction(null); return; } chooseQuestion(); - } else if (!AppPrefs.repeatImmediately.get()) { + } else if (AppPrefs.repeatImmediately.get()) { + correctingError.set(true); + item.set(new TestItem(item.get())); + list.add(item.get()); + } else { chooseQuestion(); } - correctingError.set(!right && AppPrefs.repeatImmediately.get()); answer.setText(""); answer.requestFocus(); } From 93b7dce20012453cb8c0db69d183975805fd0f6e Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 13 Sep 2019 00:01:58 +0200 Subject: [PATCH 45/65] Added timer for test --- .../jstudy/controller/TestController.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/main/java/es/kauron/jstudy/controller/TestController.java b/src/main/java/es/kauron/jstudy/controller/TestController.java index d2fc4cc..4cb5fab 100644 --- a/src/main/java/es/kauron/jstudy/controller/TestController.java +++ b/src/main/java/es/kauron/jstudy/controller/TestController.java @@ -2,6 +2,7 @@ package es.kauron.jstudy.controller; import es.kauron.jstudy.model.AppPrefs; import es.kauron.jstudy.model.TestItem; +import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.property.*; import javafx.event.ActionEvent; @@ -16,6 +17,8 @@ import javafx.scene.layout.HBox; import java.net.URL; import java.util.List; import java.util.ResourceBundle; +import java.util.Timer; +import java.util.TimerTask; public class TestController implements Initializable { @FXML @@ -34,19 +37,30 @@ public class TestController implements Initializable { private final IntegerProperty errors = new SimpleIntegerProperty(0); private final ObjectProperty item = new SimpleObjectProperty<>(); private final IntegerProperty done = new SimpleIntegerProperty(0); + // Time accounting + private final IntegerProperty seconds = new SimpleIntegerProperty(0); + private final IntegerProperty minutes = new SimpleIntegerProperty(0); + private final Timer timer = new Timer(); @Override public void initialize(URL url, ResourceBundle resourceBundle) { skipButton.disableProperty().bind(correctingError); feedback.visibleProperty().bind(AppPrefs.showFeedback); + seconds.addListener((obj, o, n) -> { + if (n.intValue() == 60) { + minutes.set(minutes.get() + 1); + seconds.set(0); + } + }); } void setList(List list) { this.list = list; int total = list.size(); progressLabel.textProperty().bind(Bindings.format( - String.format("%%.2f%%%% %%d / %d %%d mistakes", total), - done.multiply(100.0).divide(total), done, errors)); + String.format("%%.2f%%%% %%d / %d %%d mistakes %%02d:%%02d", total), + done.multiply(100.0).divide(total), done, + errors, minutes, seconds)); progress.progressProperty().bind(done.divide((double) total)); item.addListener((obj, o, n) -> { if (o != null) { @@ -55,6 +69,12 @@ public class TestController implements Initializable { } question.setText(n.getQuestion()); }); + timer.schedule(new TimerTask() { + @Override + public void run() { + Platform.runLater(() -> seconds.set(seconds.get() + 1)); + } + }, 0, 1000); onSkipAction(null); } @@ -116,5 +136,6 @@ public class TestController implements Initializable { answer.setText(""); answer.setDisable(true); question.setText("That's it!"); + timer.cancel(); } } From 7fe80b07ec3b594e64fc56ae34215017c62f7e33 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 13 Sep 2019 00:15:27 +0200 Subject: [PATCH 46/65] Table: new editing and filtering * Split buttons between the context menu and above the table. * Moved adding/editing to above the table. * Added filtering. * Added shortcut to edit (double click) and to delete rows. --- .../jstudy/controller/TableController.java | 124 ++++++++++-------- .../es/kauron/jstudy/view/table.fxml | 9 +- 2 files changed, 76 insertions(+), 57 deletions(-) diff --git a/src/main/java/es/kauron/jstudy/controller/TableController.java b/src/main/java/es/kauron/jstudy/controller/TableController.java index fd4fa12..59bb358 100644 --- a/src/main/java/es/kauron/jstudy/controller/TableController.java +++ b/src/main/java/es/kauron/jstudy/controller/TableController.java @@ -1,50 +1,47 @@ package es.kauron.jstudy.controller; -import es.kauron.jstudy.Main; import es.kauron.jstudy.model.AppPrefs; import es.kauron.jstudy.model.TestItem; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; +import javafx.beans.binding.Bindings; +import javafx.beans.property.*; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; +import javafx.collections.transformation.FilteredList; import javafx.event.ActionEvent; import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; -import javafx.scene.Parent; -import javafx.scene.Scene; -import javafx.scene.control.Button; -import javafx.scene.control.SelectionMode; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableView; +import javafx.scene.control.*; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.input.MouseEvent; import javafx.stage.FileChooser; -import javafx.stage.Modality; -import javafx.stage.Stage; import java.io.File; -import java.io.IOException; import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.ResourceBundle; +import java.util.*; public class TableController implements Initializable { @FXML private TableView table; @FXML + private TextField newQuestionField, newAnswerField, searchField; + @FXML + private Button addButton; + @FXML private TableColumn answerCol, questionCol; + private FilteredList filtered; private ObservableList data; private Controller parent; private File file; StringProperty name; final BooleanProperty saved = new SimpleBooleanProperty(); + private final ObjectProperty editing = new SimpleObjectProperty<>(null); @Override public void initialize(URL url, ResourceBundle resourceBundle) { + addButton.textProperty().bind(Bindings.when(editing.isNull()).then("_Add item").otherwise("_Save item")); // Add context menu to Table MenuItem menuEdit = new MenuItem("_Edit"); menuEdit.setOnAction(this::onEditAction); @@ -61,16 +58,18 @@ public class TableController implements Initializable { table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); answerCol.setCellValueFactory(e -> e.getValue().answerProperty()); questionCol.setCellValueFactory(e -> e.getValue().questionProperty()); - table.getSelectionModel().getSelectedIndices().addListener((ListChangeListener) obs -> { - menuEdit.setDisable(obs.getList().size() != 1); - }); + table.getSelectionModel().getSelectedIndices().addListener( + (ListChangeListener) obs -> menuEdit.setDisable(obs.getList().size() != 1)); + searchField.textProperty().addListener((obj, o, n) -> + filtered.setPredicate((item) -> item.getQuestion().contains(n) || item.getAnswer().contains(n))); } void setData(String name, List list, Controller controller, File file) { this.name = new SimpleStringProperty(name); this.data = FXCollections.observableArrayList(list); + this.filtered = data.filtered((item) -> true); this.parent = controller; - table.setItems(data); + table.setItems(filtered); this.file = file; saved.set(file != null); } @@ -99,41 +98,31 @@ public class TableController implements Initializable { @FXML protected void onAddAction(ActionEvent event) { - try { - FXMLLoader loader = new FXMLLoader(Main.class.getResource("view/edit.fxml")); - Parent pRoot = loader.load(); - - ((EditController) loader.getController()).setList(data, saved); - - Stage stage = new Stage(); - stage.setTitle("New entry"); - stage.setScene(new Scene(pRoot)); - stage.initModality(Modality.APPLICATION_MODAL); - stage.showAndWait(); - } catch (IOException e) { - e.printStackTrace(); + if (editing.get() == null) { + TestItem item = new TestItem(newQuestionField.getText().trim(), newAnswerField.getText().trim()); + data.add(item); + newQuestionField.setText(""); + newAnswerField.setText(""); + saved.set(false); + } else { + editing.get().answerProperty().set(newAnswerField.getText().trim()); + editing.get().questionProperty().set(newQuestionField.getText().trim()); + editing.set(null); + newQuestionField.setText(""); + newAnswerField.setText(""); } + newQuestionField.requestFocus(); } @FXML protected void onEditAction(ActionEvent event) { - ObservableList list = table.getSelectionModel().getSelectedIndices(); + ObservableList list = table.getSelectionModel().getSelectedItems(); if (list.size() != 1) return; - int index = list.get(0); - try { - FXMLLoader loader = new FXMLLoader(Main.class.getResource("view/edit.fxml")); - Parent root = loader.load(); - - ((EditController) loader.getController()).setList(table.getItems(), index, saved); - - Stage stage = new Stage(); - stage.setTitle("Editing entry..."); - stage.setScene(new Scene(root)); - stage.initModality(Modality.APPLICATION_MODAL); - stage.showAndWait(); - } catch (IOException e) { - e.printStackTrace(); - } + editing.set(list.get(0)); + newQuestionField.setText(list.get(0).getQuestion()); + newAnswerField.setText(list.get(0).getAnswer()); + saved.set(false); + newQuestionField.requestFocus(); } @FXML @@ -151,15 +140,14 @@ public class TableController implements Initializable { protected void onDuplicateAction(ActionEvent event) { if (table.getSelectionModel().getSelectedIndices().size() > 0) saved.set(false); for (int i : table.getSelectionModel().getSelectedIndices()) - table.getItems().add(new TestItem(table.getItems().get(i))); + data.add(new TestItem(filtered.get(i))); table.requestFocus(); } @FXML protected void onDeleteAction(ActionEvent event) { if (table.getSelectionModel().getSelectedIndices().size() > 0) saved.set(false); - for (int i : table.getSelectionModel().getSelectedIndices()) - table.getItems().remove(i); + data.removeAll(table.getSelectionModel().getSelectedItems()); table.requestFocus(); } @@ -170,6 +158,32 @@ public class TableController implements Initializable { @FXML protected void onTestAction(ActionEvent event) { - parent.newTest(data); + parent.newTest(filtered); + } + + @FXML + protected void onTableKeyEvent(KeyEvent event) { + if (event.getCode().equals(KeyCode.DELETE)) { + onDeleteAction(null); + } + } + + private final Timer timer = new Timer(); + private TimerTask timerTask = null; + @FXML + protected void onTableMouseClicked(MouseEvent event) { + if (timerTask == null) { + timerTask = new TimerTask() { + @Override + public void run() { + timerTask = null; + } + }; + timer.schedule(timerTask, 200); + } else { + if (timerTask.cancel()) + onEditAction(null); + timerTask = null; + } } } diff --git a/src/main/resources/es/kauron/jstudy/view/table.fxml b/src/main/resources/es/kauron/jstudy/view/table.fxml index bfe94b1..5b3626b 100644 --- a/src/main/resources/es/kauron/jstudy/view/table.fxml +++ b/src/main/resources/es/kauron/jstudy/view/table.fxml @@ -7,11 +7,14 @@ - + - - - - - - - - - + + @@ -38,9 +31,7 @@ - + From 4406bd4aedd97c78833370c7d7b9934c95aefd27 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 13 Sep 2019 10:31:46 +0200 Subject: [PATCH 50/65] Table: added moving via drag and drop --- .../controller/DraggableRowFactory.java | 92 +++++++++++++++++++ .../jstudy/controller/TableController.java | 1 + 2 files changed, 93 insertions(+) create mode 100644 src/main/java/es/kauron/jstudy/controller/DraggableRowFactory.java diff --git a/src/main/java/es/kauron/jstudy/controller/DraggableRowFactory.java b/src/main/java/es/kauron/jstudy/controller/DraggableRowFactory.java new file mode 100644 index 0000000..c53bc70 --- /dev/null +++ b/src/main/java/es/kauron/jstudy/controller/DraggableRowFactory.java @@ -0,0 +1,92 @@ +package es.kauron.jstudy.controller; + +import javafx.collections.ObservableList; +import javafx.scene.control.TableRow; +import javafx.scene.control.TableView; +import javafx.scene.input.ClipboardContent; +import javafx.scene.input.DataFormat; +import javafx.scene.input.Dragboard; +import javafx.scene.input.TransferMode; + +import java.util.ArrayList; +import java.util.List; + +class DraggableRowFactory { + private static final DataFormat SERIALIZED_MIME_TYPE = new DataFormat("application/x-java-serialized-object"); + + private final ObservableList data; + private final List dragging = new ArrayList<>(); + + DraggableRowFactory(ObservableList data) { + this.data = data; + } + + TableRow generator(TableView table) { + TableRow row = new TableRow<>(); + row.setOnDragDetected((event) -> { + if (!row.isEmpty() && table.getItems().size() == data.size()) { + Integer index = row.getIndex(); + dragging.clear(); + dragging.addAll(table.getSelectionModel().getSelectedItems()); + Dragboard db = row.startDragAndDrop(TransferMode.MOVE); + ClipboardContent cc = new ClipboardContent(); + cc.put(SERIALIZED_MIME_TYPE, index); + db.setContent(cc); + event.consume(); + } + }); + row.setOnDragOver((event) -> { + Dragboard db = event.getDragboard(); + if (db.hasContent(SERIALIZED_MIME_TYPE)) { + if (row.getIndex() != (Integer) db.getContent(SERIALIZED_MIME_TYPE)) { + event.acceptTransferModes(TransferMode.COPY_OR_MOVE); + event.consume(); + } + } + }); + row.setOnDragDropped((event) -> { + Dragboard db = event.getDragboard(); + if (!db.hasContent(SERIALIZED_MIME_TYPE)) + return; + int dropIndex; + S item = null; + if (row.isEmpty()) { + dropIndex = table.getItems().size(); + } else { + dropIndex = row.getIndex(); + item = table.getItems().get(dropIndex); + } + int delta = 0; + if (item != null) { + while (dragging.contains(item)) { + delta = 1; + --dropIndex; + if (dropIndex < 0) { + item = null; + dropIndex = 0; + break; + } + item = table.getItems().get(dropIndex); + } + } + data.removeAll(dragging); + if (item != null) + dropIndex = table.getItems().indexOf(item) + delta; + else if (dropIndex != 0) + dropIndex = table.getItems().size(); + + table.getSelectionModel().clearSelection(); + + for (S s : dragging) { + data.add(dropIndex, s); + table.getSelectionModel().select(dropIndex); + dropIndex++; + } + + event.setDropCompleted(true); + dragging.clear(); + event.consume(); + }); + return row; + } +} diff --git a/src/main/java/es/kauron/jstudy/controller/TableController.java b/src/main/java/es/kauron/jstudy/controller/TableController.java index 99786d0..f2c8468 100644 --- a/src/main/java/es/kauron/jstudy/controller/TableController.java +++ b/src/main/java/es/kauron/jstudy/controller/TableController.java @@ -86,6 +86,7 @@ public class TableController implements Initializable { this.data = FXCollections.observableArrayList(list); this.filtered = data.filtered((item) -> true); this.parent = controller; + table.setRowFactory(new DraggableRowFactory<>(data)::generator); table.setItems(filtered); this.file = file; saved.set(file != null); From 6d5c7917a29f92739317f5d4fe0ab8ad113924ba Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 13 Sep 2019 10:51:24 +0200 Subject: [PATCH 51/65] Table: added cancel button for editing --- .../jstudy/controller/TableController.java | 20 +++++------ .../es/kauron/jstudy/view/table.fxml | 34 +++++++++++-------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/main/java/es/kauron/jstudy/controller/TableController.java b/src/main/java/es/kauron/jstudy/controller/TableController.java index f2c8468..693028b 100644 --- a/src/main/java/es/kauron/jstudy/controller/TableController.java +++ b/src/main/java/es/kauron/jstudy/controller/TableController.java @@ -95,7 +95,6 @@ public class TableController implements Initializable { List getData() {return new ArrayList<>(data);} String getName() {return name.get();} - @FXML protected void onSaveAction(ActionEvent event) { while (file == null) { FileChooser chooser = new FileChooser(); @@ -123,20 +122,14 @@ public class TableController implements Initializable { if (editing.get() == null) { TestItem item = new TestItem(newQuestionField.getText().trim(), newAnswerField.getText().trim()); data.add(item); - newQuestionField.setText(""); - newAnswerField.setText(""); saved.set(false); } else { editing.get().answerProperty().set(newAnswerField.getText().trim()); editing.get().questionProperty().set(newQuestionField.getText().trim()); - editing.set(null); - newQuestionField.setText(""); - newAnswerField.setText(""); } - newQuestionField.requestFocus(); + onCancelAction(event); } - @FXML protected void onEditAction(ActionEvent event) { ObservableList list = table.getSelectionModel().getSelectedItems(); if (list.size() != 1) return; @@ -148,6 +141,14 @@ public class TableController implements Initializable { } @FXML + protected void onCancelAction(ActionEvent event) { + if (editing.get() != null) + editing.set(null); + newQuestionField.setText(""); + newAnswerField.setText(""); + newQuestionField.requestFocus(); + } + protected void onSwapAction(ActionEvent event) { if (table.getSelectionModel().getSelectedIndices().size() > 0) saved.set(false); for (TestItem item : table.getSelectionModel().getSelectedItems()) { @@ -158,7 +159,6 @@ public class TableController implements Initializable { table.requestFocus(); } - @FXML protected void onDuplicateAction(ActionEvent event) { if (table.getSelectionModel().getSelectedIndices().size() > 0) saved.set(false); for (int i : table.getSelectionModel().getSelectedIndices()) { @@ -169,14 +169,12 @@ public class TableController implements Initializable { table.requestFocus(); } - @FXML protected void onDeleteAction(ActionEvent event) { if (table.getSelectionModel().getSelectedIndices().size() > 0) saved.set(false); data.removeAll(table.getSelectionModel().getSelectedItems()); table.requestFocus(); } - @FXML protected void onTestSelectionAction(ActionEvent event) { parent.newTest(table.getSelectionModel().getSelectedItems()); } diff --git a/src/main/resources/es/kauron/jstudy/view/table.fxml b/src/main/resources/es/kauron/jstudy/view/table.fxml index 66d9e92..93baded 100644 --- a/src/main/resources/es/kauron/jstudy/view/table.fxml +++ b/src/main/resources/es/kauron/jstudy/view/table.fxml @@ -2,6 +2,8 @@ + + @@ -14,22 +16,26 @@ + - + - - - - - - - - - + + + From a50965fdb6f2948f8c045ed7da42512202d893ed Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 13 Sep 2019 11:29:59 +0200 Subject: [PATCH 52/65] Force program to end --- src/main/java/es/kauron/jstudy/Main.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/es/kauron/jstudy/Main.java b/src/main/java/es/kauron/jstudy/Main.java index ced64cf..b7570e0 100644 --- a/src/main/java/es/kauron/jstudy/Main.java +++ b/src/main/java/es/kauron/jstudy/Main.java @@ -20,6 +20,11 @@ public class Main extends Application { primaryStage.setOnHiding(event -> AppPrefs.save()); } + @Override + public void stop() throws Exception { + super.stop(); + System.exit(0); + } public static void main(String[] args) { launch(args); From 43ef5e7826104a90113baca4451604727963998a Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 13 Sep 2019 11:45:20 +0200 Subject: [PATCH 53/65] Table: Minor design changes --- .../resources/es/kauron/jstudy/view/table.fxml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/resources/es/kauron/jstudy/view/table.fxml b/src/main/resources/es/kauron/jstudy/view/table.fxml index 93baded..d6b40ca 100644 --- a/src/main/resources/es/kauron/jstudy/view/table.fxml +++ b/src/main/resources/es/kauron/jstudy/view/table.fxml @@ -11,12 +11,7 @@ - - + + - -